Gradle 7.x 下如何发布 jar 包到 Maven Central

Posted by rarnu on 01-25,2023

以往我们都使用 6.x 版本的 Gradle,在这个基础上,可以使用 maven 插件来将 jar 包发布到 Maven Central。其具体做法如下(以公司的 common-jvm 包为例):

... ...
apply plugin: 'maven'
apply plugin: 'signing'
... ...
task javadocJar(type: Jar) {
    from javadoc
    classifier "javadoc"
}

task sourcesJar(type: Jar) {
    from sourceSets.main.allSource
    classifier "sources"
}

artifacts {
    archives javadocJar, sourcesJar
}

signing {
    sign configurations.archives
}
... ...
uploadArchives {
    repositories {
        mavenDeployer {
            beforeDeployment { deployment ->
                signing.signPom(deployment)
            }
            repository(url: nexus_release_url) {
                authentication(userName: nexus_username, password: nexus_password)
            }
            snapshotRepository(url: nexus_snapshot_url) {
                authentication(userName: nexus_username, password: nexus_password)
            }
            pom.project {
                name "common-jvm"
                packaging 'jar'
                description 'iSysCore Common Kotlin Library'
                url 'https://github.com/isyscore/common-jvm'
                scm {
                    connection 'https://github.com/isyscore/common-jvm'
                    developerConnection 'https://github.com/isyscore/common-jvm'
                    url 'https://github.com/isyscore/common-jvm'
                }
                licenses {
                    license {
                        name 'MIT License'
                        url 'https://github.com/isyscore/common-jvm/blob/main/LICENSE'
                    }
                }
                developers {
                    developer {
                        id 'isyscore'
                        name 'isyscore'
                        email 'hexj@isyscore.com'
                    }
                }
            }
        }
    }
}

虽然看起来挺麻烦的,但是也算是一劳永逸。但是当我们把 Gradle 版本升到 7.x 之后,这个发布方式就不能用了,原因是 maven 插件已被删除,而 7.x 带的插件是 maven-publish,这使得发布方式有了一个巨大的变化。

现在新的写法是这样的:

apply plugin: "java"
apply plugin: "maven-publish"
... ...
task sourcesJar(type: Jar) {
    classifier = "sources"
    from sourceSets.main.allJava
}

task javadocJar(type: Jar) {
    classifier = "javadoc"
    from javadoc.destinationDir
}

... ...

publishing {
    publications {
        mavenKotlin(MavenPublication) {
            groupId = "com.github.isyscore"
            artifactId = "common-jvm"
            version = "2.0.0"
            from components.java
            artifact sourcesJar
            artifact javadocJar

            pom {
                name = "common-jvm"
                description = "iSysCore Common Kotlin Library"
                url = "https://github.com/isyscore/common-jvm"
                packaging = "jar"

                licenses {
                    license {
                        name = "MIT License"
                        url = "https://github.com/isyscore/common-jvm/blob/main/LICENSE"
                    }
                }
                developers {
                    developer {
                        id = "isyscore"
                        name = "isyscore"
                        email = "hexj@isyscore.com"
                    }
                }
                scm {
                    connection = "https://github.com/isyscore/common-jvm"
                    developerConnection =  "https://github.com/isyscore/common-jvm"
                    url = "https://github.com/isyscore/common-jvm"
                }
            }
        }
    }
    repositories {
        maven {
            name = "Release"
            url = "$nexus_release_url"
            credentials {
                username = "$nexus_username"
                password = "$nexus_password"
            }
        }
        maven {
            name = "Snapshot"
            url = "$nexus_snapshot_url"
            credentials {
                username = "$nexus_username"
                password = "$nexus_password"
            }
        }
    }
}

signing {
    sign publishing.publications.mavenKotlin
}

在这里的变动中,主要是必须带入 java 插件,而之前在发布时,如果是纯粹的 Kotlin 项目,则不需要带入 java 插件。而在 Gradle 7.x 下,如果不带 java 插件,则编译后不会有任何 Kotlin 代码被编译到 jar 包内。
然后就是将 maven 插件变更为 maven-publish ,然后将原本的 uploadArchives 任务修改为 publishing 任务。
我们可以发现,新版本的写法和老版本相比,差异不大,主要都是在构建 POM 信息,唯一需要注意的,是签名的位置,Gradle 脚本是“按代码顺序执行”的,因此签名的位置在这里就比较重要,必须写在 publishing 之后。

当然了,在整个迁移的过程中,其实还是发生了不小的麻烦的,最大的困扰其实就是 Maven Central 本身,在 JCenter 跑路后(JCenter 的发布是真的简单),也只有 Maven Central 可以作为可靠的发布平台了。其中的要点有几个:

  1. 必须在 Sonatype 上先注册帐号,并且进行开源项目的认证(最好是Github)
  2. 发布时必须是固定的 IP 地址,如果整个过程中发生了 IP 地址变化,那么发布会失败(这个在家用网络中经常发生,解决方法是使用 VPN,这样你会得到一个固定的 IP)
  3. 耐心是必要的,因为 Maven Central 本身也非常不稳定,经常发生上传了一半服务器拒绝继续提供服务的情况,这不是你的网络问题,也不是你的 VPN 的问题,正是 Maven Central 自己的毛病。所以一次发布可能会伴随着数次的失败,只能靠耐心来解决问题了。

最后再吐个槽,这种如此难用的服务,居然能十年如一日的被用到今天,它不是早就应该被取代的么?为什么死的是 JCenter 😦