From f232f87fbc9d4b5b29ebe15a247ad8d963fd26ee Mon Sep 17 00:00:00 2001 From: Russell Spitzer Date: Wed, 4 Nov 2026 12:55:51 -0600 Subject: [PATCH] MINOR: Set the POM SCM tag when preparing and publishing releases prepare-rc.sh only ran versions:set, so in the root POM kept whatever the release branch carried. The 1.18.2 RCs shipped apache-parquet-1.18.0-rc2 and the 1.19.0 RCs shipped HEAD. - prepare-rc.sh writes the RC tag into in the release commit, including on rc1+ when the version is already set, and refuses to tag and deploy if the committed tag doesn't match. - publish-release.sh checks out the release branch before comparing it with the RC tag (the workflow is dispatched from master), and resets to HEAD in the next development iteration commit. --- release/bin/prepare-rc.sh | 44 ++++++++++++++++++++++++++-------- release/bin/publish-release.sh | 15 +++++++++++- release/libs/_version.sh | 10 ++++++++ release/tests/version.bats | 37 ++++++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 11 deletions(-) diff --git a/release/bin/prepare-rc.sh b/release/bin/prepare-rc.sh index 931fd5460f..b18626fb38 100755 --- a/release/bin/prepare-rc.sh +++ b/release/bin/prepare-rc.sh @@ -221,26 +221,39 @@ step_summary "> it is a mechanical version bump on top of the verified" step_summary "> commit above." # --------------------------------------------------------------------------- -# Step 4: Set POM versions (only on rc0 or if version doesn't match) +# Step 4: Set POM version and SCM tag (whenever either doesn't match) # --------------------------------------------------------------------------- step_summary "" step_summary "### Version Update" current_pom_version=$(get_current_pom_version || echo "unknown") +current_scm_tag=$(get_current_pom_scm_tag || echo "unknown") print_info "Current POM version: ${current_pom_version}" +print_info "Current POM SCM tag: ${current_scm_tag}" -if [[ "${current_pom_version}" == "${version}" ]]; then - print_info "POM version already set to ${version}, skipping version update" - step_summary "POM version already at \`${version}\`, no update needed" +if [[ "${current_pom_version}" == "${version}" && "${current_scm_tag}" == "${rc_tag}" ]]; then + print_info "POM version and SCM tag already set for ${rc_tag}, skipping update" + step_summary "POM version already at \`${version}\` and SCM tag at \`${rc_tag}\`, no update needed" else - print_info "Setting POM version to ${version}..." - set_pom_version "${version}" - step_summary "Updated POM version: \`${current_pom_version}\` -> \`${version}\`" + if [[ "${current_pom_version}" != "${version}" ]]; then + print_info "Setting POM version to ${version}..." + set_pom_version "${version}" + step_summary "Updated POM version: \`${current_pom_version}\` -> \`${version}\`" + fi + + # Each RC needs its own tag here, so this also runs on rc1+ when the + # version is already set. Whatever the branch carried is overwritten. + if [[ "${current_scm_tag}" != "${rc_tag}" ]]; then + print_info "Setting POM SCM tag to ${rc_tag}..." + set_pom_scm_tag "${rc_tag}" + step_summary "Updated POM SCM tag: \`${current_scm_tag}\` -> \`${rc_tag}\`" + fi - # Commit version changes. Stage tracked files only: set_pom_version only - # edits existing POMs, and anything untracked must not land in the release. + # Commit version changes. Stage tracked files only: the version and SCM tag + # updates only edit existing POMs, and anything untracked must not land in + # the release. exec_process git add -u - exec_process git commit -m "Set version to ${version} for release" + exec_process git commit -m "Set version to ${version} for release (${rc_tag})" fi if ! require_clean_worktree; then @@ -248,6 +261,17 @@ if ! require_clean_worktree; then exit 1 fi +# The staged POMs are what Maven Central publishes, so refuse to tag and +# deploy a commit whose doesn't name this RC. +if [[ ${DRY_RUN:-1} -ne 1 ]]; then + committed_scm_tag=$(get_current_pom_scm_tag || echo "unknown") + if [[ "${committed_scm_tag}" != "${rc_tag}" ]]; then + print_error "POM SCM tag is '${committed_scm_tag}', expected '${rc_tag}'" + step_summary "SCM tag check: **FAILED** (\`${committed_scm_tag}\` != \`${rc_tag}\`)" + exit 1 + fi +fi + # --------------------------------------------------------------------------- # Step 5: Create RC tag locally (pushed in step 9) # --------------------------------------------------------------------------- diff --git a/release/bin/publish-release.sh b/release/bin/publish-release.sh index c1a62155a0..99207c0dd4 100755 --- a/release/bin/publish-release.sh +++ b/release/bin/publish-release.sh @@ -176,6 +176,18 @@ if ! git rev-parse "${rc_tag}" >/dev/null 2>&1; then exit 1 fi +# The workflow is dispatched from master, which is where these scripts live, +# so switch to the release branch before comparing it with the RC tag. This +# runs in dry-run mode too: it is local, and the checks below depend on it. +release_branch="${BRANCH_PREFIX}${major}.${minor}.x" +if [[ "$(git branch --show-current)" != "${release_branch}" ]]; then + print_info "Switching to ${release_branch}..." + if ! git checkout "${release_branch}"; then + print_error "Could not check out release branch ${release_branch}" + exit 1 + fi +fi + rc_commit=$(git rev-list -1 "${rc_tag}") current_commit=$(git rev-parse HEAD) @@ -314,6 +326,7 @@ next_snapshot="${next_dev_version}-SNAPSHOT" print_info "Bumping version to ${next_snapshot}..." set_pom_version "${next_snapshot}" +set_pom_scm_tag "HEAD" # Update previous.version property exec_process ./mvnw -pl . versions:set-property \ @@ -333,7 +346,7 @@ expected_branch="${BRANCH_PREFIX}${major}.${minor}.x" if [[ "${current_branch}" != "${expected_branch}" ]]; then print_error "Refusing to push version bump: current branch is '${current_branch}'" print_error "Expected to be on release branch '${expected_branch}' for version ${version}." - print_error "Run the publish workflow with that branch selected, or check out '${expected_branch}' locally." + print_error "The script checks out '${expected_branch}' before publishing; something switched branches since then." exit 1 fi # Also confirm the format independently in case someone has named a diff --git a/release/libs/_version.sh b/release/libs/_version.sh index 61ada8d760..40f13f9971 100644 --- a/release/libs/_version.sh +++ b/release/libs/_version.sh @@ -91,3 +91,13 @@ function set_pom_version { function get_current_pom_version { ./mvnw help:evaluate -Dexpression=project.version -q -DforceStdout 2>/dev/null } + +# Only the root POM declares ; every module inherits its tag. +function set_pom_scm_tag { + local tag="$1" + exec_process ./mvnw -pl . versions:set-scm-tag -DnewTag="${tag}" -DgenerateBackupPoms=false --batch-mode -q +} + +function get_current_pom_scm_tag { + ./mvnw -pl . help:evaluate -Dexpression=project.scm.tag -q -DforceStdout 2>/dev/null +} diff --git a/release/tests/version.bats b/release/tests/version.bats index 9554fd0dbb..ffef97b56a 100644 --- a/release/tests/version.bats +++ b/release/tests/version.bats @@ -175,6 +175,43 @@ setup() { [[ "$output" == *"2.0.0-SNAPSHOT"* ]] } +# ---- set_pom_scm_tag ---- + +@test "set_pom_scm_tag: passes correct args to mvnw in dry-run" { + DRY_RUN=1 + run set_pom_scm_tag "apache-parquet-1.18.2-rc1" + [ "$status" -eq 0 ] + [[ "$output" == *"-pl . versions:set-scm-tag"* ]] + [[ "$output" == *"-DnewTag=apache-parquet-1.18.2-rc1"* ]] + [[ "$output" == *"-DgenerateBackupPoms=false"* ]] +} + +@test "set_pom_scm_tag: accepts HEAD for the next development iteration" { + DRY_RUN=1 + run set_pom_scm_tag "HEAD" + [ "$status" -eq 0 ] + [[ "$output" == *"-DnewTag=HEAD"* ]] +} + +# ---- get_current_pom_scm_tag ---- + +@test "get_current_pom_scm_tag: evaluates project.scm.tag on the root POM" { + local tmpbin + tmpbin=$(mktemp -d) + cat > "${tmpbin}/mvnw" << 'SCRIPT' +#!/bin/bash +if [[ "$*" == *"-pl . help:evaluate -Dexpression=project.scm.tag"* ]]; then + echo "apache-parquet-1.18.0-rc2" +fi +SCRIPT + chmod +x "${tmpbin}/mvnw" + cd "${tmpbin}" + local result + result=$(get_current_pom_scm_tag) + [ "$result" = "apache-parquet-1.18.0-rc2" ] + rm -rf "${tmpbin}" +} + # ---- find_latest_rc_number ---- @test "find_latest_rc_number: returns highest RC number" {