Skip to content

Commit 53be396

Browse files
sebersolebeikov
andauthored
HHH-18912 - ORM release process (#9421)
* HHH-18912 - ORM release process --------- Co-authored-by: Christian Beikov <christian.beikov@gmail.com>
1 parent 611fb77 commit 53be396

File tree

4 files changed

+127
-207
lines changed

4 files changed

+127
-207
lines changed

build.gradle

Lines changed: 6 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -42,77 +42,35 @@ apply from: file( 'gradle/module.gradle' )
4242
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4343
// Release Task
4444

45-
task release {
45+
tasks.register('release') {
4646
description = "The task performed when we are performing a release build. Relies on " +
4747
"the fact that subprojects will appropriately define a release task " +
4848
"themselves if they have any release-related activities to perform"
4949

5050
doFirst {
5151
def javaVersionsInUse = jdkVersions.allVersions
52-
if ( javaVersionsInUse != [JavaLanguageVersion.of( 11 )].toSet() ) {
53-
throw new IllegalStateException( "Please use JDK 11 to perform the release. Currently using: ${javaVersionsInUse}" )
52+
if (javaVersionsInUse != [JavaLanguageVersion.of(11)].toSet()) {
53+
throw new IllegalStateException("Please use JDK 11 to perform the release. Currently using: ${javaVersionsInUse}")
5454
}
5555
}
5656
}
5757

58-
task publish {
58+
tasks.register('publish') {
5959
description = "The task performed when we want to just publish maven artifacts. Relies on " +
6060
"the fact that subprojects will appropriately define a release task " +
6161
"themselves if they have any publish-related activities to perform"
6262
}
6363

64-
ext {
65-
if ( project.hasProperty( 'hibernatePublishUsername' ) ) {
66-
if ( ! project.hasProperty( 'hibernatePublishPassword' ) ) {
67-
throw new GradleException( "Should specify both `hibernatePublishUsername` and `hibernatePublishPassword` as project properties" );
68-
}
69-
}
70-
}
71-
7264
nexusPublishing {
7365
repositories {
74-
sonatype {
75-
username = project.hasProperty( 'hibernatePublishUsername' ) ? project.property( 'hibernatePublishUsername' ) : null
76-
password = project.hasProperty( 'hibernatePublishPassword' ) ? project.property( 'hibernatePublishPassword' ) : null
77-
}
66+
sonatype
7867
}
7968
}
8069

81-
gradle.taskGraph.addTaskExecutionGraphListener(
82-
new TaskExecutionGraphListener() {
83-
@Override
84-
void graphPopulated(TaskExecutionGraph graph) {
85-
String[] tasksToLookFor = [
86-
'publish',
87-
'publishToSonatype',
88-
'publishAllPublicationsToSonatype',
89-
'publishPublishedArtifactsPublicationToSonatypeRepository',
90-
'publishRelocationArtifactsPublicationToSonatypeRepository',
91-
]
92-
93-
for ( String taskToLookFor : tasksToLookFor ) {
94-
if ( graph.hasTask( taskToLookFor ) ) {
95-
// trying to publish - make sure the needed credentials are available
96-
97-
if ( project.property( 'hibernatePublishUsername' ) == null ) {
98-
throw new RuntimeException( "`-PhibernatePublishUsername=...` not found" )
99-
}
100-
if ( project.property( 'hibernatePublishPassword' ) == null ) {
101-
throw new RuntimeException( "`-PhibernatePublishPassword=...` not found" )
102-
}
103-
104-
break;
105-
}
106-
}
107-
}
108-
}
109-
)
110-
111-
11270
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11371
// CI Build Task
11472

115-
task ciBuild {
73+
tasks.register('ciBuild') {
11674
description = "The task performed when one of the 'main' jobs are triggered on the " +
11775
"CI server. Just as above, relies on the fact that subprojects will " +
11876
"appropriately define a release task themselves if they have any tasks " +

ci/release/Jenkinsfile

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ pipeline {
9292
stage('Release check') {
9393
steps {
9494
script {
95+
print "INFO: params.RELEASE_VERSION = ${params.RELEASE_VERSION}"
96+
print "INFO: params.DEVELOPMENT_VERSION = ${params.DEVELOPMENT_VERSION}"
97+
print "INFO: params.RELEASE_DRY_RUN? = ${params.RELEASE_DRY_RUN}"
98+
9599
checkoutReleaseScripts()
96100

97101
def currentVersion = Version.parseDevelopmentVersion( sh(
@@ -164,27 +168,20 @@ pipeline {
164168
configFile(fileId: 'release.config.ssh', targetLocation: "${env.HOME}/.ssh/config"),
165169
configFile(fileId: 'release.config.ssh.knownhosts', targetLocation: "${env.HOME}/.ssh/known_hosts")
166170
]) {
167-
withCredentials([
168-
usernamePassword(credentialsId: 'ossrh.sonatype.org', passwordVariable: 'OSSRH_PASSWORD', usernameVariable: 'OSSRH_USER'),
169-
usernamePassword(credentialsId: 'gradle-plugin-portal-api-key', passwordVariable: 'PLUGIN_PORTAL_PASSWORD', usernameVariable: 'PLUGIN_PORTAL_USERNAME'),
170-
file(credentialsId: 'release.gpg.private-key', variable: 'RELEASE_GPG_PRIVATE_KEY_PATH'),
171-
string(credentialsId: 'release.gpg.passphrase', variable: 'RELEASE_GPG_PASSPHRASE')
172-
]) {
173-
sshagent(['ed25519.Hibernate-CI.github.com', 'hibernate.filemgmt.jboss.org', 'hibernate-ci.frs.sourceforge.net']) {
174-
// set release version
175-
// update changelog from JIRA
176-
// tags the version
177-
// changes the version to the provided development version
178-
withEnv([
179-
"BRANCH=${env.GIT_BRANCH}",
180-
"DISABLE_REMOTE_GRADLE_CACHE=true",
181-
// Increase the amount of memory for this part since asciidoctor doc rendering consumes a lot of metaspace
182-
"GRADLE_OPTS=-Dorg.gradle.jvmargs='-Dlog4j2.disableJmx -Xmx4g -XX:MaxMetaspaceSize=768m -XX:+HeapDumpOnOutOfMemoryError -Duser.language=en -Duser.country=US -Duser.timezone=UTC -Dfile.encoding=UTF-8'"
183-
]) {
184-
sh ".release/scripts/prepare-release.sh ${env.PROJECT} ${env.RELEASE_VERSION} ${env.DEVELOPMENT_VERSION}"
185-
}
186-
}
187-
}
171+
sshagent(['ed25519.Hibernate-CI.github.com', 'hibernate.filemgmt.jboss.org', 'hibernate-ci.frs.sourceforge.net']) {
172+
// set release version
173+
// update changelog from JIRA
174+
// tags the version
175+
// changes the version to the provided development version
176+
withEnv([
177+
"BRANCH=${env.GIT_BRANCH}",
178+
"DISABLE_REMOTE_GRADLE_CACHE=true",
179+
// Increase the amount of memory for this part since asciidoctor doc rendering consumes a lot of metaspace
180+
"GRADLE_OPTS=-Dorg.gradle.jvmargs='-Dlog4j2.disableJmx -Xmx4g -XX:MaxMetaspaceSize=768m -XX:+HeapDumpOnOutOfMemoryError -Duser.language=en -Duser.country=US -Duser.timezone=UTC -Dfile.encoding=UTF-8'"
181+
]) {
182+
sh ".release/scripts/prepare-release.sh ${env.PROJECT} ${env.RELEASE_VERSION} ${env.DEVELOPMENT_VERSION}"
183+
}
184+
}
188185
}
189186
}
190187
}
@@ -199,10 +196,12 @@ pipeline {
199196
configFile(fileId: 'release.config.ssh.knownhosts', targetLocation: "${env.HOME}/.ssh/known_hosts")
200197
]) {
201198
withCredentials([
202-
usernamePassword(credentialsId: 'ossrh.sonatype.org', passwordVariable: 'OSSRH_PASSWORD', usernameVariable: 'OSSRH_USER'),
203-
usernamePassword(credentialsId: 'gradle-plugin-portal-api-key', passwordVariable: 'PLUGIN_PORTAL_PASSWORD', usernameVariable: 'PLUGIN_PORTAL_USERNAME'),
204-
file(credentialsId: 'release.gpg.private-key', variable: 'RELEASE_GPG_PRIVATE_KEY_PATH'),
205-
string(credentialsId: 'release.gpg.passphrase', variable: 'RELEASE_GPG_PASSPHRASE'),
199+
// https://github.com/gradle-nexus/publish-plugin#publishing-to-maven-central-via-sonatype-ossrh
200+
usernamePassword(credentialsId: 'ossrh.sonatype.org', passwordVariable: 'ORG_GRADLE_PROJECT_sonatypePassword', usernameVariable: 'ORG_GRADLE_PROJECT_sonatypeUsername'),
201+
// https://docs.gradle.org/current/userguide/publishing_gradle_plugins.html#account_setup
202+
usernamePassword(credentialsId: 'gradle-plugin-portal-api-key', passwordVariable: 'GRADLE_PUBLISH_SECRET', usernameVariable: 'GRADLE_PUBLISH_KEY'),
203+
file(credentialsId: 'release.gpg.private-key', variable: 'SIGNING_GPG_PRIVATE_KEY_PATH'),
204+
string(credentialsId: 'release.gpg.passphrase', variable: 'SIGNING_GPG_PASSPHRASE'),
206205
gitUsernamePassword(credentialsId: 'username-and-token.Hibernate-CI.github.com', gitToolName: 'Default')
207206
]) {
208207
sshagent(['ed25519.Hibernate-CI.github.com', 'hibernate.filemgmt.jboss.org', 'hibernate-ci.frs.sourceforge.net']) {
@@ -264,4 +263,4 @@ pipeline {
264263
}
265264
}
266265
}
267-
}
266+
}

gradle/published-java-module.gradle

Lines changed: 63 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ configurations {
2121
}
2222

2323
dependencies {
24+
// `javadocSources` is a special Configuration which is used as a basis for the aggregated-javadocs we produce
2425
javadocSources sourceSets.main.allJava
2526
}
2627

@@ -29,6 +30,8 @@ dependencies {
2930
// Publishing
3031

3132
java {
33+
// Configure the Java "software component" to include javadoc and sources jars in addition to the classes jar.
34+
// Ultimately, this component is what makes up the publication for this project.
3235
withJavadocJar()
3336
withSourcesJar()
3437
}
@@ -98,130 +101,90 @@ publishing {
98101
}
99102

100103

101-
var signingKey = resolveSigningKey()
102-
var signingPassword = findSigningProperty( "signingPassword" )
103104

104-
signing {
105-
useInMemoryPgpKeys( signingKey, signingPassword )
106105

107-
sign publishing.publications.publishedArtifacts
108-
}
109106

110-
String resolveSigningKey() {
111-
var key = findSigningProperty( "signingKey" )
112-
if ( key != null ) {
113-
return key
114-
}
115107

116-
var keyFile = findSigningProperty( "signingKeyFile" )
117-
if ( keyFile != null ) {
118-
return new File( keyFile ).text
119-
}
108+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
109+
// Signing
110+
111+
def signPublicationsTask = tasks.register('signPublications') {
112+
description "Grouping task which executes all Sign tasks"
120113

121-
return null
114+
dependsOn tasks.withType( Sign )
122115
}
123116

124-
String findSigningProperty(String propName) {
125-
if ( System.getProperty( propName ) != null ) {
126-
logger.debug "Found `{}` as a system property", propName
127-
return System.getProperty(propName )
128-
}
129-
else if ( System.getenv().get( propName ) != null ) {
130-
logger.debug "Found `{}` as an env-var property", propName
131-
return System.getenv().get( propName )
132-
}
133-
else if ( project.hasProperty( propName ) ) {
134-
logger.debug "Found `{}` as a project property", propName
135-
return project.hasProperty( propName )
136-
}
137-
else {
138-
logger.debug "Did not find `{}`", propName
139-
return null
140-
}
117+
tasks.named( "publishPublishedArtifactsPublicationToSonatypeRepository" ) {
118+
// publishing depends on signing
119+
dependsOn signPublicationsTask
141120
}
142121

122+
tasks.register('sign') {
123+
description "Pseudonym for :signPublications"
124+
dependsOn signPublicationsTask
125+
}
143126

144-
var signingTask = project.tasks.getByName( "signPublishedArtifactsPublication" ) as Sign
145127
var signingExtension = project.getExtensions().getByType(SigningExtension) as SigningExtension
146128

147-
task sign {
148-
dependsOn "signPublications"
149-
}
129+
gradle.taskGraph.whenReady { TaskExecutionGraph graph ->
130+
boolean wasSigningRequested = false
131+
boolean wasPublishingRequested = false
132+
133+
graph.allTasks.each {task ->
134+
if ( task instanceof Sign ) {
135+
wasSigningRequested = true
136+
}
137+
else if ( task instanceof PublishToMavenRepository ) {
138+
wasPublishingRequested = true
139+
}
140+
}
150141

151-
task signPublications { t ->
152-
tasks.withType( Sign ).all { s ->
153-
t.dependsOn s
142+
if ( wasPublishingRequested ) {
143+
def ossrhUser = System.getenv().get( "ORG_GRADLE_PROJECT_sonatypeUsername" )
144+
def ossrhPass = System.getenv().get( "ORG_GRADLE_PROJECT_sonatypePassword" )
145+
if ( ossrhUser == null || ossrhPass == null ) {
146+
throw new RuntimeException( "Cannot perform publishing to OSSRH without credentials." )
147+
}
148+
logger.lifecycle "Publishing groupId: '" + project.group + "', version: '" + project.version + "'"
154149
}
155-
}
156150

157-
signingTask.doFirst {
158-
if ( signingKey == null || signingPassword == null ) {
159-
throw new GradleException(
160-
"Cannot perform signing without GPG details. Please set the `signingKey` and `signingKeyFile` properties"
161-
)
151+
if ( wasSigningRequested || wasPublishingRequested ) {
152+
// signing was explicitly requested and/or we are publishing to Sonatype OSSRH
153+
// - we need the signing to happen
154+
signingExtension.required = true
155+
156+
var signingKey = resolveSigningKey()
157+
var signingPassword = resolveSigningPassphrase()
158+
signingExtension.useInMemoryPgpKeys( signingKey, signingPassword )
159+
signingExtension.sign publishing.publications.publishedArtifacts
160+
}
161+
else {
162+
// signing was not explicitly requested and we are not publishing to OSSRH,
163+
// - disable all Sign tasks
164+
tasks.withType( Sign ).each { enabled = false }
162165
}
163166
}
164167

165-
166-
boolean wasSigningExplicitlyRequested() {
167-
// check whether signing task was explicitly requested when running the build
168-
//
169-
// NOTE: due to https://discuss.gradle.org/t/how-to-tell-if-a-task-was-explicitly-asked-for-on-the-command-line/42853/3
170-
// we cannot definitively know whether the task was requested. Gradle really just does not expose this information.
171-
// so we make a convention - we check the "start parameters" object to see which task-names were requested;
172-
// the problem is that these are the raw names directly from the command line. e.g. it is perfectly legal to
173-
// say `gradlew signPubArtPub` in place of `gradlew signPublishedArtifactsPublication` - Gradle will simply
174-
// "expand" the name it finds. However, it does not make that available.
175-
//
176-
// so the convention is that we will check for the following task names
177-
//
178-
// for each of:
179-
// 1. `sign`
180-
// 2. `signPublications`
181-
// 3. `signPublishedArtifactsPublication`
182-
//
183-
// and we check both forms:
184-
// 1. "${taskName}"
185-
// 2. project.path + ":${taskName}"
186-
//
187-
// we need to check both again because of the "start parameters" discussion
188-
189-
def signingTaskNames = ["sign", "signPublications", "signPublishedArtifactsPublication"]
190-
191-
for ( String taskName : signingTaskNames ) {
192-
if ( gradle.startParameter.taskNames.contains( taskName )
193-
|| gradle.startParameter.taskNames.contains( "${project.path}:${taskName}" ) ) {
194-
return true
195-
}
168+
static String resolveSigningKey() {
169+
var key = System.getenv().get( "SIGNING_GPG_PRIVATE_KEY" )
170+
if ( key != null ) {
171+
return key
196172
}
197173

198-
return false
199-
}
174+
var keyFile = System.getenv().get( "SIGNING_GPG_PRIVATE_KEY_PATH" )
175+
if ( keyFile != null ) {
176+
return new File( keyFile ).text
177+
}
200178

201-
if ( wasSigningExplicitlyRequested() ) {
202-
// signing was explicitly requested
203-
signingExtension.required = true
179+
throw new RuntimeException( "Cannot perform signing without GPG details." )
204180
}
205-
else {
206-
gradle.taskGraph.whenReady { graph ->
207-
if ( graph.hasTask( signingTask ) ) {
208-
// signing is scheduled to happen.
209-
//
210-
// we know, from above if-check, that it was not explicitly requested -
211-
// so it is triggered via task dependency. make sure we want it to happen
212-
var publishingTask = project.tasks.getByName( "publishPublishedArtifactsPublicationToSonatypeRepository" ) as PublishToMavenRepository
213-
if ( graph.hasTask( publishingTask ) ) {
214-
// we are publishing to Sonatype OSSRH - we need the signing to happen
215-
signingExtension.required = true
216-
}
217-
else {
218-
// signing was not explicitly requested and we are not publishing to OSSRH,
219-
// so do not sign.
220-
signingTask.enabled = false
221-
}
222-
}
223181

182+
static String resolveSigningPassphrase() {
183+
var passphrase = System.getenv().get( "SIGNING_GPG_PASSPHRASE" )
184+
if ( passphrase == null ) {
185+
throw new RuntimeException( "Cannot perform signing without GPG details." )
224186
}
187+
return passphrase
225188
}
226189

227190

0 commit comments

Comments
 (0)