将项目发布到Maven Central仓库

上一篇文章说到做了一个开源的项目。Java项目如果不发布到Maven Central仓库,会给使用者带来不便。在实际操作的时候发现,发布的工作其实还是比较繁琐的,具体的步骤包括:

  • 提交申请并通过人工审核
  • 完善Maven信息
  • 提供javadocsources的jar包
  • 使用GPG/PGP给上传的文件签名
  • 发布文件到OSSRH仓库

本文整合了官方多个文档的相关内容,梳理一个清晰的流程,并配置Maven做到一键发布。

在OSSRH申请账号并提交申请

只有在Apache Software Foundation、FuseSource Forge与Nuiton.org上托管的项目才可以做到自动发布。其他项目,需要到在Sonatype提供的Open Source Software Repository Hosting (OSSRH)上提交申请,并等待人工审核通过后首先发布到OSSRH,之后再由OSSRH同步到Maven的Central。你没有看错,是人工审核。

StarDict托管在GitHub上,所以只能通过OSSRH发布。

首先,在https://issues.sonatype.org/上注册一个新账号,成功登陆到Dashboard之后,在上边菜单选择”Create”,在弹出窗口中参考下图填写:

ossrh-form.jpeg

审核时间最多是2个工作日,一般几个小时就可以通过。我申请中还碰到了一个小插曲:申请使用的Group Idcom.orangereading,被要求确认这个域名是我的,否则不可以用这个Group Id。证明的方式就是把域名指到项目的地址,于是加了一个子域名stardict.orangereading.com,做了一下重定向。上午提交的申请,大概1个小时就有回复,但我一直到晚上才看到,等域名重定向生效又用了一天,还真是用了2个工作日。

完善POM文件信息

OSSRH接受的项目的POM文件需要包含:Correct Coordinates,Project Name,Project Description and URL,License Information,Developer Information,SCM Information。具体说就是POM需要包含如下内容:

1
2
3
4
5
6
7
8
9
10
11
<modelVersion/>
<groupId/>
<artifactId/>
<version/>
<packaging/>
<name/>
<description/>
<url/>
<licenses/>
<developers/>
<scm/>

其中版本号version不能以-SNAPSHOT结尾,并且推荐使用semantic versioning

添加文档与源代码打包Maven插件

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
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

PGP

从安全方面考虑,发布到仓库中的所有文件都需要使用PGP来签名,PGP签名可以使用GnuPG,key服务器可以使用hkp://pool.sks-keyservers.net,下边是在Mac上的操作步骤:

安装GnuPG

1
brew install gnupg

生成Key

使用命令gpg --gen-key生成Key,按照提示输入姓名,邮箱以及密码即可,生成的Key文件存放在~/.gnupg/openpgp-revocs.d/下。可以使用命令gpg --list-keys查看生成的Key。

发布Key到服务器

当其他小伙伴需要对文件签名做验证的时候,就需要到一个可信的服务器上拿到Public Key。使用下边的命令将Public Key上传到服务器:

1
gpg --keyserver hkp://pool.sks-keyservers.net --send-keys 34EB5FXXXXXXXXXXXXXXX8D0FAC6

命令中的34EB5FXXXXXXXXXXXXXXX8D0FAC6在生成Key之后或者使用--list-keys命令都可以看到。

对文件进行签名

对文件进行签名使用命令gpg -ab 文件,输入密码后会生成一个同名的.asc文件,可以用命令gpg --verify 文件.asc对签名进行验证。可以使用Maven插件实现自动签名:

pom.xml中加入GPG的插件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

~/.m2/settings.xml加入下边内容:

1
2
3
4
5
6
7
8
9
10
11
12
<profiles>
<profile>
<id>ossrh</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<gpg.executable>gpg</gpg.executable>
<gpg.passphrase>PGP密码</gpg.passphrase>
</properties>
</profile>
</profiles>

注意上边的gpg.executable中的gpg要对应命令行下的命令,在Linux上安装2.0版的GPG,命令是gpg2而不是gpg,之后就可以单独运行mvn verify进行签名。

添加Nexus Staging插件实现自动发布

pom.xml中加入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<build>
<plugins>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.7</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
</configuration>
</plugin>
</plugins>
</build>
<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
</distributionManagement>

~/.m2/settings.xml加入下边内容:

1
2
3
4
5
6
7
<servers>
<server>
<id>ossrh</id>
<username>你的OSSRH用户名</username>
<password>你的OSSRH密码</password>
</server>
</servers>

配置好之后,在项目根目录运行mvn clean deploy就可以自动打包,签名并发布到OSSRH仓库中。上边配置中的autoReleaseAfterClose设置为true即指staging之后直接发布。

发布成功之后,一般10分钟就之内会同步到Central的仓库中,但是Maven搜索的索引更新时间要慢一些,大概需要2个小时。

我在上午8点做的发布,中午11点多在https://search.maven.org/就可以查到了,而另一个常用的搜索网站https://mvnrepository.com的更新要慢一些,一直到第二天才查得到。

参考配置

下边是StarDict项目的完整配置

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
154
155
156
157
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.orangereading</groupId>
<artifactId>stardict</artifactId>
<packaging>jar</packaging>
<version>0.2.2</version>
<name>StarDict</name>
<url>https://github.com/sean-liang/stardict</url>
<description>Tools to work with stardict dictionary files. Command line validation and export tool.</description>
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<scm>
<url>https://github.com/sean-liang/stardict.git</url>
<connection>scm:git:git://github.com/sean-liang/stardict.git</connection>
<developerConnection>scm:git:ssh://github.com/sean-liang/stardict.git</developerConnection>
</scm>
<issueManagement>
<url>https://github.com/sean-liang/stardict/issues</url>
<system>GitHub Issues</system>
</issueManagement>
<developers>
<developer>
<email>sean.liang.inbox@gmail.com</email>
<name>Sean Liang</name>
<url>https://liangshuang.name/</url>
</developer>
</developers>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.beust</groupId>
<artifactId>jcommander</artifactId>
<version>1.72</version>
</dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.11</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.8.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.7</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<archive>
<manifest>
<mainClass>
com.orangereading.stardict.App
</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
</distributionManagement>
</project>

~/.m2/settings.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
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
https://maven.apache.org/xsd/settings-1.0.0.xsd">
<localRepository/>
<interactiveMode/>
<usePluginRegistry/>
<offline/>
<pluginGroups/>
<servers>
<server>
<id>ossrh</id>
<username>你的OSSRH用户名</username>
<password>你的OSSRH密码</password>
</server>
</servers>
<mirrors/>
<proxies/>
<profiles>
<profile>
<id>ossrh</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<gpg.executable>gpg</gpg.executable>
<gpg.passphrase>PGP密码</gpg.passphrase>
</properties>
</profile>
</profiles>
<activeProfiles/>
</settings>

参考