diff --git a/build.gradle b/build.gradle index bece5fcc1d63..85a808b4f54f 100644 --- a/build.gradle +++ b/build.gradle @@ -42,77 +42,36 @@ apply from: file( 'gradle/module.gradle' ) // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Release Task -task release { +tasks.register('release') { description = "The task performed when we are performing a release build. Relies on " + "the fact that subprojects will appropriately define a release task " + "themselves if they have any release-related activities to perform" doFirst { def javaVersionsInUse = jdkVersions.allVersions - if ( javaVersionsInUse != [JavaLanguageVersion.of( 11 )].toSet() ) { - throw new IllegalStateException( "Please use JDK 11 to perform the release. Currently using: ${javaVersionsInUse}" ) + if (javaVersionsInUse != [JavaLanguageVersion.of(11)].toSet()) { + throw new IllegalStateException("Please use JDK 11 to perform the release. Currently using: ${javaVersionsInUse}") } } } -task publish { +tasks.register('publish') { description = "The task performed when we want to just publish maven artifacts. Relies on " + "the fact that subprojects will appropriately define a release task " + "themselves if they have any publish-related activities to perform" } -ext { - if ( project.hasProperty( 'hibernatePublishUsername' ) ) { - if ( ! project.hasProperty( 'hibernatePublishPassword' ) ) { - throw new GradleException( "Should specify both `hibernatePublishUsername` and `hibernatePublishPassword` as project properties" ); - } - } -} - nexusPublishing { repositories { - sonatype { - username = project.hasProperty( 'hibernatePublishUsername' ) ? project.property( 'hibernatePublishUsername' ) : null - password = project.hasProperty( 'hibernatePublishPassword' ) ? project.property( 'hibernatePublishPassword' ) : null - } + sonatype() } } -gradle.taskGraph.addTaskExecutionGraphListener( - new TaskExecutionGraphListener() { - @Override - void graphPopulated(TaskExecutionGraph graph) { - String[] tasksToLookFor = [ - 'publish', - 'publishToSonatype', - 'publishAllPublicationsToSonatype', - 'publishPublishedArtifactsPublicationToSonatypeRepository', - 'publishRelocationArtifactsPublicationToSonatypeRepository', - ] - - for ( String taskToLookFor : tasksToLookFor ) { - if ( graph.hasTask( taskToLookFor ) ) { - // trying to publish - make sure the needed credentials are available - - if ( project.property( 'hibernatePublishUsername' ) == null ) { - throw new RuntimeException( "`-PhibernatePublishUsername=...` not found" ) - } - if ( project.property( 'hibernatePublishPassword' ) == null ) { - throw new RuntimeException( "`-PhibernatePublishPassword=...` not found" ) - } - - break; - } - } - } - } -) - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CI Build Task -task ciBuild { +tasks.register('ciBuild') { description = "The task performed when one of the 'main' jobs are triggered on the " + "CI server. Just as above, relies on the fact that subprojects will " + "appropriately define a release task themselves if they have any tasks " + diff --git a/ci/release/Jenkinsfile b/ci/release/Jenkinsfile index 6b6ca9089f5c..0e909b078bcb 100644 --- a/ci/release/Jenkinsfile +++ b/ci/release/Jenkinsfile @@ -57,6 +57,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}" + // Avoid doing a release for commits from a release def lastCommitter = sh(script: 'git show -s --format=\'%an\'', returnStdout: true).trim() def secondLastCommitter = sh(script: 'git show -s --format=\'%an\' HEAD~1', returnStdout: true).trim() @@ -124,25 +128,18 @@ pipeline { checkout scmGit(branches: [[name: '*/main']], extensions: [], userRemoteConfigs: [[credentialsId: 'ed25519.Hibernate-CI.github.com', url: 'https://github.com/hibernate/hibernate-release-scripts.git']]) } configFileProvider([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" - ]) { - 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" + ]) { + sh ".release/scripts/prepare-release.sh ${env.PROJECT} ${env.RELEASE_VERSION} ${env.DEVELOPMENT_VERSION}" + } + } } } } @@ -155,10 +152,12 @@ pipeline { } configFileProvider([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'), + // 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']) { diff --git a/gradle/published-java-module.gradle b/gradle/published-java-module.gradle index b9ea71617b22..bd0d4cf2e818 100644 --- a/gradle/published-java-module.gradle +++ b/gradle/published-java-module.gradle @@ -29,6 +29,8 @@ dependencies { // Publishing 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() } @@ -98,130 +100,86 @@ publishing { } -var signingKey = resolveSigningKey() -var signingPassword = findSigningProperty( "signingPassword" ) +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// 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( "signingKey" ) - if ( key != null ) { - return key - } - - var keyFile = findSigningProperty( "signingKeyFile" ) - if ( keyFile != null ) { - return new File( keyFile ).text - } - - return null +tasks.named( "publishPublishedArtifactsPublicationToSonatypeRepository" ) { + // publishing depends on signing + dependsOn signPublicationsTask } -String findSigningProperty(String propName) { - if ( System.getProperty( propName ) != null ) { - logger.debug "Found `{}` as a system property", propName - return System.getProperty(propName ) - } - else if ( System.getenv().get( propName ) != null ) { - logger.debug "Found `{}` as an env-var property", propName - return System.getenv().get( propName ) - } - else if ( project.hasProperty( propName ) ) { - logger.debug "Found `{}` as a project property", propName - return project.hasProperty( propName ) - } - else { - logger.debug "Did not find `{}`", propName - return null - } +tasks.register('sign') { + description "Pseudonym for :signPublications" + dependsOn signPublicationsTask } - -var signingTask = project.tasks.getByName( "signPublishedArtifactsPublication" ) as Sign var signingExtension = project.getExtensions().getByType(SigningExtension) as SigningExtension +signingExtension.sign publishing.publications.publishedArtifacts -task sign { - dependsOn "signPublications" -} +gradle.taskGraph.whenReady { TaskExecutionGraph graph -> + boolean wasSigningRequested = false + boolean wasPublishingRequested = false + + graph.allTasks.each {task -> + if ( task instanceof Sign ) { + wasSigningRequested = true + } + else if ( task instanceof PublishToMavenRepository ) { + wasPublishingRequested = true + } + } -task signPublications { t -> - tasks.withType( Sign ).all { s -> - t.dependsOn s + 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 {} : {} : {}", project.group, project.name, project.version } -} -signingTask.doFirst { - if ( signingKey == null || signingPassword == null ) { - throw new GradleException( - "Cannot perform signing without GPG details. Please set the `signingKey` and `signingKeyFile` properties" - ) + if ( wasSigningRequested || wasPublishingRequested ) { + // signing was explicitly requested and/or we are publishing to Sonatype OSSRH + // - we need the signing to happen + signingExtension.required = true + + var signingKey = resolveSigningKey() + var signingPassword = resolveSigningPassphrase() + signingExtension.useInMemoryPgpKeys( signingKey, signingPassword ) + } + else { + // signing was not explicitly requested and we are not publishing to OSSRH, + // - disable all Sign tasks + tasks.withType( Sign ).each { t-> t.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 551820769781..5778364aba00 100644 --- a/tooling/hibernate-gradle-plugin/hibernate-gradle-plugin.gradle +++ b/tooling/hibernate-gradle-plugin/hibernate-gradle-plugin.gradle @@ -100,19 +100,7 @@ publishing { } } -// local publishing (SNAPSHOT testing), cont. -// - https://github.com/gradle-nexus/publish-plugin/issues/143 -// - https://github.com/gradle-nexus/publish-plugin/pull/144 gradle.taskGraph.whenReady { - tasks.withType(PublishToMavenRepository) { PublishToMavenRepository t -> - if ( t.repository == null ) { - logger.info( "Task `{}` had null repository", t.path ) - } - else if ( t.repository.name == "sonatype" ) { - logger.debug( "Disabling task `{}` because it publishes to Sonatype", t.path ) - t.enabled = false - } - } } processResources { @@ -153,20 +141,38 @@ 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" ) + } + } + + // local publishing (SNAPSHOT testing), cont. + // - https://github.com/gradle-nexus/publish-plugin/issues/143 + // - https://github.com/gradle-nexus/publish-plugin/pull/144 + tasks.withType(PublishToMavenRepository) { PublishToMavenRepository t -> + if ( t.repository == null ) { + logger.info( "Task `{}` had null repository", t.path ) + } + else if ( t.repository.name == "sonatype" ) { + logger.debug( "Disabling task `{}` because it publishes to Sonatype", t.path ) + t.enabled = false + } } } \ No newline at end of file