استفاده از Gradle و Github Actions برای انتشار پروژه جاوا در Sonatype Maven Central Repository

در این مقاله، من می‌خواهم به روند انتشار یک مصنوع جاوا از ابتدا از طریق Github Actions به مخزن مرکزی Sonatype Maven با استفاده از سازنده Gradle نگاهی دقیق‌تر بیندازم.

به دلیل نبود آموزش معمولی در یک جا تصمیم به نوشتن این مقاله گرفتم. تمام اطلاعات باید تکه تکه از منابع مختلف جمع آوری می شد، علاوه بر این، نه کاملا تازه. چه کسی اهمیت می دهد، به زیر گربه خوش آمدید.

ایجاد یک مخزن در Sonatype

اولین قدم ایجاد یک مخزن در Sonatype Maven Central است. برای این ما می رویم اینجا، ثبت نام کنید و یک کار جدید ایجاد کنید و از ما بخواهید که یک مخزن ایجاد کنیم. ما در خود رانندگی می کنیم شناسه گروه پروژه، URL پروژه لینک پروژه و آدرس اینترنتی SCM پیوندی به سیستم کنترل نسخه که پروژه در آن قرار دارد. شناسه گروه اینجا باید به شکل com.example، com.example.domain، com.example.testsupport باشد، و همچنین می تواند به صورت پیوند به github شما باشد: github.com/نام کاربری شما -> io.github.yourusername. در هر صورت، باید مالکیت این دامنه یا نمایه را تأیید کنید. اگر پروفایل github را مشخص کرده اید، از شما خواسته می شود که یک مخزن عمومی با نام دلخواه ایجاد کنید.

مدتی پس از تایید، GroupId شما ایجاد می شود و می توانیم به مرحله بعدی یعنی پیکربندی Gradle برویم.

پیکربندی Gradle

در زمان نوشتن، من پلاگین Gradle را پیدا نکردم که بتواند به انتشار مصنوع کمک کند. آن تنها افزونه ای که پیدا کردم، با این حال، نویسنده از پشتیبانی بیشتر از آن خودداری کرد. بنابراین، تصمیم گرفتم همه چیز را خودم انجام دهم، زیرا انجام این کار خیلی سخت نیست.

اولین چیزی که باید بدانیم الزامات Sonatype برای انتشار است. آنها به شرح زیر هستند:

  • در دسترس بودن کدهای منبع و JavaDoc، به عنوان مثال. باید حضور داشته باشد -sources.jar и-javadoc.jar فایل ها. همانطور که در مستندات ذکر شده است، در صورت عدم امکان ارائه کد منبع یا مستندات، می توانید یک ساختگی ایجاد کنید. -sources.jar یا -javadoc.jar با یک README ساده در داخل برای قبولی در آزمون.
  • همه فایل ها باید با آن امضا شوند GPG/PGPو .asc فایل حاوی امضا باید برای هر فایل گنجانده شود.
  • دسترسی pom فایل
  • مقادیر صحیح groupId, artifactId и version. نسخه می تواند یک رشته دلخواه باشد و نمی تواند به آن ختم شود -SNAPSHOT
  • حضور الزامی است name, description и url
  • وجود اطلاعات در مورد مجوز، توسعه دهندگان و سیستم کنترل نسخه

اینها قوانین اساسی هستند که باید هنگام انتشار رعایت شوند. اطلاعات کامل موجود است اینجا.

ما این الزامات را در build.gradle فایل. ابتدا بیایید تمام اطلاعات لازم در مورد توسعه دهندگان، مجوزها، سیستم کنترل نسخه را اضافه کنیم و همچنین آدرس، نام و توضیحات پروژه را تنظیم کنیم. بیایید یک روش ساده برای این کار بنویسیم:

def customizePom(pom) {
    pom.withXml {
        def root = asNode()

        root.dependencies.removeAll { dep ->
            dep.scope == "test"
        }

        root.children().last() + {
            resolveStrategy = DELEGATE_FIRST

            description 'Some description of artifact'
            name 'Artifct name'
            url 'https://github.com/login/projectname'
            organization {
                name 'com.github.login'
                url 'https://github.com/login'
            }
            issueManagement {
                system 'GitHub'
                url 'https://github.com/login/projectname/issues'
            }
            licenses {
                license {
                    name 'The Apache License, Version 2.0'
                    url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                }
            }
            scm {
                url 'https://github.com/login/projectname'
                connection 'scm:https://github.com/login/projectname.git'
                developerConnection 'scm:git://github.com/login/projectname.git'
            }
            developers {
                developer {
                    id 'dev'
                    name 'DevName'
                    email '[email protected]'
                }
            }
        }
    }
}

در مرحله بعد، شما باید آن را در طول مونتاژ تولید شده مشخص کنید -sources.jar и-javadoc.jar فایل ها. برای این بخش java شما باید موارد زیر را اضافه کنید:

java {
    withJavadocJar()
    withSourcesJar()
}

بیایید به آخرین مورد نیاز برویم، تنظیم امضای GPG/PGP. برای این کار افزونه را وصل کنید signing:

plugins {
    id 'signing'
}

و یک بخش اضافه کنید:

signing {
    sign publishing.publications
}

در آخر بیایید یک بخش اضافه کنیم publishing:

publishing {
    publications {
        mavenJava(MavenPublication) {
            customizePom(pom)
            groupId group
            artifactId archivesBaseName
            version version

            from components.java
        }
    }
    repositories {
        maven {
            url "https://oss.sonatype.org/service/local/staging/deploy/maven2"
            credentials {
                username sonatypeUsername
                password sonatypePassword
            }
        }
    }
}

اینجا نام کاربری sonatype и رمز عبور sonatype متغیرهای حاوی لاگین و رمز عبور ایجاد شده در هنگام ثبت نام در sonatype.org.

بنابراین فینال build.gradle به این صورت خواهد بود:

کد کامل build.gradle

plugins {
    id 'java'
    id 'maven-publish'
    id 'signing'
}

java {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
    withJavadocJar()
    withSourcesJar()
}

group 'io.github.githublogin'
archivesBaseName = 'projectname'
version = System.getenv('RELEASE_VERSION') ?: "0.0.1"

repositories {
    mavenCentral()
}

dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.5.2'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.5.2'
}

test {
    useJUnitPlatform()
}

jar {
    from sourceSets.main.output
    from sourceSets.main.allJava
}

signing {
    sign publishing.publications
}

publishing {
    publications {
        mavenJava(MavenPublication) {
            customizePom(pom)
            groupId group
            artifactId archivesBaseName
            version version

            from components.java
        }
    }
    repositories {
        maven {
            url "https://oss.sonatype.org/service/local/staging/deploy/maven2"
            credentials {
                username sonatypeUsername
                password sonatypePassword
            }
        }
    }
}

def customizePom(pom) {
    pom.withXml {
        def root = asNode()

        root.dependencies.removeAll { dep ->
            dep.scope == "test"
        }

        root.children().last() + {
            resolveStrategy = DELEGATE_FIRST

            description 'Some description of artifact'
            name 'Artifct name'
            url 'https://github.com/login/projectname'
            organization {
                name 'com.github.login'
                url 'https://github.com/githublogin'
            }
            issueManagement {
                system 'GitHub'
                url 'https://github.com/githublogin/projectname/issues'
            }
            licenses {
                license {
                    name 'The Apache License, Version 2.0'
                    url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                }
            }
            scm {
                url 'https://github.com/githublogin/projectname'
                connection 'scm:https://github.com/githublogin/projectname.git'
                developerConnection 'scm:git://github.com/githublogin/projectname.git'
            }
            developers {
                developer {
                    id 'dev'
                    name 'DevName'
                    email '[email protected]'
                }
            }
        }
    }
}

می خواهم توجه داشته باشم که نسخه را از متغیر محیطی دریافت می کنیم: System.getenv('RELEASE_VERSION'). ما آن را در هنگام اسمبلی آشکار می کنیم و آن را از نام تگ می گیریم.

تولید کلید PGP

یکی از الزامات Sonatype این است که همه فایل ها با کلید GPG/PGP امضا شوند. برای این ما می رویم اینجا و ابزار GnuPG را برای سیستم عامل خود دانلود کنید.

  • ما یک جفت کلید تولید می کنیم: gpg --gen-key، یک نام کاربری، ایمیل و همچنین یک رمز عبور وارد کنید.
  • ما فهمیدیم id کلید ما با دستور: gpg --list-secret-keys --keyid-format short. شناسه بعد از اسلش مشخص می شود، به عنوان مثال: rsa2048/9B695056
  • انتشار کلید عمومی سرور https://keys.openpgp.org دستور: gpg --keyserver [https://keys.openpgp.org](https://keys.openpgp.org/) --send-keys 9B695056
  • ما کلید مخفی را به یک مکان دلخواه صادر می کنیم، در آینده به آن نیاز خواهیم داشت: gpg --export-secret-key 9B695056 > D:\gpg\9B695056.gpg

راه اندازی Github Actions

بیایید به مرحله نهایی برویم، ساخت و انتشار خودکار را با استفاده از Github Actions تنظیم کنیم.
Github Actions یک ویژگی است که به شما امکان می دهد با پیاده سازی یک چرخه کامل CI / CD، گردش کار را خودکار کنید. ساخت، آزمایش و استقرار می‌تواند توسط رویدادهای مختلف فعال شود: فشار کد، ایجاد انتشار یا مشکلات. این قابلیت برای مخازن عمومی کاملا رایگان است.

در این بخش، نحوه راه‌اندازی build و push کد و استقرار در مخزن Sonatype در زمان انتشار و همچنین راه‌اندازی Secrets را به شما نشان خواهم داد.

ما اسرار را تعیین می کنیم

برای مونتاژ و استقرار خودکار، به تعدادی مقادیر مخفی مانند شناسه کلید، رمز عبوری که هنگام تولید کلید وارد کردیم، خود کلید PGP و ورود/گذرواژه Sonatype نیاز داریم. می توانید آنها را در یک بخش ویژه در تنظیمات مخزن تنظیم کنید:

استفاده از Gradle و Github Actions برای انتشار پروژه جاوا در Sonatype Maven Central Repository

متغیرهای زیر را تنظیم می کنیم:

  • SONATYPE_USERNAME / SONATYPE_PASSWORD - ورود به سیستم / رمز عبوری که هنگام ثبت نام در Sonatype وارد کردیم
  • SIGNING_KEYID/SIGNING_PASSWORD - شناسه کلید PGP و رمز عبور در طول تولید تنظیم شد.

من می خواهم در مورد متغیر GPG_KEY_CONTENTS با جزئیات بیشتر صحبت کنم. واقعیت این است که برای انتشار به یک کلید PGP خصوصی نیاز داریم. به منظور ارسال آن در اسرار، استفاده کردم دستورالعمل و علاوه بر این تعدادی اقدامات انجام داد.

  • بیایید کلید خود را با gpg رمزگذاری کنیم: gpg --symmetric --cipher-algo AES256 9B695056.gpgبا وارد کردن رمز عبور باید در یک متغیر قرار گیرد: SECRET_PASSPHRASE
  • بیایید کلید رمزگذاری شده دریافتی را با استفاده از base64 به یک فرم متنی ترجمه کنیم: base64 9B695056.gpg.gpg > 9B695056.txt. محتوا در متغیر قرار می گیرد: GPG_KEY_CONTENTS.

هنگام فشار دادن کد و ایجاد روابط عمومی، تنظیمات ایجاد کنید

ابتدا باید یک پوشه در ریشه پروژه خود ایجاد کنید: .github/workflows.

در آن، فایل را علامت گذاری کنید، به عنوان مثال، gradle-ci-build.yml با محتوای زیر:

name: build

on:
  push:
    branches:
      - master
      - dev
      - testing
  pull_request:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - name: Set up JDK 8
        uses: actions/setup-java@v1
        with:
          java-version: 8

      - name: Build with Gradle
        uses: eskatos/gradle-command-action@v1
        with:
          gradle-version: current
          arguments: build -PsonatypeUsername=${{secrets.SONATYPE_USERNAME}} -PsonatypePassword=${{secrets.SONATYPE_PASSWORD}}

این گردش کار هنگام فشار دادن به شاخه ها اجرا می شود master, dev и testing، همچنین هنگام ایجاد درخواست های کششی.

در قسمت jobs مراحلی که باید در رویدادهای مشخص شده اجرا شوند را مشخص می کند. در این صورت، ما از آخرین نسخه اوبونتو استفاده می کنیم، از جاوا 8 استفاده می کنیم و همچنین از پلاگین برای Gradle استفاده می کنیم. eskatos/gradle-command-action@v1که با استفاده از آخرین نسخه سازنده، دستورات مشخص شده در آن را اجرا می کند arguments. متغیرها secrets.SONATYPE_USERNAME и secrets.SONATYPE_PASSWORD اینها رازهایی است که قبلاً پرسیدیم.

نتایج ساخت در تب Actions منعکس خواهد شد:

استفاده از Gradle و Github Actions برای انتشار پروژه جاوا در Sonatype Maven Central Repository

هنگامی که نسخه جدید منتشر می شود، به طور خودکار مستقر می شود

بیایید یک فایل گردش کار جداگانه برای autodeploy ایجاد کنیم gradle-ci-publish.yml:

name: publish

on:
  push:
    tags:
      - 'v*'

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - name: Set up JDK 8
        uses: actions/setup-java@v1
        with:
          java-version: 8

      - name: Prepare to publish
        run: |
          echo '${{secrets.GPG_KEY_CONTENTS}}' | base64 -d > publish_key.gpg
          gpg --quiet --batch --yes --decrypt --passphrase="${{secrets.SECRET_PASSPHRASE}}" 
          --output secret.gpg publish_key.gpg
          echo "::set-env name=RELEASE_VERSION::${GITHUB_REF:11}"

      - name: Publish with Gradle
        uses: eskatos/gradle-command-action@v1
        with:
          gradle-version: current
          arguments: test publish -Psigning.secretKeyRingFile=secret.gpg -Psigning.keyId=${{secrets.SIGNING_KEYID}} -Psigning.password=${{secrets.SIGNING_PASSWORD}} -PsonatypeUsername=${{secrets.SONATYPE_USERNAME}} -PsonatypePassword=${{secrets.SONATYPE_PASSWORD}}

فایل تقریباً مشابه فایل قبلی است، به جز رویدادی که در آن راه اندازی می شود. در این مورد، این رویداد ایجاد یک برچسب با نامی است که با v شروع می شود.

قبل از استقرار، ما باید کلید PGP را از رازها استخراج کرده و در ریشه پروژه قرار دهیم و همچنین آن را رمزگشایی کنیم. در مرحله بعد، باید یک متغیر محیطی ویژه تنظیم کنیم RELEASE_VERSION که به آن اشاره می کنیم gradle.build فایل. همه اینها در بخش انجام می شود Prepare to publish. ما کلید خود را از متغیر GPG_KEY_CONTENTS دریافت می کنیم، آن را به یک فایل gpg ترجمه می کنیم، سپس با قرار دادن آن در فایل رمزگشایی می کنیم. secret.gpg.

در مرحله بعد، به یک متغیر خاص می رویم GITHUB_REF، که می توانیم نسخه ای را که هنگام ایجاد تگ تنظیم کرده ایم، دریافت کنیم. این متغیر در این مورد مرتبط است. refs/tags/v0.0.2 که 11 کاراکتر اول را از آن جدا کردیم تا نسخه خاصی را دریافت کنیم. سپس از دستورات استاندارد Gradle برای انتشار استفاده می کنیم: test publish

بررسی نتایج استقرار در مخزن Sonatype

پس از ایجاد نسخه، گردش کار توضیح داده شده در بخش قبل باید شروع شود. برای انجام این کار، یک نسخه ایجاد کنید:

استفاده از Gradle و Github Actions برای انتشار پروژه جاوا در Sonatype Maven Central Repository

نام تگ باید با v شروع شود. اگر پس از کلیک بر روی انتشار انتشار، گردش کار با موفقیت کامل شد، می‌توانیم به نکسوس سوناتایپ برای اطمینان از:

استفاده از Gradle و Github Actions برای انتشار پروژه جاوا در Sonatype Maven Central Repository

مصنوع در مخزن Staging ظاهر شد. بلافاصله در وضعیت Open ظاهر می شود، سپس باید به صورت دستی با فشار دادن دکمه مناسب به وضعیت Close منتقل شود. پس از بررسی اینکه آیا تمام الزامات برآورده شده است، مصنوع به وضعیت Close می رود و دیگر برای اصلاح در دسترس نیست. در این شکل، در MavenCentral به پایان می رسد. اگر همه چیز خوب است، می توانید دکمه را فشار دهید آزاد، و مصنوع در مخزن Sonatype قرار می گیرد.

برای اینکه مصنوع وارد MavenCentral شود، باید آن را در کاری که در همان ابتدا ایجاد کردیم، درخواست کنید. شما فقط باید یک بار این کار را انجام دهید، بنابراین ما برای اولین بار منتشر می کنیم. در زمان های بعدی، این مورد نیاز نیست، همه چیز به طور خودکار همگام می شود. آنها به سرعت همگام سازی را برای من روشن کردند، اما حدود 5 روز طول کشید تا مصنوع در MavenCentral در دسترس قرار گیرد.

این همه است، ما مصنوع خود را در MavenCentral منتشر کرده ایم.

لینک های مفید

  • مشابه مقاله، فقط از طریق maven منتشر شود
  • چوب بست مخزن سوناتایپ
  • سرو Sonatype که در آن وظیفه ایجاد می شود
  • مثال مخزن که در آن همه راه اندازی شده است

منبع: www.habr.com