用Gradle在Maven Central上打包发布了第一个Java Library
最近在做一些Java上面的小试验,然后做到一半突然觉得,似乎可以把这个代码转化为一个target Java 8的库,然后就在想,是不是可以发布到Maven上面呢?这样的话,就可以在别的项目或者让其他人能够用到了呢。
另外一方面,这几年认识的朋友也都有发布过自己的仓库,所以也想试试呢。
于是首先第一步就是把原本的intelliJ生成的只有src的项目转化为符合Gradle文件结构的模样。
这一步大概就是看着别的基于Gradle的项目的文件结构来做的,具体来说有这么几个步骤吧:
创建
gradle/wrapper
文件夹复制一个
gradle-wrapper.jar
进来创建一个
gradle-wrapper.properties
,并且在里面增加必要的属性:1
2
3
4
5distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists这些属性是和项目本身无关的,所以直接复制过来就好。
把gradlew和gradlew.bat文件复制过来
创建settings.gradle.kts文件,并且在里面把
rootProject.name
设置为项目名创建build.gradle.kts文件,并且填充必要的信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19plugins {
id("java")
}
group = "com.company.example"
version = "0.9.9"
repositories {
mavenCentral()
}
dependencies {
testImplementation(platform("org.junit:junit-bom:5.9.1"))
testImplementation("org.junit.jupiter:junit-jupiter")
}
tasks.test {
useJUnitPlatform()
}这里需要注意的是group的名字必须和之后修改后的代码在src里面的路径相匹配,version的话,Central Portal的部署不再支持打包SNAPSHOT版本,所以需要指定一个不是SNAPSHOT的版本号。
最后一步,在src下创建main文件夹,然后创建java文件夹,再按照前面定义的group把包名路径创建出来,例如这里就应该是
src/main/java/com/company/example
,然后把原先src下的所有Java文件转移过去然后reload一下Gradle的配置文件,这时候这个项目就已经被Gradle托管了。还可以进一步把test文件夹也创建了。
那么到这里就已经有了一个简单的,用Gradle来管理的Java项目。该考虑怎么打包到Maven仓库上面了。因为我用的GitHub来管理代码,所以用GitHub actions就是很自然的选择。GitHub的官方文档推荐用maven-publish插件,并且给出了很详细的介绍。
但是问题在于,这个插件给出的方法是基于OSSRH的。根据Maven Central的官方说明,OSSRH已经是legacy的接入口,所有新的注册和发布都会基于Central Portal而OSSRH仅对极个别情况开放。
我之前注册的Maven账户也是基于Central Portal的,换句话说,就是GitHub文档所推荐的办法是没法用的。
按照官方声明,官方并没有支持Gradle的基于Central Portal的发布方法。
Currently, there is no official Gradle plugin for publishing to Maven Central via the Central Publishing Portal
看起来就卡住了。
不过还好社区有不少第三方的插件,其中有几个一直有维护。在折腾了几天后我选择了gradle-maven-publish-plugin,于是就需要把build.gradle.kts给修改一下。
不过首先先在Central Portal里面拿一下用户名和密码(不是登入的时候的那个,是使用Publisher API的时候需要用到的)。打开https://central.sonatype.com然后登入进去后,在View Account里面,选择Generate User Token就可以拿到(或者刷新)一个用户名和密码了。
1 |
|
大概是这样的格式。
然后去Namespaces里面,需要去claim一个namespace,这里会需要用到自己名下的域名,得去DNS提供商那边在@下面加一行TXT记录。然后等待验证就行了。
Central Portal弄好了之后,就得更新项目文件了。有两个文件需要更新,一个是刚才提到的Gradle的kts配置文件,另一个是GitHub Actions的配置,用以在需要的时间点触发workflow。
首先是Gradle这边,先在plugins里面增加一行:
1 |
|
这里需要注意一个有点微妙的地方:我的项目JDK版本是1.8的,但是Gradle也依赖Java JDK,而不同版本的Gradle和Gradle所引用的插件,需要的JDK版本是不一样的。如果我在1.8下面,在引入这个新插件后,build.gradle.kts会出现语法错误。
这时候只需要在Settings - Build, Execution, Deployment - Build Tools - Gradle里面,把这个项目的Gradle JVM改为较新的版本,例如IDEA自带的jbr-17,重新reload一下,就可以了。
为了保证项目输出的代码版本,也可以添加这么一行:
1 |
|
加了新插件重新刷新依赖后,就可以增加打包相关的配置了。
我这里在配置文件最后加上的部分大概是这样:
1 |
|
其实这个也是插件的官方文档给出的样例。
然后需要用到GPG生成的私钥、Passphrase和短ID,这里就不详细介绍了。
结合之前的Central Portal的用户名密码,一共是五个变量。
在GitHub的仓库设置里,Security - Secrets and variables - actions - Repository secrets里面,加入这五个变量。
然后就是定义GitHub
actions的配置了,需要在根目录下创建.github/workflows
文件夹,并且在里面创建一个yml文件,例如release.yml。
大概长这样:
1 |
|
这里的env下面的五个变量刚好是我们刚才放进GitHub仓库设置里面的五个变量。
根据插件的官方文档的Secrets栏目,这五个变量的变量名是固定的,也就是ORG_GRADLE_PROJECT
开头的五个固定的名字。
然后我这里的话,设定为每次合并PR后会运行一次打包release一个版本,所以我设置成这样:
1 |
|
修改on的内容就可以按照不同的需求去决定workflow的运行时机,例如on: [push]
会在每次push被触发的时候运行一次这个job。按照不同的需求,就可以组合出很复杂的流程,例如引入一些简单的测试。jobs.publish.if
限制了这个流程只能在github.event.pull_request.merged
的值为true的时候才被运行,换句话说,就是只有被合并了的PR可以触发workflow。
然后按照平常一样修改代码,开PR,合并PR后,再登入Central Portal,就会发现有一个Deployment被推送上来了。这时候就可以选择Publish,把它发布出来,或者Drop掉它。如果选Publish的话,十几分钟后,就可以在Maven Central里面搜到这个新发布的Java库了。
大概就是这样了。
于是也就发布了我的第一个Maven仓库了呢(撒花)