From 87588472abaf0ffab5fbe4b5284678c1b4f19b3d Mon Sep 17 00:00:00 2001 From: marko-bekhta Date: Tue, 11 Nov 2025 14:39:19 +0100 Subject: [PATCH] Update the order of release steps and simplify the ORM build script [HHH-19913] --- ci/release/Jenkinsfile | 179 ++++++++++++---------- gradle/published-java-module.gradle | 5 +- release/release.gradle | 227 +--------------------------- 3 files changed, 107 insertions(+), 304 deletions(-) diff --git a/ci/release/Jenkinsfile b/ci/release/Jenkinsfile index 78dd1e3da17b..9a92217db669 100644 --- a/ci/release/Jenkinsfile +++ b/ci/release/Jenkinsfile @@ -176,92 +176,111 @@ pipeline { script { checkoutReleaseScripts() - configFileProvider([ - configFile(fileId: 'release.config.ssh', targetLocation: "${env.HOME}/.ssh/config"), - configFile(fileId: 'release.config.ssh.knownhosts', targetLocation: "${env.HOME}/.ssh/known_hosts") - ]) { - 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([ - "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 -j -b ${env.GIT_BRANCH} -v ${env.DEVELOPMENT_VERSION} ${env.PROJECT} ${env.RELEASE_VERSION}" - } - } - } - } - } - } - stage('Publish release') { - steps { - script { - checkoutReleaseScripts() + configFileProvider([ + configFile(fileId: 'release.config.ssh', targetLocation: "${env.HOME}/.ssh/config"), + configFile(fileId: 'release.config.ssh.knownhosts', targetLocation: "${env.HOME}/.ssh/known_hosts") + ]) { + sshagent(['ed25519.Hibernate-CI.github.com', 'hibernate-ci.frs.sourceforge.net']) { + // set release version + // update changelog from JIRA + // tags the version + // changes the version to the provided development version + withEnv([ + "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 -j -b ${env.GIT_BRANCH} -v ${env.DEVELOPMENT_VERSION} ${env.PROJECT} ${env.RELEASE_VERSION}" + } + } + } + } + } + } + stage('Publish') { + steps { + script { + checkoutReleaseScripts() - 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: 'central.sonatype.com', passwordVariable: 'JRELEASER_MAVENCENTRAL_TOKEN', usernameVariable: 'JRELEASER_MAVENCENTRAL_USERNAME'), - // 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'), - gitUsernamePassword(credentialsId: 'username-and-token.Hibernate-CI.github.com', gitToolName: 'Default'), - file(credentialsId: 'release.gpg.private-key', variable: 'RELEASE_GPG_PRIVATE_KEY_PATH'), - string(credentialsId: 'release.gpg.passphrase', variable: 'JRELEASER_GPG_PASSPHRASE'), - string(credentialsId: 'Hibernate-CI.github.com', variable: 'JRELEASER_GITHUB_TOKEN') - ]) { - sshagent(['ed25519.Hibernate-CI.github.com', 'hibernate.filemgmt.jboss.org', 'hibernate-ci.frs.sourceforge.net']) { - // performs documentation upload and Sonatype release - // push to github - withEnv([ - "DISABLE_REMOTE_GRADLE_CACHE=true" - ]) { - sh ".release/scripts/publish.sh -j ${env.SCRIPT_OPTIONS} ${env.PROJECT} ${env.RELEASE_VERSION} ${env.DEVELOPMENT_VERSION} ${env.GIT_BRANCH}" - } - } - } - } - } - } - } - stage('Website release') { - steps { - script { - checkoutReleaseScripts() + 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: 'central.sonatype.com', passwordVariable: 'JRELEASER_MAVENCENTRAL_TOKEN', usernameVariable: 'JRELEASER_MAVENCENTRAL_USERNAME'), + // 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'), + gitUsernamePassword(credentialsId: 'username-and-token.Hibernate-CI.github.com', gitToolName: 'Default'), + file(credentialsId: 'release.gpg.private-key', variable: 'RELEASE_GPG_PRIVATE_KEY_PATH'), + string(credentialsId: 'release.gpg.passphrase', variable: 'JRELEASER_GPG_PASSPHRASE'), + string(credentialsId: 'Hibernate-CI.github.com', variable: 'JRELEASER_GITHUB_TOKEN') + ]) { + sshagent(['ed25519.Hibernate-CI.github.com', 'jenkins.in.relation.to', 'hibernate-ci.frs.sourceforge.net']) { + // performs documentation upload and Sonatype release + // push to github + withEnv([ + "DISABLE_REMOTE_GRADLE_CACHE=true" + ]) { + def notesFiles = findFiles(glob: 'release_notes.md') + if ( notesFiles.length < 1 ) { + throw new IllegalStateException( "Could not locate `release_notes.md`" ) + } + if ( notesFiles.length > 1 ) { + throw new IllegalStateException( "Located more than 1 `release_notes.md`" ) + } + + sh ".release/scripts/publish.sh -j --notes=${notesFiles[0].path} ${env.SCRIPT_OPTIONS} ${env.PROJECT} ${env.RELEASE_VERSION} ${env.DEVELOPMENT_VERSION} ${env.GIT_BRANCH} " + } + } + } + } + } + } + } + stage('Release on Jira') { + steps { + script { + checkoutReleaseScripts() + + withCredentials([string(credentialsId: 'release-webhook.hibernate.atlassian.net', variable: 'JIRA_WEBHOOK_SECRET')]) { + sh ".release/scripts/jira-release.sh ${env.SCRIPT_OPTIONS} ${env.PROJECT} ${env.RELEASE_VERSION} ${env.DEVELOPMENT_VERSION}" + } + } + } + } + stage('Update website') { + steps { + script { + checkoutReleaseScripts() - configFileProvider([ - configFile(fileId: 'release.config.ssh', targetLocation: "${env.HOME}/.ssh/config"), - configFile(fileId: 'release.config.ssh.knownhosts', targetLocation: "${env.HOME}/.ssh/known_hosts") - ]) { - withCredentials([ - 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'] ) { - dir( '.release/hibernate.org' ) { + configFileProvider([ + configFile(fileId: 'release.config.ssh', targetLocation: "${env.HOME}/.ssh/config"), + configFile(fileId: 'release.config.ssh.knownhosts', targetLocation: "${env.HOME}/.ssh/known_hosts") + ]) { + withCredentials([ + gitUsernamePassword(credentialsId: 'username-and-token.Hibernate-CI.github.com', gitToolName: 'Default') + ]) { + sshagent( ['ed25519.Hibernate-CI.github.com'] ) { + dir( '.release/hibernate.org' ) { checkout scmGit( branches: [[name: '*/production']], extensions: [], userRemoteConfigs: [[credentialsId: 'ed25519.Hibernate-CI.github.com', url: 'https://github.com/hibernate/hibernate.org.git']] ) sh "../scripts/website-release.sh ${env.SCRIPT_OPTIONS} ${env.PROJECT} ${env.RELEASE_VERSION}" - } - } - } - } - } - } - } - } - post { - always { - configFileProvider([configFile(fileId: 'job-configuration.yaml', variable: 'JOB_CONFIGURATION_FILE')]) { - notifyBuildResult maintainers: (String) readYaml(file: env.JOB_CONFIGURATION_FILE).notification?.email?.recipients - } - } - } + } + } + } + } + } + } + } + } + post { + always { + configFileProvider([configFile(fileId: 'job-configuration.yaml', variable: 'JOB_CONFIGURATION_FILE')]) { + notifyBuildResult maintainers: (String) readYaml(file: env.JOB_CONFIGURATION_FILE).notification?.email?.recipients + } + } + } } diff --git a/gradle/published-java-module.gradle b/gradle/published-java-module.gradle index 369ab9e5c275..288a95d500fa 100644 --- a/gradle/published-java-module.gradle +++ b/gradle/published-java-module.gradle @@ -164,5 +164,8 @@ publishing { task ciBuild( dependsOn: [test, publish] ) -task release( dependsOn: [test] ) +task releasePrepare( dependsOn: [publishAllPublicationsToStagingRepository] ) { + group = "Release" + description = "Performs a release: the hibernate version is set and the changelog.txt file updated, the changes are pushed to github, then the release is performed, tagged and the hibernate version is set to the development one." +} diff --git a/release/release.gradle b/release/release.gradle index 50be844f52f5..89775dadb37e 100644 --- a/release/release.gradle +++ b/release/release.gradle @@ -11,52 +11,11 @@ import groovy.json.JsonSlurper apply plugin: 'idea' apply plugin: 'distribution' -ext { - if ( !project.hasProperty( 'gitRemote' ) ) { - gitRemote = 'origin' - } -} - idea.module { } final File documentationDir = mkdir( "${rootProject.buildDir}/staging-deploy/documentation" ); -task releaseChecks() { - doFirst { - if ( !project.hasProperty('releaseVersion') || !project.hasProperty('developmentVersion') - || !project.hasProperty('gitRemote') ||!project.hasProperty('gitBranch') ) { - throw new GradleException( - "Release tasks require all of the following properties to be set:" - + "'releaseVersion', 'developmentVersion', 'gitRemote', 'gitBranch'." - ) - } - - logger.lifecycle( "Checking that the working tree is clean..." ) - String uncommittedFiles = executeGitCommand( 'status', '--porcelain' ) - if ( !uncommittedFiles.isEmpty() ) { - throw new GradleException( - "Cannot release because there are uncommitted or untracked files in the working tree." - + "\nCommit or stash your changes first." - + "\nUncommitted files:\n" + uncommittedFiles - ); - } - - logger.lifecycle( "Switching to branch '${project.gitBranch}'..." ) - executeGitCommand( 'checkout', project.gitBranch ) - - logger.lifecycle( "Checking that all commits are pushed..." ) - String diffWithUpstream = executeGitCommand( 'diff', '@{u}' ) - if ( !diffWithUpstream.isEmpty() ) { - throw new GradleException( - "Cannot release because there are commits on the branch to release that haven't been pushed yet." - + "\nPush your commits to the branch to release first." - ); - } - - } -} - /** * Assembles all documentation into the {buildDir}/documentation directory. * @@ -102,190 +61,12 @@ task assembleDocumentation(type: Task, dependsOn: [rootProject.project( 'documen } } -task releasePerform( dependsOn: [releaseChecks] ) { - doLast { - String tag = null - if ( !project.hasProperty( 'noTag' ) ) { - logger.lifecycle("Pushing branch to remote '${project.gitRemote}'...") - executeGitCommand( 'push', project.gitRemote , project.gitBranch ) - } - else { - logger.lifecycle("Pushing branch and tag to remote '${project.gitRemote}'...") - executeGitCommand( 'push', '--atomic', project.gitRemote , project.gitBranch, tag ) - } - } -} - -task changeLogFile( dependsOn: [releaseChecks] ) { - group = "Release" - description = "Updates the changelog.txt file" - - doFirst { - logger.lifecycle( "Appending version '${project.releaseVersion}' to changelog..." ) - ChangeLogFile.update( ormVersion.fullName ); - } -} - -task addVersionCommit( dependsOn: [changeLogFile] ) { - group = "Release" - description = "Adds a commit for the released version and push the changes to github" - doFirst{ - logger.lifecycle( "Updating version to '${project.releaseVersion}'..." ) - project.ormVersionFile.text = "hibernateVersion=${project.releaseVersion}" - - logger.lifecycle( "Adding commit to update version to '${project.releaseVersion}'..." ) - executeGitCommand( 'add', '.' ) - executeGitCommand( 'commit', '-m', project.ormVersion.fullName ) - } -} - -rootProject.subprojects.each { Project subProject -> - if ( !this.name.equals( subProject.name ) ) { - if ( subProject.tasks.findByName( 'releasePerform' ) ) { - this.tasks.releasePerform.dependsOn( subProject.tasks.releasePerform ) - } - } -} - -task releasePrepare( dependsOn: [releaseChecks, addVersionCommit, assembleDocumentation] ) { +task releasePrepare( dependsOn: [assembleDocumentation] ) { group = "Release" description = "Performs a release: the hibernate version is set and the changelog.txt file updated, the changes are pushed to github, then the release is performed, tagged and the hibernate version is set to the development one." - doLast { - String tag = null - if ( !project.hasProperty( 'noTag' ) ) { - tag = project.ormVersion.fullName - // the release is tagged and the tag is pushed to github - if ( tag.endsWith( ".Final" ) ) { - tag = tag.replace( ".Final", "" ) - } - logger.lifecycle( "Tagging '${tag}'..." ) - executeGitCommand( 'tag', '-a', tag, '-m', "Release $project.ormVersion.fullName" ) - } - - logger.lifecycle( "Adding commit to update version to '${project.developmentVersion}'..." ) - project.ormVersionFile.text = "hibernateVersion=${project.developmentVersion}" - executeGitCommand( 'add', '.') - executeGitCommand( 'commit', '-m', project.developmentVersion ) - } } -static String executeGitCommand(Object ... subcommand){ - List command = ['git'] - Collections.addAll( command, subcommand ) - def proc = command.execute() - def code = proc.waitFor() - def stdout = inputStreamToString( proc.getInputStream() ) - def stderr = inputStreamToString( proc.getErrorStream() ) - if ( code != 0 ) { - throw new GradleException( "An error occurred while executing " + command + "\n\nstdout:\n" + stdout + "\n\nstderr:\n" + stderr ) - } - return stdout -} - -static String inputStreamToString(InputStream inputStream) { - inputStream.withCloseable { ins -> - new BufferedInputStream(ins).withCloseable { bis -> - new ByteArrayOutputStream().withCloseable { buf -> - int result = bis.read(); - while (result != -1) { - buf.write((byte) result); - result = bis.read(); - } - return buf.toString( StandardCharsets.UTF_8.name()); - } - } - } -} - -class ChangeLogFile { - - // Get the Release Notes from Jira and add them to the Hibernate changelog.txt file - static void update(String releaseVersion) { - def text = "" - File changelog = new File( "changelog.txt" ) - def newReleaseNoteBlock = getNewReleaseNoteBlock(releaseVersion) - changelog.eachLine { - line -> - if ( line.startsWith( "Note:" ) ) { - text += line + System.lineSeparator() + System.lineSeparator() + newReleaseNoteBlock - } - else { - text += line + System.lineSeparator() - } - } - changelog.text = text - } - - // Get the Release Notes from Jira - static String getNewReleaseNoteBlock(String releaseVersion) { - def restReleaseVersion; - if ( releaseVersion.endsWith( ".Final" ) ) { - restReleaseVersion = releaseVersion.replace( ".Final", "" ) - } - else { - restReleaseVersion = releaseVersion - } - def apiString = "https://hibernate.atlassian.net/rest/api/2/search/?jql=project=HHH%20AND%20fixVersion=${restReleaseVersion}%20order%20by%20issuetype%20ASC" - def apiUrl = new URL( apiString ) - def jsonReleaseNotes = new JsonSlurper().parse( apiUrl ) - def releaseDate = new Date().format( 'MMMM dd, YYYY' ) - def versionId = getVersionId( jsonReleaseNotes, restReleaseVersion ) - - ReleaseNote releaseNotes = new ReleaseNote( releaseVersion, releaseDate, versionId ) - - def issuetype - jsonReleaseNotes.issues.each { - issue -> - if ( issuetype != issue.fields.issuetype.name ) { - issuetype = issue.fields.issuetype.name - releaseNotes.addEmptyLine(); - releaseNotes.addLine( "** ${issue.fields.issuetype.name}" ) - } - releaseNotes.addLine( " * [" + issue.key + "] - " + issue.fields.summary ) - } - releaseNotes.addEmptyLine() - return releaseNotes.notes - } - - private static getVersionId(jsonReleaseNotes, String restReleaseVersion) { - def fixVersions = jsonReleaseNotes.issues.get( 0 ).fields.fixVersions - - for ( def fixVersion : fixVersions ) { - if ( fixVersion.name.equals( restReleaseVersion ) ) { - return fixVersion.id - } - } - throw new GradleException( "Unable to determine the version id of the current release." ) - } -} - -class ReleaseNote { - String notes; - String notesHeaderSeparator = "------------------------------------------------------------------------------------------------------------------------" - - ReleaseNote(String releaseVersion, String releaseDate, String versionId) { - notes = "Changes in ${releaseVersion} (${releaseDate})" + System.lineSeparator() - addHeaderSeparator() - addEmptyLine() - addLine( "https://hibernate.atlassian.net/projects/HHH/versions/${versionId}" ) - } - - void addLine(String text) { - notes += text + System.lineSeparator() - } - - void addHeaderSeparator() { - addLine( notesHeaderSeparator ) - } - - void addEmptyLine() { - notes += System.lineSeparator() - } - - void addEmptyLines(int numberOfLines) { - for ( i in 1..numberOfLines ) { - notes += System.lineSeparator() - } - } +task releaseGradlePluginPerform { + group = "Release" + description = "This is only a stub task for the release scripts to call. We do not actually publish any Gradle plugins in 5.x.We do publish them in 6+." } -