0x00 前言
手动发布的方法详见《发布 JAR 到 Maven 中央仓库全流程指引》。
但是手动发布效率太低,而且每次都要交互输入密码,因此很自然就想到利用 Github Actions 自动发布。
Github Actions 是对标 Gitlab Ci/CD 的流水线工具
0x10 改造流程
在手动发布基础上,需要改造的要点为:
- GPG 签名改为非交互模式输入密码
- 添加 Github Actions 脚本
- 设计合理的发版规约以触发流水线脚本
配置自动发布之前,首先确保手动发布流程能走通
0x20 GPG 签名改为非交互模式
因为 Github Actions 是完全用流水线脚本自动执行的,而手动发布方式中,唯一的交互点就是 GPG 签名时需要输入其密码,故需要改造为无交互方式才能满足自动化执行。
只需要修改 pom.xml 中 maven-gpg-plugin 插件的配置,在手动发布的配置基础上,添加 <configuration>
即可变为非交互模式:
<!-- GPG 签名 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
<configuration>
<!-- 必须配置,用于 gpg 非交互式密码输入 -->
<gpgArguments>
<arg>--pinentry-mode</arg>
<arg>loopback</arg>
</gpgArguments>
</configuration>
</execution>
</executions>
</plugin>
但是建议新建一个 <profile>
专用于流水线非交互式发布,这样就不会影响原有的配置:
<project>
... ...
<profiles>
... ...
<!-- 专用于 Github Actions 命令行发布的 profile (主要是 GPG 签名插件需要配置非交互模式输入密码) -->
<profile>
<id>autoDeploy</id>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<!-- 编译 maven 工程 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.0</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<!-- 生成源码 jar 包 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- 生成 javadoc 包 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.3.2</version>
<configuration>
<charset>${project.build.sourceEncoding}</charset>
<encoding>${project.build.sourceEncoding}</encoding>
<docencoding>${project.build.sourceEncoding}</docencoding>
<!-- 从 JDK8 开始, Javadoc中 添加了 doclint, 目的是旨在获得符合 W3C HTML 4.01 标准规范的 HTML 文档 -->
<!-- 简而言之 Javadoc 不允许出现 html 相关的元素, 若旧注释含有这些元素又不想修改, 只能关闭 doclint -->
<additionalOptions>
<additionalOption>-Xdoclint:none</additionalOption>
</additionalOptions>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- GPG 签名 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
<configuration>
<!-- 必须配置,用于 gpg 非交互式密码输入 -->
<gpgArguments>
<arg>--pinentry-mode</arg>
<arg>loopback</arg>
</gpgArguments>
</configuration>
</execution>
</executions>
</plugin>
<!-- 分发管理和认证:用于部署和发布到中央仓库 https://mvnrepository.com/ -->
<!-- 此插件对于发布 SNAPSHOT 版本时不会触发 -->
<!-- 其作用是自动在 https://s01.oss.sonatype.org/ 的 Staging Repositories 中 close 并 release,无需手动干预 -->
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.13</version>
<extensions>true</extensions>
<configuration>
<serverId>sonatype</serverId> <!-- 要与 distributionManagement 定义的 id 一致 -->
<nexusUrl>https://s01.oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
</configuration>
</plugin>
</plugins>
</build>
</profile>
... ...
</profiles>
... ...
</project>
完整的配置可参考开源工程 exp-libs-refactor 的 pom.xml
0x30 添加 Github Actions 脚本
在 Maven 工程的根目录创建 Github Actions 脚本 .github/workflows/auto_deploy.yml
,其内容如下:
name: Automatically deploy to sonatype
on:
# 手动触发构建
workflow_dispatch:
# (从版本分支)创建 release 的时候触发 (release 版)
release:
types: [published]
# 把特性分支合并到 v* 版本分支时触发 (snapshot 版)
pull_request:
branches: [v*]
# 推送特性分支时触发 (snapshot 版)
# push:
# branches: [feature-*]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
# 拉取仓库
- name: Check out repo
uses: actions/checkout@v2
# 设置 Java 环境
- name: Set up Java env
uses: actions/setup-java@v1
with:
java-version: 1.8
server-id: sonatype # 要与 distributionManagement 定义的 id 一致
server-username: MAVEN_USERNAME
server-password: MAVEN_CENTRAL_TOKEN
gpg-passphrase: MAVEN_GPG_PASSPHRASE
gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
# 发布 Jar 到 Maven 中央仓库
- name: Publish to Sonatype Maven Central
run: mvn clean deploy -P autoDeploy # 指定使用 pom.xml 的 <profile>.<id>autoDeploy</id> 配置进行发布
env:
MAVEN_USERNAME: ${{ secrets.SONATYPE_USERNAME }}
MAVEN_CENTRAL_TOKEN: ${{ secrets.SONATYPE_PASSWORD }}
MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE_KEY }}
此脚本需要修改的内容为:
- 触发条件: 按需修改,主要依赖自行设计的发版规则
java-version
: JDK 版本,根据实际工程修改server-id
: 要与 pom.xml 中<distributionManagement>
定义的<id>
一致mvn clean deploy -P autoDeploy
:-P
后面的参数与 pom.xml 中定义的非交互模式的<profile>.<id>
一致
此脚本需要到仓库的 settings -> secrets -> actions -> New repository secret
中设置的变量有 4 个:
SONATYPE_USERNAME
: 在 Sonatype JIRA 申请的帐号SONATYPE_PASSWORD
: 在 Sonatype JIRA 申请的密码GPG_PASSPHRASE_KEY
: 在生成 GPG 密钥对时所设置的保护密码GPG_PRIVATE_KEY
: 通过 GPG 命令生成密钥对时的私钥
查询 GPG 私钥的方法见:《GnuPG 环境安装与配置》
完整的流水线脚本可参考开源工程 exp-libs-refactor 的 auto_depoly.yml
0x40 设计合理的发版规约
但有了流水线自动化,还需要配合一套发版规约才能使其有效运转起来。
各个组织、各个人、各个项目的发版规约不尽相同,故此处不深入讨论这个问题,但是笔者的开源工程 exp-libs-refactor 设计了一套发版规约以配合上述的流水线脚本,或许能给大家参考一下。