多模块 Gradle Java 项目发布到新 Maven中央仓库最新指南

背景说明

最近有个项目希望发布到 Maven 中央仓库,发现从 2024 年 3 月 12 日起,所有注册都将通过 Maven Central Portal 进行, 不再走过去的提交 issue 的那套流程。

而网上大部分都是介绍使用旧版本的 OSSRH 的发布方法,新版本的发包的介绍很少,并且由于 Gradle 插件目前没有官方的支持,三方插件很多,其中坑不少,有些插件按照文档配置并不能正常的发布。

加上,我们的这个项目是包含多个模块及支持 BOM 的 Gradle 项目,使得发布的配置很难有比较好的参考,折腾的好几天,总算找个比较合理的方案解决。

今天就把这个最新的方案分享一下,希望大家少踩坑,省时省力的发布到新的 Maven Central。

另外,旧版的注册与发布,可以参考下面的两个文档

  • 旧版注册的信息,可以看这个文档
  • 旧版本的OSSRH 发布方法,看这个文档

准备工作

注册Central Portal账户

  • 通过 Maven Central Portal 注册账号,建议使用 github 直接登录。
  • 创建命名空间如(io.github.username),需验证域名或GitHub仓库所有权。 对于 io.github 可以通过 github 直接注册登录Maven Central Portal即可自动完成验证。 对于自定义的域名,首先这个域名没有在 OSSRH 上注册过,如果注册过,会提示无法注册,并给了一个 support 邮件,可以通过邮件联系。
  • 通过 Portal 生成用户令牌(SONATYPE_USERNAMESONATYPE_USERNAME),后面的配置会用到

GPG密钥准备

安装 GnuPG

生成 key

gpg --gen-key

生成过程中需要输入一次密码,这个密码就是 GPG_PASSPHRASE(也有文档叫 GPG_SIGNING_PASSWORD) 也需要一个邮箱,后面导出秘钥需要用到。

列出 KEY 信息

plain 复制代码
$ gpg --list-keys /home/mylocaluser/.gnupg/pubring.kbx 
--------------------------------
- pub rsa3072 2021-06-23 [SC] [expires: 2023-06-23] 
      CA925CD6C9E8D064FF05B4728 uid [ultimate] Central Repo Test 
<central@example.com> sub rsa3072 2021-06-23 [E] [expires: 2023-06-23]

输出显示公钥环文件的路径。以 pub 开头的行显示大小 (rsa3072)、keyid (CA925CD6C9E8D064FF05B4728190C4130ABA0F98) 和创建日期 (2023-06-23) 的公钥. 分发公钥时,我们需要使用 keyid

分发公钥

bash 复制代码
gpg --keyserver keys.openpgp.org --send-keys CA925CD6C9E8D064FF05B4728
gpg --keyserver pgp.mit.edu --send-keys CA925CD6C9E8D064FF05B4728

导出秘钥

我们使用 Gradle 生成签名,需要 GPG_PASSPHRASE 和 GPG_SIGNING_KEY。 首先我们需要导出 GPG_SIGNING_KEY

bash 复制代码
gpg --armor --export-secret-key your_email
-----BEGIN PGP PRIVATE KEY BLOCK-----

xxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxx

-----END PGP PRIVATE KEY BLOCK-----

导出 GPG_SIGNING_KEY 秘钥后的整个文本块都需要配置到环境变量里。

配置秘钥到环境变量里

修改 ~/.zshrc 或 ~/.bashrc

bash 复制代码
export GPG_PASSPHRASE='YOUR_PASSWORD'
export GPG_SIGNING_KEY='
-----BEGIN PGP PRIVATE KEY BLOCK-----
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-----END PGP PRIVATE KEY BLOCK-----
'

Gradle 项目中配置发布 - 单模块

1. 在 build.gradle 或 build.gradle.kts 中添加必要的插件

对于 Groovy DSL(build.gradle):

groovy 复制代码
plugins {
    id 'java-library'
    id 'maven-publish'
    id 'signing'
}

2. 配置发布信息

关键点: mavenJava 这个是自定义的一个值

这个其实就是 publishing 插件产物的目录,签名需要这个目录。

groovy 复制代码
group = 'io.github.yourusername'
version = '1.0.0'

publishing {
    publications {
        mavenJava(MavenPublication) {
            from components.java
            pom {
                name = 'Your Project Name'
                description = 'A description of your project'
                url = 'https://github.com/yourusername/project'
                
                licenses {
                    license {
                        name = 'The Apache License, Version 2.0'
                        url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                    }
                }
                
                developers {
                    developer {
                        id = 'yourusername'
                        name = 'Your Name'
                        email = 'your.email@example.com'
                    }
                }
                
                scm {
                    connection = 'scm:git:git://github.com/yourusername/project.git'
                    developerConnection = 'scm:git:ssh://github.com/yourusername/project.git'
                    url = 'https://github.com/yourusername/project'
                }
            }
        }
    }
}

3. 配置签名

只要是配置了 publishing 的地方就需要配置签名。

groovy 复制代码
signing {
    def signingKey = findProperty('GPG_SIGNING_KEY') ?: System.getenv('GPG_SIGNING_KEY')
    def signingPassword = findProperty('GPG_PASSPHRASE') ?: System.getenv('GPG_PASSPHRASE')
    
    useInMemoryPgpKeys(signingKey, signingPassword)
    sign publishing.publications.mavenJava
}

4. 配置源码和 JavaDoc 和 Java Source

发布到 Maven Central 必须要有 Java Docs 以及 Java Sources

groovy 复制代码
java {
    withJavadocJar()
    withSourcesJar()
}

javadoc 编译有可能失败,可以优化对 JavaDoc 的编译限制。

groovy 复制代码
tasks.withType(Javadoc) {
    options {
        encoding = 'UTF-8'
        charSet = 'UTF-8'
        author = true
        version = true
        links = ['https://docs.oracle.com/en/java/javase/17/docs/api/']
        if (JavaVersion.current().isJava9Compatible()) {
            addBooleanOption('html5', true)
        }
        // 忽略一些警告
        addStringOption('Xdoclint:none', '-quiet')
    }
    // 忽略 Javadoc 错误
    failOnError = false
}

多模块buildSrc结构项目配置

buildSrc 插件配置

我们在 buildSrc 的 gradle 插件扩展为: io.github.yourname.myproject.java-conventions.gradle 通过修改 java-conversion.gradle 文件,来添加 publish,内容与单模块一样。

groovy 复制代码
// java-conversion.gradle
plugins {
    id 'java-library'
    id 'maven-publish'
    id 'signing'
}

// 其他配置参考单模块

publishing {
    publications {
        mavenJava(MavenPublication) {
            groupId = project.group
            version = project.version
            from(components.java)
            pom {
            // 参考单模块
            }
        }
    }
}

signing {
    required { gradle.taskGraph.hasTask("publish") }
    def signingKey = System.getenv("GPG_SIGNING_KEY")
    def signingPassword = System.getenv("GPG_SIGNING_PASSWORD")
    useInMemoryPgpKeys(signingKey, signingPassword)
    // 注意:这个使用 mavenJava
    sign publishing.publications.mavenJava
}

因为子模块会通过 id 'io.github.yourname.myproject.java-conventions' 来引用,所以配置会统一生效。

bom gradle 配置

groovy 复制代码
// 在 BOM 模块的 build.gradle 中
plugins {
    id 'java-platform'
    id 'maven-publish'
    id 'signing'
}

publishing {
    publications {
        mavenBom(MavenPublication) {
            from components.javaPlatform
            pom {
                name = 'Your Project BOM'
                description = 'Bill of Materials for Your Project'
                // ...其他 POM 信息
            }
        }
    }
}

signing {
    required { gradle.taskGraph.hasTask("publish") }
    def signingKey = System.getenv("GPG_SIGNING_KEY")
    def signingPassword = System.getenv("GPG_SIGNING_PASSWORD")
    useInMemoryPgpKeys(signingKey, signingPassword)
    // 注意:这个使用 mavenBom
    sign publishing.publications.mavenBom
}

上传 Maven Central

ncmp 插件

在项目 root build.gradle 中添加上传 maven central 插件,此次推荐使用 ncmp。

注意 : 这里SONATYPE_USERNAME不是咱们注册时的账号,而是通过 portal 生成的账号。

groovy 复制代码
// 主 build.gradle
plugins {
    id 'java-platform'
    id 'maven-publish'
    id 'signing'
    id("com.gradleup.nmcp").version("0.0.8")
}

allprojects {
    group = project.findProperty('group')
    version = project.findProperty('version')

    nmcp {
        publishAllPublications {

        }
    }
}

nmcp {
    publishAllProjectsProbablyBreakingProjectIsolation {
        username = System.getenv("SONATYPE_USERNAME");
        password = System.getenv("SONATYPE_PASSWORD");
        // 如果子模块很多建议使用 AUTOMATIC, 也可以使用 USER_MANAGED
        publicationType = "AUTOMATIC"
    }
}

发布

  1. 发布之前,使用 publish 命令检查下文件
bash 复制代码
./gradlew publish

可以看到一个 ncmp 的目录,检查是否存在 .asc 的签名文件,以及 .md5 等 checksum 文件

  1. 使用这个命令发布
bash 复制代码
./gradlew publishAllPublicationsToCentralPortal
相关推荐
shengjk17 分钟前
Flink 中RocksDB 为什么将每个键和值的限制为 2^31 字节
人工智能·后端
neo_Ggx2341 分钟前
Spring上下文工具类
java·后端·spring
西岭千秋雪_1 小时前
Spring MVC源码分析の请求处理流程
java·后端·spring·mvc·springboot
web147862107231 小时前
Spring Framework 中文官方文档
java·后端·spring
Pitayafruit1 小时前
【📕分布式锁通关指南 07】源码剖析redisson利用看门狗机制异步维持客户端锁
redis·分布式·后端
小菜不菜_xc2 小时前
Spring Boot + MyBatis-Plus 最全配置指南,让你的项目更高效!
java·后端·spring
uhakadotcom2 小时前
阿里云PAI:一站式机器学习平台
后端·面试·github
Matrix702 小时前
Scala编程_数组、列表、元组、集合与映射
开发语言·后端·scala
uhakadotcom2 小时前
阿里云可观测监控Prometheus版:简化监控,提升效率
后端·面试·github
37手游后端团队2 小时前
聊聊提示词注入攻击那些事
人工智能·后端·程序员