Jade Dungeon

发布jar包到Maven中央仓库

发布到第三方仓库

Maven 中央仓库并不支持直接上传 jar 包,因此需要将 jar 包发布到一些指定的第三方 Maven 仓库, 比如:Sonatype OSSRH 仓库,然后该仓库再将 jar 包同步到 Maven ,本文详细记录整个发布、同步过程。

注册一个 Sonatype 用户

进入地址:https://issues.sonatype.org/secure/Signup!default.jspa 注册 Sonatype 用户,Sonatype 通过 JIRA(JIRA 是 Atlassian 公司出品的项目与事务跟踪工具) 来管理 OSSRH 仓库。

创建一个发布构件的 issue

提交「构件发布申请」的第一步是在 JIRA Dashborad 上创建一个 issue。如下所示,点击Create按钮:

会弹出一个对话框让你填写 issue 的详细信息,这里最重要的就是 Group Id,一般会带上域名, 千万别弄错了,这关系到以后发布其它的构件。我们这里是com.vesoft。

Sonatype 有域名验证,验证方式:

  • 选择一个带有项目托管信息的 GroupId,例如 io.github.facebook 或 com.github.facebook
  • 另外一种推荐的方式是使用免费的 free managed security reporting service

等待 issue 审核通过

审核因为时差原因需要一定时间,审核通过后会收到邮件通知,同时在对应 issue 下会看到 Sonatype 工作人员的回复,一般是添加一个 comment,内容大致如下:

Configuration has been prepared, now you can: Deploy snapshot artifacts into repository https://oss.sonatype.org/content/repositories/snapshots Deploy release artifacts into the staging repository https://oss.sonatype.org/service/local/staging/deploy/maven2 Promote staged artifacts into repository 'Releases' Download snapshot and release artifacts from group https://oss.sonatype.org/content/groups/public Download snapshot, release and staged artifacts from staging group https://oss.sonatype.org/content/groups/staging please comment on this ticket when you promoted your first release, thanks

使用 GPG 生成密钥对

生成密钥对

gpg --gen-key

会让选择加密方式,默认选择: RSA and RSA (default)

,需输入用户名和邮箱,和 Passphase——相当于密钥库密码。

查看公钥

gpg --list-keys

xxx/.gnupg/pubring.gpg
---------------------------------
pub   2048R/xxxx 2019-12-02
uid   $YOUR_UID <$YOUR_EMAIL>
sub   2048R/**** 2019-12-02

这里的公钥 ID 是 xxxx,马上就会用到了。

将公钥上传到 PGP 密钥服务器

gpg --keyserver hkp://keys.gnupg.net:11371 --send-keys xxxx

查看公钥是否上传成功

> gpg --keyserver hkp://keys.gnupg.net:11371 --recv-keys xxxx

gpg: 下载密钥‘xxxx’,从 hkp 服务器 keys.gnupg.net
gpg: 密钥 xxxx:“$YOUR_UID <$YOUR_EMAIL>”未改变
gpg: 合计被处理的数量:1
gpg: 未改变:1

注意:

  • 根据实际填写此处的公钥 ID
  • 很多网上教程给的是http://pool.sks-keyservers.net,个人感觉 http://pool.sks-keyservers.net这个 keyserver 不好用,上传了 key,经常会验证失败, 也获取失败,maven 支持两个key servers:http://keys.gnupg.net:11371http://pool.sks-keyservers.net:11371
  • 此处采用 hkp 协议而不是 http 协议很
  • 多教程没有给端口,经试验,需加上端口号

本地的私钥用来对上传的构件进行数字签名,而下载该构件的用户可通过上传的公钥来验证签名 --需验证这个构件是否由本人上传的,因为存在构件被篡改的可能。

修改Maven配置文件

修改 Maven 配置文件主要是需要修改setting.xml和项目的pom.xml文件

配置 Maven 的 setting.xml

修改~/.m2/setting.xml文件

<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
                      http://maven.apache.org/xsd/settings-1.0.0.xsd">
    <servers>
      <!-- ... -->
        <server>
            <id>snapshots</id>
            <username>$USER_NAME</username>
            <password>$YOUR_PASSWORD</password>
        </server>
        <server>
            <id>release</id>
            <username>$USER_NAME</username>
            <password>$YOUR_PASSWORD</password>
        </server>
    </servers>

</settings>

替换USER_NAMEYOUR_PASSWORDSonatype上面注册的用户名和密码, 这里的 ID 会在 pom.xml 里面使用到。

配置 Maven 的 pom.xml

<project>
    ...

    <!-- More Project Information -->
    <name>nebula-java</name>
    <description>Nebula Java Client</description>
    <url>https://github.com/vesoft-inc/nebula-java</url>
    <scm>
        <connection>scm:git:https://github.com/vesoft-inc/nebula</connection>
        <url>https://github.com/vesoft-inc/nebula</url>
        <developerConnection>scm:git:https://github.com/vesoft-inc/nebula</developerConnection>
    </scm>
    <licenses>
        <license>
            <name>Apache License, Version 2.0</name>
            <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
            <distribution>repo</distribution>
            <comments>license</comments>
        </license>
    </licenses>

    ...
    <profiles>
        <profile>
            <id>release</id>
            <build>
                <plugins>
                    <!-- Source -->
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-source-plugin</artifactId>
                        <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.1.1</version>
                        <configuration>
                            <excludePackageNames>com.facebook.thrift:com.facebook.thrift.*</excludePackageNames>
                        </configuration>
                        <executions>
                            <execution>
                                <id>attach-javadocs</id>
                                <phase>package</phase>
                                <goals>
                                    <goal>jar</goal>
                                </goals>
                                <configuration>
                                    <doclint>none</doclint>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>
                    <!-- GPG -->
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-gpg-plugin</artifactId>
                        <version>1.6</version>
                        <executions>
                            <execution>
                                <phase>verify</phase>
                                <goals>
                                    <goal>sign</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
            <distributionManagement>
                <repository>
                    <id>release</id>
                    <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
                </repository>
                <snapshotRepository>
                    <id>snapshots</id>
                    <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
                </snapshotRepository>
            </distributionManagement>
        </profile>
    </profiles>
    ...
</project>

pom.xml中必须包括:namedescriptionurllicensesdeveloperscm等基本信息 (血泪史之踩过的坑)发布 maven 除了 jar 必须还有文档包和源码包。 因此 pom 需添加maven-javadoc-pluginmaven-source-plugin。 参考示例:

com-vesoft-client
|-- pom.xml
|-- src\
`-- target
    `-- attach-source-javadoc-1.0-SNAPSHOT.jar
    `-- attach-source-javadoc-1.0-SNAPSHOT-javadoc.jar
    `-- attach-source-javadoc-1.0-SNAPSHOT-sources.jar

发布构建需要秘钥加密,因此 pom 需添加maven-gpg-plugin血泪史之踩过的坑

多模块项目配置

nebula-java 是多模块项目

<modules>
    <module>client</module>
    <module>examples</module>
</modules>

为了上传 Client,需要上传parentpom.xml,否则 Client 会找不到依赖 (血泪史之踩过的坑),但我们又不希望上传examples模块,所以要在examplesmaven-deploy-plugin中声明skip跳过布署。

故做了如下改动:

项目信息 name 、 description 、 url 、 licenses 、 developers 、 scm 等信息和 maven-gpg-plugin放在 parent 的pom.xml文件中:

<project>
  ...
    <name>nebula-java</name>
    <description>Nebula Java Client</description>
    <url>https://github.com/vesoft-inc/nebula-java</url>
    <scm>
        <connection>scm:git:https://github.com/vesoft-inc/nebula</connection>
        <url>https://github.com/vesoft-inc/nebula</url>
        <developerConnection>scm:git:https://github.com/vesoft-inc/nebula</developerConnection>
    </scm>
    <licenses>
        <license>
            <name>Apache License, Version 2.0</name>
            <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
            <distribution>repo</distribution>
            <comments>license</comments>
        </license>
    </licenses>

    <developers>
        <developer>
            <id>$ID</id>
            <name>$NAME</name>
            <email>$EMAIL</email>
            <organization>vesoft</organization>
            <roles>
                <role>architect</role>
                <role>developer</role>
            </roles>
        </developer>
    </developers>

    <distributionManagement>
        <repository>
            <id>release</id>
            <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
        </repository>
        <snapshotRepository>
            <id>snapshots</id>
            <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
        </snapshotRepository>
    </distributionManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-gpg-plugin</artifactId>
                <version>1.6</version>
                <executions>
                    <execution>
                        <phase>verify</phase>
                        <goals>
                            <goal>sign</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
  </project>

在 Java Client 的pom.xml中添加maven-javadoc-pluginmaven-source-pluginmaven-deploy-plugin

<plugins>
  ......
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-source-plugin</artifactId>
        <executions>
            <execution>
                <id>attach-sources</id>
                <goals>
                    <goal>jar</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-javadoc-plugin</artifactId>
        <version>3.1.1</version>
        <configuration>
            <excludePackageNames>com.facebook.thrift:com.facebook.thrift.*</excludePackageNames>
        </configuration>
        <executions>
            <execution>
                <id>attach-javadocs</id>
                <phase>package</phase>
                <goals>
                    <goal>jar</goal>
                </goals>
                <configuration>
                    <doclint>none</doclint>
                </configuration>
            </execution>
        </executions>
    </plugin>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-deploy-plugin</artifactId>
        <executions>
            <execution>
                <id>default-deploy</id>
                <phase>deploy</phase>
            </execution>
        </executions>
    </plugin>
</plugins>

在 example 模块的pom.xml中声明skip deploy

<plugins>
  ......
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-deploy-plugin</artifactId>
        <configuration>
            <skip>true</skip>
        </configuration>
    </plugin>
</plugins>

Q: 为什么 maven-gpg-plugin 放在 parent 的 pom.xm l中,而 maven-javadoc-plugin,maven-source-plugin 插件放在 Client 的 pom.xml 中

A: 因为上传的所有构件都需要加密,包括 parent 的 pom.xml,因此放在 parent 中; 而只有 Client 需要上传 javadoc,source,因此 maven-javadoc-plugin,maven-source-plugin 插件放在 Client 中。