通过 GitHub Action 自动发布 Maven 包到中央仓库

前言

前阵子微软 leader round 面试的时候聊到我做的的开源项目 nebula-jdbc,面试官问到了这个项目的被使用情况,我知道这个项目有人在用(因为有人在 issue 中提问了哈哈哈哈)但是不知道有多少人在用,所以当时只回答了这个 repo 的 watch、fork 和 star 数量,因为我并没有把这个项目打成 jar 包发布到 maven 中央仓库。事后想想确实有必要打包发布,一方面方便用户使用,一方面也能看到被使用的情况。

流程

配置 GPG

GnuPG,简称 GPG,是 GPG 标准的一个免费实现。不管是 Linux 还是 Windows 平台,都可以使用。GPGneng 可以为文件生成签名、管理密匙以及验证签名。发布到Maven仓库中的所有文件都要使用 GPG 签名保证不被篡改。具体的配置过程可以参考这篇博客。最终需要用到 GPG 密钥(导出的一长串)和 Passphrase(自己在生成密钥过程中设置的密码)

注册 Sonatype 账号

不能直接向 maven 中央仓库中发包,需要发布到 Nexus 然后由它定期自动同步到 maven 的中央仓库。首先需要注册 Sonatype 账号,然后提交一个 issue 说明你要发布的这个 jar 包的信息,具体过程可以参考这篇博客。一开始我不知道还有这个步骤,然后发包时就报了 403 forBiden 的错误。。。

GitHub Action

GitHub Action 是 GitHub 推出的实现 CI/CD(持续集成、持续交付/部署)的手段。可以创建工作流程来构建和测试存储库的每个拉取请求,或将合并的拉取请求部署到生产环境,由 GitHub 提供虚拟机来运行你在 workflow 文件中写好的执行流程。

GitHub Action 可以针对不同的时间设置不同的处理流程,这次我要实现的目标是在 release 一个新版本时自动打包发布,所以监听的是 released 事件,处理流程复用了 samuelmeuli/action-maven-publish。事实上 GitHub Action 能做的事情远不止如此,比如还可以在新 pr 提交的时候自动跑一遍测试用例以及做一些定时任务之类的…

首先在仓库的 Actions 中 new workflow,工作流的 yml 文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 相当于脚本用途的一个声明
name: Maven Central Repo Deployment
# 触发脚本的事件 这里为发布release之后触发
on:
release:
types: [released]
# 定义一个发行任务
jobs:
release:
# 运行处理流程的 OS 环境
runs-on: ubuntu-18.04
steps:
- name: Check out Git repository
uses: actions/checkout@v2

- name: Install Java and Maven
uses: actions/setup-java@v1
with:
java-version: 8

- name: Release Maven package
uses: samuelmeuli/action-maven-publish@v1
with:
# 一系列需要的密码
gpg_private_key: ${{ secrets.GPG_SECRET }} # GPG 导出的那段长长的密钥
gpg_passphrase: ${{ secrets.GPG_PASSWORD }} # 自己设置的 GPG 密码
nexus_username: ${{ secrets.OSSRH_USER }} # sonatype 用户名(不是邮箱)
nexus_password: ${{ secrets.OSSRH_PASSWORD }} # sonatype 登录密码

上面提到的一系列密码保存在 repo 的 Settings->Secrets->Actios->Repository secrets

pom.xml 配置

具体可以参考如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>

<groupId>io.github.young-flash</groupId>
<artifactId>flash-GAT</artifactId>
<version>4.0.0</version>


<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>

<!-- 项目信息 -->
<name>Github-Action-Test-By-Flash</name>
<description>Github-Action-Test-By-Flash</description>
<url>https://github.com/Young-Flash/GitHub-Action-Test</url>

<!-- 项目地址信息 -->
<scm>
<connection>scm:git:https://github.com/Young-Flash/GitHub-Action-Test</connection>
<url>https://github.com/Young-Flash/GitHub-Action-Test.git</url>
<developerConnection>scm:git:https://github.com/Young-Flash/GitHub-Action-Test</developerConnection>
</scm>

<!-- licenses 信息 -->
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
</license>
</licenses>

<!-- 开发者信息 -->
<developers>
<developer>
<name>Flash</name>
<email>871946895@qq.com</email>
</developer>
</developers>

<!-- 如果用到了 snapshot 版本的依赖则需要加上下面这个声明 -->
<repositories>
<repository>
<id>snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</repository>
</repositories>

<dependencies>
<!-- 你的依赖 -->
</dependencies>

<profiles>
<profile>
<id>deploy</id>
<build>
<plugins>
<!-- Javadoc plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<doclint>none</doclint>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>

<!-- Source plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>

<!-- GPG plugin -->
<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>
<!-- Prevent `gpg` from using pinentry programs -->
<gpgArguments>
<arg>--pinentry-mode</arg>
<arg>loopback</arg>
</gpgArguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>

<distributionManagement>
<!-- Central Repository -->
<snapshotRepository>
<id>ossrh</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
<repository>
<id>ossrh</id>
<name>Nexus Release Repository</name>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>

<build>
<plugins>
<!-- Nexus Staging Plugin -->
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.8</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://s01.oss.sonatype.org</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
</configuration>
</plugin>
</plugins>
</build>

</project>

发布

所有准备工作就绪后就可以尝试发布了,release 一个新版本,此时会自动触发你在 workflow 的 yml 文件中设置的执行流程,具体地运行情况可以在 Actions 中看到,可以会报错,这个就需要看报错信息自己去摸索解决方法了。

踩坑

“nexus-staging-maven-plugin:1.6.8:deploy failed: 403 - Forbidden”

按照其他教程的步骤来,一切配置就绪后发布时遇到这个错误,查了很久都没找到解决方法。后来在这篇博客中看到还有一个注册工单的步骤,完成工单后再发布就没问题了。过程中会有社区机器人验证你创建的工单的合法性,比如需要验证你对该 github 账号的所有权(让你建一个指定名字的临时仓库)和 groupId 对应的域名的所有权。

“The POM for … is missing, no dependency information available”

在为项目引入依赖后发布时遇到这个错误,原因是我引入的那个依赖是 SNAPSHOT 版本,需要在 pom.xml 中加上 <repository> 声明

1
2
3
4
5
6
<repositories>
<repository>
<id>snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</repository>
</repositories>

包发布成功后需要一段时间才会同步到中央仓库,发布后成功后过小半天后可以先在 sonatype 上查看

参考