使用 Gradle 和 Github Actions 將 Java 項目發佈到 Sonatype Maven 中央存儲庫

在本文中,我想仔細看看使用 Gradle 構建器通過 Github Actions 從頭開始將 Java 工件發佈到 Sonatype Maven Central Repository 的過程。

由於一處缺少正常的教程,我決定寫這篇文章。 所有的信息都必須從各種來源一點一點地收集,而且不是完全新鮮的。 誰在乎,歡迎在貓下。

在 Sonatype 中創建存儲庫

第一步是在 Sonatype Maven Central 中創建一個存儲庫。 為此我們去 這裡,註冊並創建一個新任務,要求我們創建一個存儲庫。 我們開車在我們的 組ID 項目, 項目網址 項目鏈接和 單片機網址 指向項目所在的版本控制系統的鏈接。 組ID 這裡應該是 com.example, com.example.domain, com.example.testsupport 的形式,也可以是你的 github 鏈接的形式: github.com/你的用戶名 -> io.github.你的用戶名。 在任何情況下,您都需要驗證此域或配置文件的所有權。 如果您指定了一個 github 配置文件,您將被要求創建一個具有所需名稱的公共存儲庫。

確認後的某個時間,您的 GroupId 將被創建,我們可以繼續下一步,Gradle 配置。

配置搖籃

在撰寫本文時,我沒有找到可以幫助發布工件的 Gradle 插件。 我發現的唯一插件,但是作者拒絕進一步支持它。 因此,我決定自己做所有事情,因為這樣做並不難。

首先要搞清楚的是Sonatype對發布的要求。 它們是:

  • 源代碼和 JavaDoc 的可用性,即。 必須參加 -sources.jar и-javadoc.jar 文件。 如文檔中所述,如果無法提供源代碼或文檔,您可以製作一個虛擬 -sources.jar-javadoc.jar 裡面有一個簡單的自述文件來通過測試。
  • 所有文件必須簽名 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 的要求之一是所有文件都使用 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 Actions 將 Java 項目發佈到 Sonatype Maven 中央存儲庫

我們設置以下變量:

  • 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 Actions 將 Java 項目發佈到 Sonatype Maven 中央存儲庫

發布新版本時自動部署

讓我們為自動部署創建一個單獨的工作流文件 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 開頭的標籤的事件。

在部署之前,我們需要從 secrets 中提取 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 將 Java 項目發佈到 Sonatype Maven 中央存儲庫

標籤名稱必須以 v 開頭。 如果在點擊 Publish release 之後,工作流成功完成,我們可以去 Sonatype Nexus 確保;確定:

使用 Gradle 和 Github Actions 將 Java 項目發佈到 Sonatype Maven 中央存儲庫

該工件出現在登台存儲庫中。 它立即出現在 Open 狀態,然後必須通過按相應的按鈕手動將其轉換為 Close 狀態。 檢查是否滿足所有要求後,工件進入關閉狀態,不再可供修改。 以這種形式,它將最終出現在 MavenCentral 中。 如果一切順利,您可以按下按鈕 發行, 工件將最終出現在 Sonatype 存儲庫中。

為了讓工件進入 MavenCentral,您需要在我們一開始創建的任務中請求它。 你只需要這樣做一次,所以我們第一次發布。 在以後的時間裡,這不是必需的,一切都會自動同步。 他們很快就為我打開了同步功能,但是花了大約 5 天的時間才在 MavenCentral 中提供該工件。

就是這樣,我們已經在 MavenCentral 中發布了我們的工件。

有用的鏈接

  • 相似的 文章, 僅通過 maven 發布
  • 室内裝飾設計 存儲庫 聲納型
  • 吉拉 在其中創建任務的 Sonatype
  • 例子 全部設置的存儲庫

來源: www.habr.com