diff --git a/ci/release/Jenkinsfile b/ci/release/Jenkinsfile index 0f352c451a13..316fa42b4076 100644 --- a/ci/release/Jenkinsfile +++ b/ci/release/Jenkinsfile @@ -53,8 +53,6 @@ def checkoutReleaseScripts() { } } -File findReleaseNotes() { -} // -------------------------------------------- // Pipeline @@ -95,6 +93,10 @@ pipeline { stage('Release check') { steps { script { + print "INFO: params.RELEASE_VERSION = ${params.RELEASE_VERSION}" + print "INFO: params.DEVELOPMENT_VERSION = ${params.DEVELOPMENT_VERSION}" + print "INFO: params.RELEASE_DRY_RUN? = ${params.RELEASE_DRY_RUN}" + checkoutReleaseScripts() def currentVersion = Version.parseDevelopmentVersion( sh( @@ -152,7 +154,7 @@ pipeline { env.DEVELOPMENT_VERSION = developmentVersion.toString() if ( params.RELEASE_DRY_RUN ) { - env.SCRIPT_OPTIONS += " -d" + env.SCRIPT_OPTIONS += "-d" } // Determine version id to check if Jira version exists @@ -169,27 +171,20 @@ pipeline { configFile(fileId: 'release.config.ssh', targetLocation: "${env.HOME}/.ssh/config"), configFile(fileId: 'release.config.ssh.knownhosts', targetLocation: "${env.HOME}/.ssh/known_hosts") ]) { - withCredentials([ - usernamePassword(credentialsId: 'ossrh.sonatype.org', passwordVariable: 'OSSRH_PASSWORD', usernameVariable: 'OSSRH_USER'), - usernamePassword(credentialsId: 'gradle-plugin-portal-api-key', passwordVariable: 'PLUGIN_PORTAL_PASSWORD', usernameVariable: 'PLUGIN_PORTAL_USERNAME'), - file(credentialsId: 'release.gpg.private-key', variable: 'RELEASE_GPG_PRIVATE_KEY_PATH'), - string(credentialsId: 'release.gpg.passphrase', variable: 'RELEASE_GPG_PASSPHRASE') - ]) { - sshagent(['ed25519.Hibernate-CI.github.com', 'hibernate.filemgmt.jboss.org', 'hibernate-ci.frs.sourceforge.net']) { - // set release version - // update changelog from JIRA - // tags the version - // changes the version to the provided development version - withEnv([ - "BRANCH=${env.GIT_BRANCH}", - "DISABLE_REMOTE_GRADLE_CACHE=true", - // Increase the amount of memory for this part since asciidoctor doc rendering consumes a lot of metaspace - "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'" - ]) { - sh ".release/scripts/prepare-release.sh ${env.PROJECT} ${env.RELEASE_VERSION} ${env.DEVELOPMENT_VERSION}" - } - } - } + sshagent(['ed25519.Hibernate-CI.github.com', 'hibernate.filemgmt.jboss.org', 'hibernate-ci.frs.sourceforge.net']) { + // set release version + // update changelog from JIRA + // tags the version + // changes the version to the provided development version + withEnv([ + "BRANCH=${env.GIT_BRANCH}", + "DISABLE_REMOTE_GRADLE_CACHE=true", + // Increase the amount of memory for this part since asciidoctor doc rendering consumes a lot of metaspace + "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'" + ]) { + sh ".release/scripts/prepare-release.sh ${env.PROJECT} ${env.RELEASE_VERSION} ${env.DEVELOPMENT_VERSION}" + } + } } } } @@ -204,10 +199,12 @@ pipeline { configFile(fileId: 'release.config.ssh.knownhosts', targetLocation: "${env.HOME}/.ssh/known_hosts") ]) { withCredentials([ - usernamePassword(credentialsId: 'ossrh.sonatype.org', passwordVariable: 'OSSRH_PASSWORD', usernameVariable: 'OSSRH_USER'), - usernamePassword(credentialsId: 'gradle-plugin-portal-api-key', passwordVariable: 'PLUGIN_PORTAL_PASSWORD', usernameVariable: 'PLUGIN_PORTAL_USERNAME'), - file(credentialsId: 'release.gpg.private-key', variable: 'RELEASE_GPG_PRIVATE_KEY_PATH'), - string(credentialsId: 'release.gpg.passphrase', variable: 'RELEASE_GPG_PASSPHRASE'), + // https://github.com/gradle-nexus/publish-plugin#publishing-to-maven-central-via-sonatype-ossrh + usernamePassword(credentialsId: 'ossrh.sonatype.org', passwordVariable: 'ORG_GRADLE_PROJECT_sonatypePassword', usernameVariable: 'ORG_GRADLE_PROJECT_sonatypeUsername'), + // https://docs.gradle.org/current/userguide/publishing_gradle_plugins.html#account_setup + usernamePassword(credentialsId: 'gradle-plugin-portal-api-key', passwordVariable: 'GRADLE_PUBLISH_SECRET', usernameVariable: 'GRADLE_PUBLISH_KEY'), + file(credentialsId: 'release.gpg.private-key', variable: 'SIGNING_GPG_PRIVATE_KEY_PATH'), + string(credentialsId: 'release.gpg.passphrase', variable: 'SIGNING_GPG_PASSPHRASE') gitUsernamePassword(credentialsId: 'username-and-token.Hibernate-CI.github.com', gitToolName: 'Default') ]) { sshagent(['ed25519.Hibernate-CI.github.com', 'hibernate.filemgmt.jboss.org', 'hibernate-ci.frs.sourceforge.net']) { @@ -216,7 +213,7 @@ pipeline { withEnv([ "DISABLE_REMOTE_GRADLE_CACHE=true" ]) { - sh ".release/scripts/publish.sh ${env.PROJECT} ${env.RELEASE_VERSION} ${env.DEVELOPMENT_VERSION} ${env.GIT_BRANCH} ${env.SCRIPT_OPTIONS}" + sh ".release/scripts/publish.sh ${env.SCRIPT_OPTIONS} ${env.PROJECT} ${env.RELEASE_VERSION} ${env.DEVELOPMENT_VERSION} ${env.GIT_BRANCH}" } } } @@ -243,7 +240,7 @@ pipeline { extensions: [], userRemoteConfigs: [[credentialsId: 'ed25519.Hibernate-CI.github.com', url: 'https://github.com/hibernate/hibernate.org.git']] ) - sh "../scripts/website-release.sh ${env.PROJECT} ${env.RELEASE_VERSION} ${env.SCRIPT_OPTIONS} " + sh "../scripts/website-release.sh ${env.SCRIPT_OPTIONS} ${env.PROJECT} ${env.RELEASE_VERSION}" } } } diff --git a/gradle/published-java-module.gradle b/gradle/published-java-module.gradle index 2f9b30b0828e..7226569a64c5 100644 --- a/gradle/published-java-module.gradle +++ b/gradle/published-java-module.gradle @@ -24,155 +24,107 @@ dependencies { javadocSources sourceSets.main.allJava } +java { + // Configure the Java "software component" to include javadoc and sources jars in addition to the classes jar. + // Ultimately, this component is what makes up the publication for this project. + withJavadocJar() + withSourcesJar() +} + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Publishing -publishing { - publications { - // main publication - publishedArtifacts { - // Add the Java component to the main publication - from components.java - } +var publishingExtension = project.getExtensions().getByType(PublishingExtension) as PublishingExtension +publishingExtension.publications { + // main publication + publishedArtifacts { + // Add the Java component to the main publication + from components.java } } -java { - // include javadoc and sources jar in the Java component - // - classes jar included by default - withJavadocJar() - withSourcesJar() -} -var signingKey = resolveSigningKey() -var signingPassword = findSigningProperty( "RELEASE_GPG_PASSPHRASE" ) +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Signing -signing { - useInMemoryPgpKeys( signingKey, signingPassword ) +def signPublicationsTask = tasks.register('signPublications') { + description "Grouping task which executes all Sign tasks" - sign publishing.publications.publishedArtifacts + dependsOn tasks.withType( Sign ) } -String resolveSigningKey() { - var key = findSigningProperty( "RELEASE_GPG_PRIVATE_KEY" ) - if ( key != null ) { - return key - } - - var keyFile = findSigningProperty( "RELEASE_GPG_PRIVATE_KEY_PATH" ) - if ( keyFile != null ) { - return new File( keyFile ).text - } +tasks.named( "publishPublishedArtifactsPublicationToSonatypeRepository" ) { + // publishing depends on signing + dependsOn signPublicationsTask +} - return null +tasks.register('sign') { + description "Pseudonym for :signPublications" + dependsOn signPublicationsTask } -String findSigningProperty(String propName) { - def sysProp = System.getProperty(propName) - if ( sysProp != null ) { - logger.debug "Found `{}` as a system property", propName - return sysProp - } +var signingExtension = project.getExtensions().getByType(SigningExtension) as SigningExtension - def envVar = System.getenv().get(propName) - if ( envVar != null ) { - logger.debug "Found `{}` as an env-var property", propName - return envVar - } +gradle.taskGraph.whenReady { TaskExecutionGraph graph -> + boolean wasSigningRequested = false + boolean wasPublishingRequested = false - def projectProp = project.hasProperty(propName) - if (projectProp) { - logger.debug "Found `{}` as a project property", propName - return projectProp + graph.allTasks.each {task -> + if ( task instanceof Sign ) { + wasSigningRequested = true + } + else if ( task instanceof PublishToMavenRepository ) { + wasPublishingRequested = true + } } - logger.debug "Did not find `{}`", propName - return null -} - - -var signingTask = project.tasks.getByName( "signPublishedArtifactsPublication" ) as Sign -var signingExtension = project.getExtensions().getByType(SigningExtension) as SigningExtension + if ( wasPublishingRequested ) { + def ossrhUser = System.getenv().get( "ORG_GRADLE_PROJECT_sonatypeUsername" ) + def ossrhPass = System.getenv().get( "ORG_GRADLE_PROJECT_sonatypePassword" ) + if ( ossrhUser == null || ossrhPass == null ) { + throw new RuntimeException( "Cannot perform publishing to OSSRH without credentials." ) + } + logger.lifecycle "Publishing groupId: '" + project.group + "', version: '" + project.version + "'" + } -task sign { - dependsOn "signPublications" -} + if ( wasSigningRequested || wasPublishingRequested ) { + // signing was explicitly requested and/or we are publishing to Sonatype OSSRH + // - we need the signing to happen + signingExtension.required = true -task signPublications { t -> - tasks.withType( Sign ).all { s -> - t.dependsOn s + var signingKey = resolveSigningKey() + var signingPassword = resolveSigningPassphrase() + signingExtension.useInMemoryPgpKeys( signingKey, signingPassword ) + signingExtension.sign publishing.publications.publishedArtifacts } -} - -signingTask.doFirst { - if ( signingKey == null || signingPassword == null ) { - throw new GradleException( - "Cannot perform signing without GPG details. Please set the `signingKey` and `signingKeyFile` properties" - ) + else { + // signing was not explicitly requested and we are not publishing to OSSRH, + // - disable all Sign tasks + tasks.withType( Sign ).each { enabled = false } } } - -boolean wasSigningExplicitlyRequested() { - // check whether signing task was explicitly requested when running the build - // - // NOTE: due to https://discuss.gradle.org/t/how-to-tell-if-a-task-was-explicitly-asked-for-on-the-command-line/42853/3 - // we cannot definitively know whether the task was requested. Gradle really just does not expose this information. - // so we make a convention - we check the "start parameters" object to see which task-names were requested; - // the problem is that these are the raw names directly from the command line. e.g. it is perfectly legal to - // say `gradlew signPubArtPub` in place of `gradlew signPublishedArtifactsPublication` - Gradle will simply - // "expand" the name it finds. However, it does not make that available. - // - // so the convention is that we will check for the following task names - // - // for each of: - // 1. `sign` - // 2. `signPublications` - // 3. `signPublishedArtifactsPublication` - // - // and we check both forms: - // 1. "${taskName}" - // 2. project.path + ":${taskName}" - // - // we need to check both again because of the "start parameters" discussion - - def signingTaskNames = ["sign", "signPublications", "signPublishedArtifactsPublication"] - - for ( String taskName : signingTaskNames ) { - if ( gradle.startParameter.taskNames.contains( taskName ) - || gradle.startParameter.taskNames.contains( "${project.path}:${taskName}" ) ) { - return true - } +static String resolveSigningKey() { + var key = System.getenv().get( "SIGNING_GPG_PRIVATE_KEY" ) + if ( key != null ) { + return key } - return false -} + var keyFile = System.getenv().get( "SIGNING_GPG_PRIVATE_KEY_PATH" ) + if ( keyFile != null ) { + return new File( keyFile ).text + } -if ( wasSigningExplicitlyRequested() ) { - // signing was explicitly requested - signingExtension.required = true + throw new RuntimeException( "Cannot perform signing without GPG details." ) } -else { - gradle.taskGraph.whenReady { graph -> - if ( graph.hasTask( signingTask ) ) { - // signing is scheduled to happen. - // - // we know, from above if-check, that it was not explicitly requested - - // so it is triggered via task dependency. make sure we want it to happen - var publishingTask = project.tasks.getByName( "publishPublishedArtifactsPublicationToSonatypeRepository" ) as PublishToMavenRepository - if ( graph.hasTask( publishingTask ) ) { - // we are publishing to Sonatype OSSRH - we need the signing to happen - signingExtension.required = true - } - else { - // signing was not explicitly requested and we are not publishing to OSSRH, - // so do not sign. - signingTask.enabled = false - } - } +static String resolveSigningPassphrase() { + var passphrase = System.getenv().get( "SIGNING_GPG_PASSPHRASE" ) + if ( passphrase == null ) { + throw new RuntimeException( "Cannot perform signing without GPG details." ) } + return passphrase } diff --git a/tooling/hibernate-gradle-plugin/hibernate-gradle-plugin.gradle b/tooling/hibernate-gradle-plugin/hibernate-gradle-plugin.gradle index f1717e50568e..7b8edd11aab5 100644 --- a/tooling/hibernate-gradle-plugin/hibernate-gradle-plugin.gradle +++ b/tooling/hibernate-gradle-plugin/hibernate-gradle-plugin.gradle @@ -63,7 +63,7 @@ tasks.withType(AbstractArchiveTask).configureEach { test { useJUnitPlatform() if ( project.hasProperty( 'excludeTests' ) ) { - exclude project.property( 'excludeTests' ) + exclude project.property( 'excludeTests' ) as String } } @@ -107,14 +107,14 @@ processResources { filter( ReplaceTokens, tokens: [ 'hibernateVersion': getVersion() ] ) } -tasks.withType( JavaCompile ) { +tasks.withType(JavaCompile).configureEach { options.encoding = 'UTF-8' } if ( !jdkVersions.explicit ) { - tasks.withType( GroovyCompile ) { - sourceCompatibility = JavaVersion.toVersion( jdkVersions.baseline ) - targetCompatibility = JavaVersion.toVersion( jdkVersions.baseline ) + tasks.withType(GroovyCompile).configureEach { + sourceCompatibility = JavaVersion.toVersion(jdkVersions.baseline) + targetCompatibility = JavaVersion.toVersion(jdkVersions.baseline) } } else { @@ -133,20 +133,25 @@ tasks.publish.enabled !project.ormVersion.isSnapshot tasks.publishPlugins.enabled !project.ormVersion.isSnapshot gradle.taskGraph.whenReady { tg -> - if ( tg.hasTask( project.tasks.publishPlugins ) && project.tasks.publishPlugins.enabled ) { - // look for sys-prop or env-var overrides of the tokens used for publishing - if ( project.properties.containsKey( 'gradle.publish.key' ) - || project.properties.containsKey( 'gradle.publish.secret' ) ) { - // nothing to do - already explicitly set - } - else { - // use the values from the credentials provider, if any - if ( project.property( 'gradle.publish.key' ) == null ) { - throw new RuntimeException( "`-Pgradle.publish.key=...` not found" ) + // verify credentials for publishing the plugin up front to avoid any work (only if we are publishing) + if ( tg.hasTask( ":publishPlugins" ) && project.tasks.publishPlugins.enabled ) { + // we are publishing the plugin - make sure there is a credentials pair + // + // first, check the `GRADLE_PUBLISH_KEY` / `GRADLE_PUBLISH_SECRET` combo (env vars) + // and then the `gradle.publish.key` / `gradle.publish.secret` combo (project prop) + // - see https://docs.gradle.org/current/userguide/publishing_gradle_plugins.html#account_setup + if ( System.getenv().get("GRADLE_PUBLISH_KEY") != null ) { + if ( System.getenv().get("GRADLE_PUBLISH_SECRET") != null ) { + throw new RuntimeException( "`GRADLE_PUBLISH_KEY` specified, but not `GRADLE_PUBLISH_SECRET` for publishing Gradle plugin" ) } - if ( project.property( 'gradle.publish.secret' ) == null ) { - throw new RuntimeException( "`-Pgradle.publish.secret=...` not found" ) + } + else if ( project.findProperty( 'gradle.publish.key' ) != null ) { + if ( project.findProperty( 'gradle.publish.secret' ) != null ) { + throw new RuntimeException( "`gradle.publish.key` specified, but not `gradle.publish.secret` for publishing Gradle plugin" ) } } + else { + throw new RuntimeException( "No credentials specified for publishing Gradle plugin" ) + } } }