Operation

如何配置 github action 自动构建发布到 maven central

1. parent pom.xml 配置,如

<profile>
    <id>release</id>
    <build>
        <plugins>
            <!-- Source -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-source-plugin</artifactId>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>jar-no-fork</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <!-- Javadoc -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-javadoc-plugin</artifactId>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                        <configuration>
                            <additionalOptions>-Xdoclint:none</additionalOptions> <!-- 3.0.0+ -->
                            <!-- <additionalparam>-Xdoclint:none</additionalparam> -->
                            <!-- 2.0.0 -->
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <!-- Usage: mvn versions:set -DnewVersion=latest -->
            <!-- See: http://www.mojohaus.org/versions-maven-plugin/set-mojo.html -->
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>versions-maven-plugin</artifactId>
                <configuration>
                    <!-- <newVersion>latest</newVersion> -->
                    <allowSnapshots>true</allowSnapshots>
                    <generateBackupPoms>false</generateBackupPoms>
                    <processAllModules>true</processAllModules>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-release-plugin</artifactId>
                <configuration>
                    <autoVersionSubmodules>true</autoVersionSubmodules>
                    <!-- <preparationGoals>clean install</preparationGoals> -->
                    <!-- <developmentVersion>latest</developmentVersion> -->
                </configuration>
            </plugin>
            <!-- GPG -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-gpg-plugin</artifactId>
                <executions>
                    <execution>
                        <phase>verify</phase>
                        <goals>
                            <goal>sign</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <!-- https://help.sonatype.com/repomanager2/staging-releases/configuring-your-project-for-deployment -->
            <plugin>
                <groupId>org.sonatype.plugins</groupId>
                <artifactId>nexus-staging-maven-plugin</artifactId>
                <extensions>true</extensions>
                <configuration>
                    <serverId>sonatype-nexus-staging</serverId>
                    <nexusUrl>https://oss.sonatype.org/</nexusUrl>
                    <autoReleaseAfterClose>true</autoReleaseAfterClose>
                    <stagingProgressTimeoutMinutes>15</stagingProgressTimeoutMinutes>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <distributionManagement>
        <snapshotRepository>
            <id>sonatype-nexus-snapshots</id>
            <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
        </snapshotRepository>
        <!-- see:https://blogs.wl4g.com/archives/56 -->
        <!-- Using github workflow auto publishing to Maven central. -->
        <!-- see:https://docs.github.com/en/actions/publishing-packages/publishing-java-packages-with-maven#publishing-packages-to-the-maven-central-repository -->
        <repository>
            <id>sonatype-nexus-staging</id>
            <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
        </repository>
    </distributionManagement>
</profile>
  • 红色为核心部分

2. 准备 GPG key

# 生成密钥对
gpg2 --gen-key

# 查看密钥列表
gpg2 --list-keys
gpg2 --list-secret-keys

# 发送到中央密钥服务
gpg2 --keyserver keyserver.ubuntu.com --recv-keys CA925CD6C9E8D064FF05B4728190C4130ABA0F98

# 导出密钥到文件
gpg2 --export-secret-keys --armor CA925CD6C9E8D064FF05B4728190C4130ABA0F98 > you_name@gmail.com.gpg.key

3. 编写 github action(workflow)脚本 (自动导入 GPG key)

name: Build and deploy

on:
  workflow_call:
    #inputs: {}
    secrets: ## see:https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#example-of-onworkflow_callsecrets
      PERSONAL_ACCESS_TOKEN:
        description: 'A developer personal token from the caller workflow'
        required: false
      OSSRH_USERNAME:
        description: 'A deploy to Maven central (OSSRH) username from the caller workflow'
        required: false
      OSSRH_TOKEN:
        description: 'A deploy to Maven central (OSSRH) token(password) from the caller workflow'
        required: false
      MAVEN_GPG_PRIVATE_KEY:
        description: 'A deploy to Maven central (OSSRH) GPG private key from the caller workflow'
        required: false
      MAVEN_GPG_PASSPHRASE:
        description: 'A deploy to Maven central (OSSRH) GPG private key password from the caller workflow'
        required: false

jobs:
  build-deploy:
    steps:
      - name: Configure GPG Key
        if: ${{ inputs.enable-build == true && inputs.enable-deploy == true }}
        env:
          MAVEN_GPG_PRIVATE_KEY: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }}
          MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }}
        run: |
          ## Check for gpg keys.
          if [[ -z "$MAVEN_GPG_PRIVATE_KEY" || -z "$MAVEN_GPG_PASSPHRASE" ]]; then
            echo "ERROR: No MAVEN_GPG_PRIVATE_KEY or MAVEN_GPG_PASSPHRASE defined"; exit 1
          fi

          ## Check for supported gpg version.
          gpg_version=$(gpg --version | head -1 | grep -iEo '(([0-9]+)\.([0-9]+)\.([0-9]+))') # eg: 2.2.19
          gpg_version_major=$(echo $gpg_version | awk -F '.' '{print $1}')
          gpg_version_minor=$(echo $gpg_version | awk -F '.' '{print $2}')
          gpg_version_revision=$(echo $gpg_version | awk -F '.' '{print $3}')
          if [[ ! ("$gpg_version_major" -ge 2 && "$gpg_version_minor" -ge 1) ]]; then
            echo "ERROR: The GPG version must >= $gpg_version_major.$gpg_version_minor.x"; exit 1
          fi

          rm -rf ~/.gnupg/; mkdir -p ~/.gnupg/private-keys-v1.d/; chmod -R 700 ~/.gnupg/
          echo -n "$MAVEN_GPG_PRIVATE_KEY" > /tmp/private.key

          #cat /tmp/private.key # for debugging

          ## FIXED:https://github.com/keybase/keybase-issues/issues/2798#issue-205008630
          #export GPG_TTY=$(tty) # Notice: github action the VM instance no tty.

          ## FIXED:https://bbs.archlinux.org/viewtopic.php?pid=1691978#p1691978
          ## FIXED:https://github.com/nodejs/docker-node/issues/922
          ## Note that since Version 2.0 this passphrase is only used if the option --batch has also
          ## been given. Since Version 2.1 the --pinentry-mode also needs to be set to loopback.
          ## see:https://www.gnupg.org/documentation/manuals/gnupg/GPG-Esoteric-Options.html#index-allow_002dsecret_002dkey_002dimport
          gpg2 -v --pinentry-mode loopback --batch --secret-keyring ~/.gnupg/secring.gpg --import /tmp/private.key

          rm -rf /tmp/private.key
          ls -al ~/.gnupg/

          gpg2 --list-keys
          gpg2 --list-secret-keys

          ## Notice: Test signing should be performed first to ensure that the gpg-agent service has been 
          ## pre-started (gpg-agent --homedir /root/.gnupg --use-standard-socket --daemon), otherwise
          ## an error may be reported : 'gpg: signing failed: Inappropriate ioctl for device'
          echo "Preparing testing the GPG signing ..."
          echo "test" | gpg2 -v --pinentry-mode loopback --passphrase $MAVEN_GPG_PASSPHRASE --clear-sign

4. 配置密钥 (github secret variables)

5. FAQ

  • 5.1 在 github action workflow 中执行导入 GPG 错误1:

    gpg: key D4862BB6D276F6BC: public key "you_name@gmail.com " imported
    gpg: key D4862BB6D276F6BC/D4862BB6D276F6BC: error sending to agent: No such file or directory
    gpg: error building skey array: No such file or directory
    gpg: error reading '/home/runner/private.key': No such file or directory
    gpg: import from '/home/runner/private.key' failed: No such file or directory
    gpg: Total number processed: 0
    gpg:               imported: 1
    gpg:       secret keys read: 1
    Error: Process completed with exit code 2.
    gpg2 -v **--pinentry-mode loopback** --secret-keyring ~/.gnupg/secring.gpg --import /tmp/private.key

  • 5.2 在 github action workflow 执行 mvn deploy -Prelease 错误2:gpg: cannot open '/dev/tty': No such device or address

    **export GPG_TTY=$(tty)**
    gpg2 -v --pinentry-mode loopback --secret-keyring ~/.gnupg/secring.gpg --import /tmp/private.key

6. 参考资料

留言

您的电子邮箱地址不会被公开。