发布Jar到Maven中央仓库--Gradle版

摘要

一、将项目推送到远程仓库,如 Github或者Gitee

二、注册 Sonatype 账户 – 就是一个JIRA

三、登录 Sonatype 创建工单–每部署一个新项目就创建一个工单

前三个步骤与 发布Jar到Maven中央仓库--Maven版 相同,不在赘述。

四、发布

  • 1.签名
    我是mac电脑,于是签名工具使用的是https://gpgtools.org,gradle签名时需要使用到.gpg证书文件,这个工具不支持直接导出.gpg,其导出的证书文件是.asc格式的,asc其实就是字符串,可以用记事本打开查看。

    使用如下命令导出.gpg格式的私钥证书:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    # qunfeng_han@126.com是创建证书时使用的邮箱,会要求你输入创建证书时的密码
    gpg --export-secret-keys qunfeng_han@126.com > secret.gpg

    # 也可以使用创建证书的用户名,会要求你输入创建证书时的密码
    gpg --export-secret-keys hanqunfeng > secret.gpg
    # 导出私钥明文
    gpg --export-secret-keys --armor hanqunfeng > secret.asc

    # 列出当前全部证书
    gpg -k

    # 导出公钥
    gpg --export hanqunfeng > public.gpg
    # 导出公钥明文
    gpg --export --armor hanqunfeng > public.asc

    # 导入公钥或私钥,区别就是导入公钥不需要创建证书的密码
    gpg --import public.gpg
    gpg --import --armor secret.asc

    也可以使用windows系统下载的https://www.gpg4win.org/Kleopatra,将gpgtools导出的证书(勾选密码才是私钥证书,看生成文件的名称就可以,公开就是公钥,私密就是私钥)导入到Kleopatra中,然后右键选择–>Backup secret keys,记得后缀一定是.gpg,该工具支持三种格式,ascgpgpgp,默认也是acs,手工将文件后缀修改为.gpg即可。

    也可以重新生成了一个密钥对,打开软件,菜单–>文件–>新建密钥对–>创建个人penPGP密钥对,创建好后记得点击保存密钥副本,以导出.gpg证书文件,该工具支持三种格式,ascgpgpgp,默认也是acs,手工将文件后缀修改为gpg即可,如果此时忘记点击保留副本,也可以在证书列表页右键选择–>Backup secret keys,记得后缀一定是gpg

  • build.gradle
    重点还是io.codearte.nexus-staging这个自动发布插件,不需要手工操作oss-sonatype的UI进行发布。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186

plugins {
id 'io.spring.dependency-management' version '1.0.10.RELEASE'
//此处必须是java-library,如果是java则api方法不可用,api可以理解为就是compile,支持传递依赖
id 'java-library'
//发布插件
id 'maven-publish'
//签名插件
id 'signing'
//自动发布到maven中央仓库插件
//https://github.com/Codearte/gradle-nexus-staging-plugin
id 'io.codearte.nexus-staging' version '0.22.0'
}

group = 'com.hanqunfeng'
//SNAPSHOT版本是不支持发布到Maven中央仓库
version = '1.0.3'
sourceCompatibility = '1.8'



java {
withJavadocJar()
withSourcesJar()
}

repositories {
maven { url 'https://maven.aliyun.com/repository/public/' }
mavenLocal()
mavenCentral()
}

dependencyManagement {
imports { mavenBom("org.springframework.boot:spring-boot-dependencies:2.4.0") }
}

dependencies {
//lombok
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'

//如果不希望传递依赖,则使用implementation,传递依赖则使用compile或者api,gradle7后将不再支持compile
//注解相关
api 'org.springframework.boot:spring-boot-autoconfigure'
api 'org.springframework.boot:spring-boot-configuration-processor'

//json-jackson
api 'com.fasterxml.jackson.core:jackson-databind'
api 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8'
api 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'

//@Aspect
api 'org.aspectj:aspectjweaver'

//Mono Flux
api 'io.projectreactor:reactor-core'

//redis-template
api 'org.springframework.data:spring-data-redis'

}

test {
useJUnitPlatform()
}

// java编译的时候缺省状态下会因为中文字符而失败
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'


/**
* 发布插件
* 参考:https://docs.gradle.org/6.6.1/userguide/publishing_maven.html#publishing_maven:resolved_dependencies
*/
publishing {
publications {
mavenJava(MavenPublication) {
groupId = project.group
artifactId = project.name
version = project.version
//如果不定义,则会按照以上默认值执行

from components.java

pom {
name = 'redis-cache-annotation-reactive'
description = 'redis cache function annotation for webflux'
url = 'https://blog.hanqunfeng.com'
licenses {
license {
name = 'The Apache License, Version 2.0'
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
developers {
developer {
id = 'hanqf'
name = 'han qunfeng'
email = 'qunfeng_han@126.com'
}
}
scm {
connection = 'scm:git:https://github.com/hanqunfeng/reactive-redis-cache-annotation-spring-boot-starter.git'
developerConnection = 'scm:git:https://github.com:hanqunfeng/reactive-redis-cache-annotation-spring-boot-starter.git'
url = 'https://github.com/hanqunfeng/reactive-redis-cache-annotation-spring-boot-starter'
}
}

versionMapping {
usage('java-api') {
fromResolutionOf('runtimeClasspath')
}
usage('java-runtime') {
fromResolutionResult()
}
}
}
}
repositories {
maven {
// 发布仓库配置,这里基于version后缀是否为SNAPSHOT来区分发布到release库还是snapshots库
// def releasesRepoUrl = "http://nexus.cxzh.ltd:8081/repository/maven-releases/"
// def snapshotsRepoUrl = "http://nexus.cxzh.ltd:8081/repository/maven-snapshots/"

def releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
def snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots/"
url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl

//认证用户和密码,在配置文件gradle.properties中配置
//oss-sonatype的登录用户名和密码
credentials {
username nexusUser
password nexusPassword
}
}
}
}

tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}

//javadoc,如果用jdk11,默认就支持中文
//查看可以配置的属性:https://docs.gradle.org/current/javadoc/org/gradle/external/javadoc/StandardJavadocDocletOptions.html
tasks.withType(Javadoc) {
options.version = true
options.author = true
options.encoding = "UTF-8"
options.charSet = "UTF-8" //解决中文乱码
}


javadoc {
if(JavaVersion.current().isJava9Compatible()) {
options.addBooleanOption('html5', true)
}

if (JavaVersion.current().isJava8Compatible()) {
tasks.withType(Javadoc) {
// disable the crazy super-strict doclint tool in Java 8
// noinspection SpellCheckingInspection
options.addStringOption('Xdoclint:none', '-quiet')
}
}
}

//签名,发布时会先执行签名
//参考:https://docs.gradle.org/current/userguide/signing_plugin.html
signing {
sign publishing.publications.mavenJava
}

//自动发布到maven中央仓库插件的配置信息
//参考:https://github.com/Codearte/gradle-nexus-staging-plugin
nexusStaging {
//oss-sonatype的登录用户名和密码
username nexusUser
password nexusPassword
//重试次数,默认是60次
numberOfRetries 10
//每次重试的间隔时间,单位毫秒,默认2000,按照官网的说明,执行发布时有延迟,需要等待响应,所以建议调整间隔时间,可以减少重试次数,我这里间隔20秒,大约重试1~2次即可完成
delayBetweenRetriesInMillis 20000
// packageGroup = "com.hanqunfeng" //optional if packageGroup == project.getGroup()
// stagingProfileId = "yourStagingProfileId" //when not defined will be got from server using "packageGroup"
}

  • gradle.properties

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#gradle -PnexusUser=developer -PnexusPassword=developer clean publish
# 注意参数要放到命令前面
# 这里替换为自己的oss-sonatype的用户名和密码
nexusUser=developer
nexusPassword=developer

#Disable maven-metadata.xml SHA256 and SHA512 upload warnings to Nexus
#参考:https://github.com/gradle/gradle/issues/12355
systemProp.org.gradle.internal.publish.checksums.insecure=true

#签名信息。或者执行命令时携带参数,如:gradle -Psigning.secretKeyRingFile=/SECRET.gpg -Psigning.password=xxxxxxxx -Psigning.keyId=xxxxxxxx clean publish
# 这里替换自己的签名信息
signing.keyId=xxxxxxxx
signing.password=xxxxxxxx
signing.secretKeyRingFile=/SECRET.gpg
  • 执行命令

1
2
./gradlew clean publish closeAndReleaseRepository # 部署到maven中央仓库,参数都配置在gradle.properties中
./gradlew -PnexusUser=developer -PnexusPassword=developer -Psigning.secretKeyRingFile=/SECRET.gpg -Psigning.password=xxxxxxxx -Psigning.keyId=xxxxxxxx clean publish closeAndReleaseRepository # 命令行携带参数