diff --git a/build.gradle b/build.gradle index 6a35b97c163e..9ce03f745b51 100644 --- a/build.gradle +++ b/build.gradle @@ -40,19 +40,6 @@ apply from: file( 'gradle/module.gradle' ) // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Release Task -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}") - } - } -} - 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 " + diff --git a/ci/release/Jenkinsfile b/ci/release/Jenkinsfile index ab2cb33d8cde..1080b79cba7b 100644 --- a/ci/release/Jenkinsfile +++ b/ci/release/Jenkinsfile @@ -182,7 +182,7 @@ pipeline { 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']) { + sshagent(['ed25519.Hibernate-CI.github.com', 'hibernate-ci.frs.sourceforge.net']) { // set release version // update changelog from JIRA // tags the version @@ -217,13 +217,21 @@ pipeline { 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', 'jenkins.in.relation.to', 'hibernate-ci.frs.sourceforge.net']) { + 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" ]) { - sh ".release/scripts/publish.sh -j ${env.SCRIPT_OPTIONS} ${env.PROJECT} ${env.RELEASE_VERSION} ${env.DEVELOPMENT_VERSION} ${env.GIT_BRANCH}" + 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} " } } } @@ -254,7 +262,7 @@ pipeline { 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'] ) { + sshagent( ['ed25519.Hibernate-CI.github.com'] ) { dir( '.release/hibernate.org' ) { // Lock to avoid rejected pushes when multiple releases try to clone-commit-push lock('hibernate.org-git') { @@ -272,16 +280,6 @@ pipeline { } } } - stage('Create GitHub release') { - steps { - script { - checkoutReleaseScripts() - withCredentials([string(credentialsId: 'Hibernate-CI.github.com', variable: 'GITHUB_API_TOKEN')]) { - sh ".release/scripts/github-release.sh ${env.SCRIPT_OPTIONS} ${env.PROJECT} ${env.RELEASE_VERSION}" - } - } - } - } } post { always { diff --git a/documentation/documentation.gradle b/documentation/documentation.gradle index 570d6983fb5f..fbd22a24e531 100644 --- a/documentation/documentation.gradle +++ b/documentation/documentation.gradle @@ -34,7 +34,6 @@ repositories { apply from: rootProject.file( 'gradle/module.gradle' ) -apply from: rootProject.file( 'gradle/releasable.gradle' ) apply plugin: 'org.hibernate.orm.build.reports' @@ -194,10 +193,6 @@ dependencies { if ( project.ormVersion.isSnapshot ) { // only run the ci build tasks for SNAPSHOT versions tasks.register('ciBuild') { dependsOn clean } - tasks.release.enabled false -} -else { - tasks.release.dependsOn clean } diff --git a/gradle/published-java-module.gradle b/gradle/published-java-module.gradle index 7bbad9f85903..45791fabf74c 100644 --- a/gradle/published-java-module.gradle +++ b/gradle/published-java-module.gradle @@ -5,7 +5,6 @@ * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ -apply from: rootProject.file( 'gradle/releasable.gradle' ) apply from: rootProject.file( 'gradle/java-module.gradle' ) apply from: rootProject.file( 'gradle/publishing-pom.gradle' ) @@ -102,12 +101,19 @@ task ciBuild { dependsOn test } -tasks.release.dependsOn tasks.test - -tasks.preVerifyRelease.dependsOn build -tasks.preVerifyRelease.dependsOn generateMetadataFileForPublishedArtifactsPublication -tasks.preVerifyRelease.dependsOn generatePomFileForPublishedArtifactsPublication -tasks.preVerifyRelease.dependsOn generatePomFileForRelocationPomPublication +task releasePrepare { + group 'Release' + description 'Performs release preparations on local check-out, including updating changelog' + + dependsOn build + dependsOn generateMetadataFileForPublishedArtifactsPublication + dependsOn generatePomFileForPublishedArtifactsPublication + dependsOn generatePomFileForRelocationPomPublication + dependsOn generatePomFileForRelocationPomPublication + // we depend on publishAllPublicationsToStagingRepository to make sure that the artifacts are "published" to a local staging directory + // used by JReleaser during the release process + dependsOn publishAllPublicationsToStagingRepository +} // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Ancillary tasks diff --git a/gradle/releasable.gradle b/gradle/releasable.gradle deleted file mode 100644 index eb5052d02db7..000000000000 --- a/gradle/releasable.gradle +++ /dev/null @@ -1,10 +0,0 @@ -apply from: rootProject.file( 'gradle/base-information.gradle' ) - -task release { - mustRunAfter ':release:releaseChecks' - enabled !project.ormVersion.isSnapshot -} - -task preVerifyRelease { - dependsOn ':release:preVerifyRelease' -} diff --git a/hibernate-platform/hibernate-platform.gradle b/hibernate-platform/hibernate-platform.gradle index 323819dc6cec..ba64f64c107e 100644 --- a/hibernate-platform/hibernate-platform.gradle +++ b/hibernate-platform/hibernate-platform.gradle @@ -4,7 +4,6 @@ plugins { description = 'Gradle platform for Hibernate ORM' -apply from: rootProject.file( 'gradle/releasable.gradle' ) apply from: rootProject.file( "gradle/base-information.gradle" ) apply from: rootProject.file( "gradle/publishing-pom.gradle" ) diff --git a/release/jenkins-release-process.adoc b/release/jenkins-release-process.adoc index bc050ee2d1ca..0dbc67d98e7f 100644 --- a/release/jenkins-release-process.adoc +++ b/release/jenkins-release-process.adoc @@ -15,7 +15,7 @@ First, a list of resources you will need access to in order to perform a release == Steps -1. Perform `./gradlew preVerifyRelease` locally (after pulling all upstream changes). The Jenkins job does only the release steps, and we need to make sure tests and checkstyle especially are ok +1. Perform `./gradlew releasePrepare` locally (after pulling all upstream changes). The Jenkins job does only the release steps, and we need to make sure tests and checkstyle especially are ok 2. Mark the version as released in Jira 3. Close all issues associated with the version as closed. Be sure to remove the version from any issues that are not resolved (e.g. rejected) - the Jira "release notes" mechanism includes all issues with that version as the fix-for regardless of the resolution 4. Start the https://ci.hibernate.org/view/ORM/job/hibernate-orm-release/[Jenkins job]. It is a parameterized build - Jenkins will prompt user for needed information: @@ -34,4 +34,4 @@ The Jenkins job performs the following tasks: == Post-release steps -See <<./post-release-steps.adoc>> \ No newline at end of file +See <<./post-release-steps.adoc>> diff --git a/release/release.gradle b/release/release.gradle index 20ab54948257..2cab8764a481 100644 --- a/release/release.gradle +++ b/release/release.gradle @@ -189,371 +189,10 @@ def assembleDocumentationTask = tasks.register( "assembleDocumentation" ) { dependsOn stageOrmReportsTask } - -def releaseChecksTask = tasks.register( "releaseChecks" ) { - group 'Release' - description 'Checks and preparation for release' - - doFirst { - 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.\n" + - "Commit or stash your changes first.\n" + - "Uncommitted files:\n " + - uncommittedFiles - ); - } - - String gitBranchLocal - String gitRemoteLocal - - if (project.hasProperty('gitBranch') && !project.property('gitBranch').isEmpty()) { - gitBranchLocal = project.property('gitBranch') - } - else { - gitBranchLocal = executeGitCommand( 'branch', '--show-current' ).trim() - } - - if (project.hasProperty('gitRemote') && !project.property('gitRemote').isEmpty()) { - gitRemoteLocal = project.property('gitRemote') - } - else { - final String remotes = executeGitCommand( 'remote', 'show' ).trim() - final List tokens = remotes.tokenize() - if ( tokens.size() != 1 ) { - throw new GradleException( "Could not determine `gitRemote` property for `releaseChecks` tasks." ) - } - gitRemoteLocal = tokens.get( 0 ) - } - - project.ext { - gitBranch = gitBranchLocal - gitRemote = gitRemoteLocal - } - - 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 perform `ciRelease` tasks because there are un-pushed local commits .\n" + - "Push your commits first." - ); - } - } -} - -def preVerifyReleaseTask = tasks.register( "preVerifyRelease" ) { - group 'Release' - description 'Pre-verifies a release job execution (Run locally before a CI release)' - - dependsOn tasks.clean - dependsOn assembleDocumentationTask -} - -def changeLogFileTask = tasks.register( "changeLogFile" ) { - group 'Release' - description 'Updates the changelog.txt file based on the change-log report from Jira' - dependsOn releaseChecksTask - - doFirst { - logger.lifecycle( "Appending version `${project.releaseVersion}` to changelog..." ) - ChangeLogFile.update( ormVersion.fullName, rootProject ); - } -} - -def changeToReleaseVersionTask = tasks.register( "changeToReleaseVersion" ) { - group 'Release' - description 'Updates `gradle/version.properties` file to the specified release-version' - - dependsOn releaseChecksTask - - doFirst { - logger.lifecycle( "Updating version-file to release-version : `${project.releaseVersion}`" ) - updateVersionFile( project.releaseVersion ) - } -} - -def gitPreparationForReleaseTask = tasks.register( 'gitPreparationForRelease' ) { - dependsOn releaseChecksTask - dependsOn changeLogFileTask - dependsOn changeToReleaseVersionTask - - doLast { - logger.lifecycle( "Performing pre-steps Git commit : `${project.releaseVersion}`" ) - executeGitCommand( 'add', '.' ) - executeGitCommand( 'commit', '-m', "Pre-steps for release : `${project.ormVersion.fullName}`" ) - } -} - -def changeToDevelopmentVersionTask = tasks.register( 'changeToDevelopmentVersion' ) { - group 'Release' - description 'Updates `gradle/version.properties` file to the specified development-version' - - dependsOn releaseChecksTask - - doFirst { - logger.lifecycle( "Updating version-file to development-version : `${project.developmentVersion}`" ) - updateVersionFile( project.developmentVersion ) - } -} - -def releasePreparePostGitTask = tasks.register( 'gitTasksAfterRelease' ) { - dependsOn changeToDevelopmentVersionTask - - doLast { - if ( project.createTag ) { - logger.lifecycle( "Tagging release : `${project.releaseTag}`..." ) - executeGitCommand( 'tag', '-a', project.releaseTag, '-m', "Release $project.ormVersion.fullName" ) - } - - logger.lifecycle( "Performing post-steps Git commit : `${project.releaseVersion}`" ) - executeGitCommand( 'add', '.' ) - executeGitCommand( 'commit', '-m', "Post-steps for release : `${project.ormVersion.fullName}`" ) - } -} - -void updateVersionFile(String version) { - logger.lifecycle( "Updating `gradle/version.properties` version to `${version}`" ) - project.ormVersionFile.text = "hibernateVersion=${version}" -} - -def releasePerformPostGitTask = tasks.register( 'gitTasksAfterReleasePerform' ) { - - doLast { - if ( project.createTag ) { - logger.lifecycle( "Pushing branch and tag to remote `${project.gitRemote}`..." ) - executeGitCommand( 'push', '--atomic', project.gitRemote, project.gitBranch, project.releaseTag ) - } - else { - logger.lifecycle( "Pushing branch to remote `${project.gitRemote}`..." ) - executeGitCommand( 'push', project.gitRemote, project.gitBranch ) - } - } -} - -def releasePrepareTask = tasks.register( 'releasePrepare' ) { +task releasePrepare { group 'Release' description 'Performs release preparations on local check-out, including updating changelog' // we want to assemble the docs here so that we catch problems early (and even during "dry run" for CI releases) dependsOn assembleDocumentationTask - dependsOn gitPreparationForReleaseTask - - finalizedBy releasePreparePostGitTask -} - -def releasePerformTask = tasks.register( 'releasePerform' ) { - group 'Release' - description 'Performs a release on local check-out, including updating changelog and ' - - finalizedBy releasePerformPostGitTask -} - -def releaseTask = tasks.register( 'release' ) { - group 'Release' - description 'Performs a release on local check-out, including updating changelog and ' - - dependsOn releasePrepareTask - dependsOn releasePerformTask -} - -def ciReleaseTask = tasks.register( 'ciRelease' ) { - 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.' - - dependsOn releaseTask -} - -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, Project project) { - def text = "" - File changelog = project.rootProject.layout.projectDirectory.file( "changelog.txt" ).asFile - 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 ReleaseNote releaseNotes = null - def String nextPageToken = null - def issuetype = null - do { - def apiString = "https://hibernate.atlassian.net/rest/api/3/search/jql/?jql=project=HHH%20AND%20fixVersion=${restReleaseVersion}%20AND%20statusCategory%20%3D%20Done%20order%20by%20issuetype%20ASC&fields=issuetype,summary,fixVersions&maxResults=200${nextPageToken == null ? '' : '&nextPageToken=' + nextPageToken}" - def apiUrl = new URI(apiString).toURL() - def jsonReleaseNotes = new JsonSlurper().parse(apiUrl) - if (releaseNotes == null) { - def releaseDate = new Date().format( 'MMMM dd, YYYY' ) - def versionId = getVersionId(jsonReleaseNotes, restReleaseVersion) - releaseNotes = new ReleaseNote(releaseVersion, releaseDate, versionId) - } - - 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 ) - } - - nextPageToken = jsonReleaseNotes.nextPageToken - - } while (nextPageToken != null) - - releaseNotes.addEmptyLine() - return releaseNotes.notes - } - - private static getVersionId(jsonReleaseNotes, String restReleaseVersion) { - for ( def issue : jsonReleaseNotes.issues ) { - for ( def fixVersion : issue.fields.fixVersions ) { - if ( fixVersion.name == restReleaseVersion ) { - return fixVersion.id - } - } - } - throw new GradleException("No issues found for current release version (" + restReleaseVersion + "), aborting.") - } -} - -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() - } - } -} - - -gradle.getTaskGraph().whenReady {tg-> - - if ( ( tg.hasTask( project.tasks.releasePrepare ) || tg.hasTask( project.tasks.releasePerform ) ) - && ! project.getGradle().getStartParameter().isDryRun() ) { - String releaseVersionLocal - String developmentVersionLocal - - def console = tg.hasTask( project.tasks.release ) && !tg.hasTask( project.tasks.ciRelease ) - ? System.console() - : null - - if (project.hasProperty('releaseVersion')) { - releaseVersionLocal = project.property('releaseVersion') - } - else { - if (console) { - // prompt for `releaseVersion` - releaseVersionLocal = console.readLine('> Enter the release version: ') - } - else { - throw new GradleException( - "`release`-related tasks require the following properties: 'releaseVersion', 'developmentVersion'" - ) - } - } - - if (project.hasProperty('developmentVersion')) { - developmentVersionLocal = project.property('developmentVersion') - } - else { - if (console) { - // prompt for `developmentVersion` - developmentVersionLocal = console.readLine('> Enter the next development version: ') - } - else { - throw new GradleException( - "`release`-related tasks require the following properties: 'releaseVersion', 'developmentVersion'" - ) - } - } - - assert releaseVersionLocal != null && developmentVersionLocal != null; - - // set up information for the release-related tasks - project.ext { - releaseVersion = releaseVersionLocal; - developmentVersion = developmentVersionLocal; - createTag = !project.hasProperty('noTag') - releaseTag = project.createTag ? determineReleaseTag(releaseVersionLocal) : '' - } - } -} - -static String determineReleaseTag(String releaseVersion) { - return releaseVersion.endsWith( '.Final' ) - ? releaseVersion.replace( ".Final", "" ) - : releaseVersion; } diff --git a/release_notes.md b/release_notes.md new file mode 100644 index 000000000000..3d58a819f02a --- /dev/null +++ b/release_notes.md @@ -0,0 +1,4 @@ + +* See the [website](https://hibernate.org/orm/releases/{{releaseVersionFamily}}) for requirements and compatibilities. +* See the [What's New](https://hibernate.org/orm/releases/{{releaseVersionFamily}}/#whats-new) guide for details about new features and capabilities. +* See the [Migration Guide](https://docs.hibernate.org/orm/{{releaseVersionFamily}}/migration-guide/) for details about migration to {{releaseVersionFamily}} version. diff --git a/tooling/hibernate-gradle-plugin/hibernate-gradle-plugin.gradle b/tooling/hibernate-gradle-plugin/hibernate-gradle-plugin.gradle index 5e0ac1e8376c..279b2cde9bed 100644 --- a/tooling/hibernate-gradle-plugin/hibernate-gradle-plugin.gradle +++ b/tooling/hibernate-gradle-plugin/hibernate-gradle-plugin.gradle @@ -19,7 +19,6 @@ plugins { apply from: rootProject.file( 'gradle/module.gradle' ) apply from: rootProject.file( 'gradle/javadoc.gradle' ) -apply from: rootProject.file( 'gradle/releasable.gradle' ) description = "Gradle plugin for integrating Hibernate aspects into your build" @@ -79,12 +78,6 @@ test { useJUnitPlatform() } -// Publish to the Gradle Plugin Portal -tasks.release.dependsOn tasks.publishPlugins - -// local publishing (SNAPSHOT testing) -tasks.publish.dependsOn tasks.publishPlugins - // local publishing (SNAPSHOT testing) publishing { repositories { @@ -169,9 +162,9 @@ gradle.taskGraph.whenReady { tg -> } } -tasks.register("releasePerform") { +task releaseGradlePluginPerform { group "release-perform" - description "See :release:releasePerform for details. Here we hook in publishing to the Plugin Portal" + description "An explicit task for publishing Gradle Plugins to the Plugin Portal" dependsOn tasks.publishPlugins }