使用 Gradle 发布 Jar 包到 Maven 中央仓库

# Java  /  Maven  /  Gradle

前端时间成功在中央仓库上传了本人第一个 Artifact,本文结合自己实际操作过程(参考了众多博文),做下记录。

OSSRH:Sonatype Open Source Software Repository Hosting Service,为开源软件提供maven仓库托管服务。可以在上面部署snapshot、release等,最后可以申请把你的release同步到Maven Central Repository(Maven中央仓库)。

猜测,Central OSSRH是Maven中央仓库的前置审批仓库,只有完全符合了发布要求,成功的将的项目发布到了OSSRH,才有机会申请同步到Maven中央仓库。

1.Sonatype JIRA

1.1 注册

地址:https://issues.sonatype.org/ ,需要先注册一个账号,很重要记好了。

1.2 创建 Issue

Create Issue表单中填入申请信息:

  • Project:Community Support - Open Source Project Repository Hosting (OSSRH)
  • Issue Type:New Project
  • Summary:简单写个标题
  • Group Id:可以使用自己拥有的子域名(会审核验证)

    没有域名的,可以使用 github 的方式

  • Project URL:项目地址,此处我写的是开源项目访问地址
  • SCM url:版本仓库拉取地址
  • Already Synced to Central:默认No

我的第一个issue地址:https://issues.sonatype.org/browse/OSSRH-50547
参考一个网友的issue:https://issues.sonatype.org/browse/OSSRH-46951

1.3 等待审核回复

存在的问题,审核者会在jira中指出(有邮件提醒),我们可以直接回复需要的资料或者回答(跟工作使用的jira没什么两样)。

响应速度还是很快的,我在申请时,按照要求配置了一个 TXT 类型的域名解析记录。

当出现类似以下回复的时候,说明初步的审核已经搞定了。

central-ossrh Central OSSRH 添加了评论 -  
com.sherlocky has been prepared, now user(s) sherlock 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  

2.GPG 加密

OSSRH 对提交的文件有严格的要求,

example-1.0.0.pom  
example-1.0.0.pom.asc  
example-1.0.0.jar  
example-1.0.0.jar.asc  
example-1.0.0-sources.jar  
example-1.0.0-sources.jar.asc  
example-1.0.0-javadoc.jar  
example-1.0.0-javadoc.jar.asc  

除了jar包和pom文件,Javadoc和Sources也是必须的,且每个文件都要有一个对应的asc文件(GPG签名文件,用于校验文件)。

2.1 GPG 安装

我使用的win7,安装的是gpg4win,下载时跳过捐款即可,或者直接在gpg4win FTP下载。

安装成功以后,就可以在命令行中使用gpg命令了。

2.2 公钥、私钥、签名

GPG 的默认秘钥类型是RSA——非对称加密。

  • 公钥(public-key)和私钥(secret-key)是成对的。
  • 公钥加密,私钥解密。
  • 私钥签名,公钥验证。

2.3 新建一个密钥

生成了密钥以后,才能导出公钥、私钥

gpg --gen-key  

创建的时候,会提示输入密码,记好了,后面会用到。

2.4 查看已经生成的密钥

gpg --list-keys

C:/Users/Administrator/AppData/Roaming/gnupg/pubring.kbx  
--------------------------------------------------------
pub   rsa2048 2019-08-06 [SC] [expires: 2029-08-05]  
      292197497942CADF1CDD421044482227A2A62714
uid           [ultimate] xxx <yyy@126.com>  
sub   rsa2048 2019-08-06 [E] [expires: 2021-08-05]  

292197497942CADF1CDD421044482227A2A62714是:密钥指纹
后面8位A2A62714是:KEY ID,后面给jar包签名会用到。

密钥默认有效期是1年,此处是我手动在Kleopatra中修改的。

2.5 导出私钥文件

gpg --export-secret-keys 44482227A2A62714 > secret.gpg  

会生成一个二进制的私钥文件,后面需要配置到gradle中,给文件批量签名。

2.6 上传公钥到公钥服务器

gpg --keyserver hkp://keyserver.ubuntu.com --send-keys 44482227A2A62714  

sonatype 会去以下服务器拉取公钥,所以都是可选的:
keys.gnupg.net
pool.sks-keyservers.net
keyserver.ubuntu.com

2.7 关于证书的撤销

提前生成一张"撤销证书",以备以后密钥作废时,可以请求外部的公钥服务器撤销你的公钥

gpg --gen-revoke 44482227A2A62714  

3.Gradle 配置上传jar

附上build.gradle

plugins {  
    id 'java'
    /** 可对外暴露 api dependencies */
    id 'java-library'
    id 'maven-publish'
    id 'signing'
}

group 'com.xxx'  
version app_version

[compileJava, compileTestJava, javadoc]*.options*.encoding = 'UTF-8'
sourceCompatibility = 1.8  
targetCompatibility = 1.8

repositories {  
    maven {
        url maven_url
    }
}

dependencies {  
    api 'org.slf4j:slf4j-api:1.7.26'
    api 'org.apache.commons:commons-lang3:3.9'
    api 'org.apache.commons:commons-collections4:4.4'
    api 'commons-codec:commons-codec:1.12'
    api 'commons-io:commons-io:2.6'
    api 'com.alibaba:fastjson:1.2.58'
    api 'org.hashids:hashids:1.0.3'

    compileOnly 'javax.servlet:javax.servlet-api:3.1.0'
    compileOnly 'org.projectlombok:lombok:1.18.8'
    annotationProcessor 'org.projectlombok:lombok:1.18.8'

    testImplementation 'junit:junit:4.12'
}

task sourcesJar(type: Jar) {  
    from sourceSets.main.allJava
    classifier = 'sources'
}

task javadocJar(type: Jar) {  
    from javadoc
    classifier = 'javadoc'
}

javadoc {  
    description = "生成jar格式的javadoc。"
    // 只显示 protected 和 public 的类和成员
    options.memberLevel = org.gradle.external.javadoc.JavadocMemberLevel.PROTECTED
    options.author = true
    options.version = true
    options.header = project.name
    // 静默javadoc检查(比如不支持@date会报错等),jdk 8+
    options.addStringOption('Xdoclint:none', '-quiet')
    /**
     * <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
     * 防止本地打开中文乱码
     */
    options.addStringOption("charset", "UTF-8")
    // suppress warnings due to cross-module @see and @link references;
    // note that global 'api' task does display all warnings.
    logging.captureStandardError LogLevel.INFO
    // suppress "## warnings" message
    logging.captureStandardOutput LogLevel.INFO
    // 编码一定要配置否则直接出错
    options.encoding = "UTF-8"
    options.charSet = "UTF-8"
}

publishing {  
    publications {
        mavenJava(MavenPublication) {
            /** 默认使用项目的group/name/version信息 */
            /**
             groupId = 'com.xxx'
             artifactId = 'yyy'
             version = '0.0.1'
             */
            /**
             * 如果是war包填写components.web,
             * 如果是jar包填写components.java,
             * 不过该方法没有manifest信息(会自动附带pom依赖信息)
             */
            from components.java
            artifact sourcesJar
            artifact javadocJar
            pom {
                name = 'yyy'
                description = 'xxx...'
                url = 'https://github.com/xxx/yyy'
                licenses {
                    license {
                        name = 'Apache License, Version 2.0'
                        url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                        distribution = 'repo'
                        comments = 'A business-friendly OSS license'
                    }
                }
                developers {
                    developer {
                        id = 'xx'
                        name = 'xx'
                        //email = 'xxx@126.com'
                        roles = ['Java Developer']
                    }
                }
                scm {
                    url = 'https://github.com/xxx/yyy'
                    connection = 'scm:git:https://git@github.com/xxx/yyy.git'
                    developerConnection = 'scm:git:git@github.com:xxx/yyy.git'
                }
            }
        }
    }

    // 发布到oss sonatype,非SNAPSHOT版必须GPG签名
    repositories {
        maven {
            name = 'oss'
            url = oss_sonatype_maven_url
            credentials {
                username oss_sonatype_maven_username
                password oss_sonatype_maven_password
            }
        }
        /** oss snapshot 仓库,必须携带 -SNAPSHOT 后缀
        maven {
            name = 'oss-snapshot'
            url = oss_sonatype_snapshot_maven_url
            credentials {
                username = oss_sonatype_maven_username
                password = oss_sonatype_maven_password
            }
        }
        */
    }

    /** 发布到自建maven仓库,无需签名
    repositories {
        maven {
            url = xxx_maven_url
            credentials {
                username xxx_maven_username
                password xxx_maven_password
            }
        }
    }
    */

    /**
     * GPG 签名jar包配置,注意顺序,必须在 publishing 配置之后
     * (因为使用了 publishing 中定义的 mavenJava)
     */
    signing {
        sign publishing.publications.mavenJava
    }
}

对应的 gradle.properties

app_version=0.0.1

# 使用阿里云 Maven仓库
## central仓和jcenter仓的聚合仓
maven_url=https://maven.aliyun.com/repository/public

##############################################################
### 以下配置可以在本地全局配置文件中配置(保密需要)
##############################################################
### maven官方仓库上传地址
oss_sonatype_maven_url=  
oss_sonatype_snapshot_maven_url=  
oss_sonatype_maven_username=  
oss_sonatype_maven_password=

### GPG signing
signing.keyId=密钥id(密钥指纹末八位)  
signing.password=密钥密码  
signing.secretKeyRingFile=前文导出的私钥文件secret.gpg  

4.Gradle发布jar包到OSS仓库

先发布到本地仓库,测试jar构建是否正常:gradle publishMavenJavaPublicationToMavenLocal 本地构建ok后,再发布到OSS仓库:gradle publishMavenJavaPublicationToOssRepository

具体的 gradle 任务名称和 publishing>publications>下maven任务名有关。

5.推送到中央仓库

第4步的推送完成后,jar包会在https://oss.sonatype.org/#stagingRepositories中,需要登录OSS,进行一番操作方可真正推送到maven中央仓库。

  • 1.进入OSS后,点击Staging Repositories
  • 2.在最下方找到构件(或者在搜索栏输入你的 groupId)。
  • 3.勾选构件并点击Tab栏的Close
  • 4.Close完成后,点击 tab 栏的Release

    CloseRelease操作如果失败了,可以点击对应的Activity标签查看具体执行过程,查找错误信息。

  • 5.通知 Sonatype 的工作人员关闭 issue。(仅第一次) ,我操作的时候没有这一步,直接看到结果了。

central-ossrh Central OSSRH 添加了评论 - 08/06/19 05:19 下午  
Central sync is activated for com.sherlocky. After you successfully release, your component will be published to Central, typically within 10 minutes, though updates to search.maven.org can take up to two hours.  

等待审批通过后,就可以在中央仓库中搜索到自己发布的构件了!
一般10分钟就可以看到发布的结果,但是搜索结果的更新至少两个小时。

附上一些个人发布成功后的地址:
https://oss.sonatype.org/content/groups/public/com/sherlocky/sherlocky-commons/  
https://mvnrepository.com/artifact/com.sherlocky/sherlocky-commons  
https://repo1.maven.org/maven2/com/sherlocky/sherlocky-commons/  

6.暂未解决

暂时没有找到给 artifact 添加图标(logo)的找到有效的办法。


参考:

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×