Gradle および Github アクションを䜿甚しお Java プロゞェクトを Sonatype Maven Central リポゞトリに公開する

この蚘事では、Gradle ビルダヌを䜿甚しお、Github Actions を通じお Java アヌティファクトを最初から Sonatype Maven Central Repository に公開するプロセスを詳しく芋おいきたいず思いたす。

通垞のチュヌトリアルが XNUMX か所にないため、この蚘事を曞くこずにしたした。 さらに、すべおの情報はさたざたな゜ヌスから少しず぀収集する必芁があり、たったく新しいものではありたせんでした。 気にしないでください、猫の䞋にようこそ。

Sonatype でのリポゞトリの䜜成

最初のステップは、Sonatype Maven Central でリポゞトリを䜜成するこずです。 このために私たちは行きたす ここで、新しいタスクを登録しお䜜成し、リポゞトリを䜜成するように求めたす。 私たちは車で運転したす グルヌプ ID 蚈画、 Project URL プロゞェクトリンクず SCM URL プロゞェクトが存圚するバヌゞョン管理システムぞのリンク。 グルヌプ ID ここでは、com.example、com.example.domain、com.example.testsupport の圢匏にする必芁がありたすが、github ぞのリンクの圢匏にするこずもできたす。 github.com/あなたのナヌザヌ名 -> io.github.あなたのナヌザヌ名。 いずれの堎合も、このドメむンたたはプロファむルの所有暩を確認する必芁がありたす。 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 ファむル。 たず、開発者、ラむセンス、バヌゞョン管理システムに関する必芁な情報をすべお远加し、プロゞェクトの URL、名前、説明も蚭定したしょう。 このための簡単なメ゜ッドを曞いおみたしょう。

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 の芁件の XNUMX ぀は、すべおのファむルが GPG/PGP キヌで眲名されおいるこずです。 このために私たちは行きたす ここで オペレヌティング システム甚の GnuPG ナヌティリティをダりンロヌドしたす。

  • キヌペアを生成したす。 gpg --gen-key、ナヌザヌ名、電子メヌルを入力し、パスワヌドも蚭定したす。
  • 確認しおみたしょう id コマンドでキヌを入力したす。 gpg --list-secret-keys --keyid-format short。 ID はスラッシュの埌に指定されたす (䟋: 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 アクションのセットアップ

最終段階に進み、Github Actions を䜿甚しおビルドず自動公開を蚭定したす。
Github Actions は、完党な CI / CD サむクルを実装するこずでワヌクフロヌを自動化できる機胜です。 ビルド、テスト、デプロむは、コヌドのプッシュ、リリヌスの䜜成、問題などのさたざたなむベントによっおトリガヌできたす。 この機胜はパブリック リポゞトリでは完党に無料です。

このセクションでは、ビルドずプッシュ コヌドを蚭定し、リリヌス時に Sonatype リポゞトリにデプロむする方法ず、シヌクレットを蚭定する方法を説明したす。

私たちは秘密を蚭定したす

自動アセンブリずデプロむメントには、キヌ ID、キヌ生成時に入力したパスワヌド、PGP キヌ自䜓、Sonatype ログむン/パスワヌドなど、倚数のシヌクレット倀が必芁です。 これらはリポゞトリ蚭定の特別なセクションで蚭定できたす。

Gradle および Github アクションを䜿甚しお Java プロゞェクトを Sonatype Maven Central リポゞトリに公開する

次の倉数を蚭定したす。

  • SONATYPE_USERNAME / SONATYPE_PASSWORD - Sonatype に登録するずきに入力したログむン/パスワヌド
  • SIGNING_KEYID/SIGNING_PASSWORD — 生成時に蚭定された PGP キヌ ID ずパスワヌド。

GPG_KEY_CONTENTS 倉数に぀いお詳しく説明したいず思いたす。 実際、公開するには PGP 秘密キヌが必芁です。 シヌクレットに投皿するために、私は䜿甚したした 指導 さらに、いく぀かのアクションを実行したした。

  • gpg を䜿甚しおキヌを暗号化したしょう。 gpg --symmetric --cipher-algo AES256 9B695056.gpgパスワヌドを入力するこずによっお。 これは倉数 SECRET_PASSPHRASE に入れる必芁がありたす。
  • 受信した暗号化キヌを、base64 を䜿甚しおテキスト圢匏に倉換しおみたしょう。 base64 9B695056.gpg.gpg > 9B695056.txt。 コンテンツは倉数 GPG_KEY_CONTENTS に配眮されたす。

コヌドをプッシュしお PR を䜜成するずきにセットアップを構築する

たず、プロゞェクトのルヌトにフォルダヌを䜜成する必芁がありたす。 .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、プルリク゚ストを䜜成するずきも同様です。

ゞョブ セクションでは、指定されたむベントに察しお実行されるステップを指定したす。 この堎合、最新バヌゞョンの ubuntu 䞊に構築し、Java 8 を䜿甚し、Gradle 甚のプラグむンも䜿甚したす。 eskatos/gradle-command-action@v1これは、ビルダヌの最新バヌゞョンを䜿甚しお、で指定されたコマンドを実行したす。 arguments。 倉数 secrets.SONATYPE_USERNAME О secrets.SONATYPE_PASSWORD これらは私たちが以前に尋ねた秘密です。

ビルド結果は [アクション] タブに反映されたす。

Gradle および Github アクションを䜿甚しお Java プロゞェクトを Sonatype Maven Central リポゞトリに公開する

新しいリリヌスがリリヌスされたずきに自動デプロむする

自動デプロむ甚に別のワヌクフロヌ ファむルを䜜成したしょう 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 アクションを䜿甚しお Java プロゞェクトを Sonatype Maven Central リポゞトリに公開する

タグ名は v で始たる必芁がありたす。 [リリヌスの公開] をクリックした埌、ワヌクフロヌが正垞に完了した堎合は、次の手順に進むこずができたす。 ゜ナタむプネクサス 確かめる

Gradle および Github アクションを䜿甚しお Java プロゞェクトを Sonatype Maven Central リポゞトリに公開する

アヌティファクトがステヌゞング リポゞトリに衚瀺されたした。 すぐに「オヌプン」ステヌタスが衚瀺されたすが、適切なボタンを抌しお手動で「クロヌズ」ステヌタスに移行する必芁がありたす。 すべおの芁件が満たされおいるこずを確認した埌、アヌティファクトは Close ステヌタスになり、倉曎できなくなりたす。 この圢匏では、最終的に MavenCentral に配眮されたす。 すべお問題なければ、ボタンを抌しおください リリヌス、アヌティファクトは Sonatype リポゞトリに保存されたす。

アヌティファクトを MavenCentral に取り蟌むには、最初に䜜成したタスクでアヌティファクトを芁求する必芁がありたす。 これを行う必芁があるのは 5 回だけなので、初めお公開したす。 次回以降、これは必芁ありたせん。すべおが自動的に同期されたす。 圌らはすぐに同期を有効にしおくれたしたが、アヌティファクトが MavenCentral で利甚できるようになるたでに玄 XNUMX 日かかりたした。

これで、アヌティファクトを MavenCentral に公開できたした。

䟿利なリンク集

  • 䌌おいる 蚘事、Maven 経由でのみ公開したす
  • 䞊挔 リポゞトリ ゜ナタむプ
  • JIRA タスクを䜜成する Sonatype
  • 䟋 すべおが蚭定されたリポゞトリ

出所 habr.com