This is an automated email from the ASF dual-hosted git repository.
pingtimeout pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/polaris.git
The following commit(s) were added to refs/heads/main by this push:
new bd1babb02 Ensure release can only run from specific SHA (#3295)
bd1babb02 is described below
commit bd1babb02f6370c2b33ab615b515c4ba0fe0dc32
Author: Pierre Laporte <[email protected]>
AuthorDate: Mon Dec 22 09:54:18 2025 +0100
Ensure release can only run from specific SHA (#3295)
* Ensure release publish workflow can only run from last RC (#3290)
* Enable use of second release workflow for RC>0
* Patch 3rd workflow to support commits with multiple RC tags
* Force 4th workflow to only run from a release branch
* Update release guide to match new workflows
---
.../release-2-update-release-candidate.yml | 13 ++--
.../release-3-build-and-publish-artifacts.yml | 15 +++-
.github/workflows/release-4-publish-release.yml | 53 ++++++++-----
releasey/libs/_version.sh | 33 +++++---
.../release-guides/semi-automated-release-guide.md | 84 ++++++++++-----------
.../img/release-guides/github-workflow-3.png | Bin 237365 -> 237744 bytes
6 files changed, 116 insertions(+), 82 deletions(-)
diff --git a/.github/workflows/release-2-update-release-candidate.yml
b/.github/workflows/release-2-update-release-candidate.yml
index b760b5287..83d75b646 100644
--- a/.github/workflows/release-2-update-release-candidate.yml
+++ b/.github/workflows/release-2-update-release-candidate.yml
@@ -146,6 +146,7 @@ jobs:
java-version: '21'
- name: Update project versions
+ if: env.rc_number == '0'
run: |
source "${LIBS_DIR}/_version.sh"
@@ -156,6 +157,7 @@ jobs:
EOT
- name: Update changelog
+ if: env.rc_number == '0'
run: |
source "${LIBS_DIR}/_exec.sh"
exec_process ./gradlew patchChangelog
@@ -166,6 +168,7 @@ jobs:
EOT
- name: Commit and push changes
+ if: env.rc_number == '0'
run: |
source "${LIBS_DIR}/_constants.sh"
source "${LIBS_DIR}/_exec.sh"
@@ -176,19 +179,19 @@ jobs:
"$HELM_CHART_YAML_FILE" \
"$HELM_README_FILE" \
"$CHANGELOG_FILE"
- exec_process git commit -m "[chore] Bump version to
${version_without_rc} for release candidate ${rc_number}"
+ exec_process git commit -m "[chore] Bump version to
${version_without_rc}"
# Push the changes
exec_process git push origin "${release_branch}"
- # Get the new commit SHA after our changes
- new_tag_ref=$(git rev-parse HEAD)
- echo "new_tag_ref=${new_tag_ref}" >> $GITHUB_ENV
-
- name: Create RC tag at new commit
run: |
source "${LIBS_DIR}/_exec.sh"
+ # Get the new commit SHA after our changes
+ new_tag_ref=$(git rev-parse HEAD)
+ echo "new_tag_ref=${new_tag_ref}" >> $GITHUB_ENV
+
# Create the tag at the new commit
exec_process git tag "${release_tag}" "${new_tag_ref}"
exec_process git push origin "${release_tag}"
diff --git a/.github/workflows/release-3-build-and-publish-artifacts.yml
b/.github/workflows/release-3-build-and-publish-artifacts.yml
index 3577a4cc8..0c759a0bb 100644
--- a/.github/workflows/release-3-build-and-publish-artifacts.yml
+++ b/.github/workflows/release-3-build-and-publish-artifacts.yml
@@ -73,8 +73,19 @@ jobs:
echo "## Parameters" >> $GITHUB_STEP_SUMMARY
- if ! git_tag=$(git describe --tags --exact-match HEAD 2>/dev/null);
then
- echo "❌ Current HEAD is not on a release candidate tag. Please
checkout a release candidate tag first." >> $GITHUB_STEP_SUMMARY
+ # Extract the ref name from github.ref
+ # github.ref format: refs/heads/branch-name or refs/tags/tag-name
+ ref="${{ github.ref }}"
+
+ if [[ "${ref}" =~ ^refs/tags/(.+)$ ]]; then
+ # Running from a tag
+ git_tag="${BASH_REMATCH[1]}"
+ else
+ echo "❌ Workflow must be run from a release candidate tag, not a
branch." >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "Current ref: \`${ref}\`" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "Please select a release candidate tag (e.g.,
\`apache-polaris-1.0.0-incubating-rc0\`) from the 'Use workflow from' dropdown
in the GitHub UI." >> $GITHUB_STEP_SUMMARY
exit 1
fi
diff --git a/.github/workflows/release-4-publish-release.yml
b/.github/workflows/release-4-publish-release.yml
index 9e2750da0..36a0042fb 100644
--- a/.github/workflows/release-4-publish-release.yml
+++ b/.github/workflows/release-4-publish-release.yml
@@ -92,38 +92,38 @@ jobs:
run: |
source "${LIBS_DIR}/_version.sh"
- # Get the current branch name
- current_branch=$(git branch --show-current)
-
echo "## Parameters" >> $GITHUB_STEP_SUMMARY
- # Validate that we're on a release branch
- if [[ ! "${current_branch}" =~ ^release/(.+)$ ]]; then
- echo "❌ This workflow must be run from a release branch
(release/major.minor.x). Current branch: \`${current_branch}\`." >>
$GITHUB_STEP_SUMMARY
+ # Extract the ref name from github.ref
+ # github.ref format: refs/heads/branch-name or refs/tags/tag-name
+ ref="${{ github.ref }}"
+
+ if [[ "${ref}" =~ ^refs/heads/release/(.+)$ ]]; then
+ # Running from a release branch
+ branch_version="${BASH_REMATCH[1]}"
+ current_branch="release/${branch_version}"
+ else
+ echo "❌ This workflow must be run from a release branch
(release/major.minor.x)." >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "Current ref: \`${ref}\`" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "Please select a release branch (e.g., \`release/1.0.x\`)
from the 'Use workflow from' dropdown in the GitHub UI." >> $GITHUB_STEP_SUMMARY
exit 1
fi
- # Extract version from release branch name
- branch_version="${BASH_REMATCH[1]}"
-
# Validate branch version format and extract components
if ! validate_and_extract_branch_version "${branch_version}"; then
echo "❌ Invalid release branch version format:
\`${branch_version}\`. Expected format: major.minor.x." >> $GITHUB_STEP_SUMMARY
exit 1
fi
- # Find the next patch number for this major.minor version by looking
at existing tags
+ # Find the patch number for this major.minor version by looking at
existing tags
+ # Note: find_next_patch_number returns the current patch if no final
tag exists,
+ # which is exactly what we need for publishing (we publish from an
RC that has no final tag yet)
find_next_patch_number "${major}" "${minor}"
- next_patch=$((patch))
- latest_patch=$((next_patch - 1))
-
- if [[ ${next_patch} -eq 0 ]]; then
- echo "❌ No existing tags found for version
\`${major}.${minor}.0\`. Expected at least one RC to be created before
publishing a release." >> $GITHUB_STEP_SUMMARY
- exit 1
- fi
- # Build the version string for the latest existing patch
- version_without_rc="${major}.${minor}.${latest_patch}-incubating"
+ # Build the version string for the patch with RC tags
+ version_without_rc="${major}.${minor}.${patch}-incubating"
# Find the latest RC tag for this version
find_next_rc_number "${version_without_rc}"
@@ -142,6 +142,21 @@ jobs:
exit 1
fi
+ # Verify that current HEAD is at the RC tag commit
+ rc_commit=$(git rev-parse "${rc_tag}")
+ current_commit=$(git rev-parse HEAD)
+
+ if [[ "${current_commit}" != "${rc_commit}" ]]; then
+ echo "❌ Current HEAD (\`${current_commit}\`) does not match RC tag
\`${rc_tag}\` (\`${rc_commit}\`)." >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "This means that some commits have been made on the release
branch after the last RC was created." >> $GITHUB_STEP_SUMMARY
+ echo "You should not publish a release from a branch that has
received additional commits after the last RC was created." >>
$GITHUB_STEP_SUMMARY
+ echo "Either remove the commits from the release branch so that it
points to the last RC that was voted on, or create a new RC from the current
state of the branch." >> $GITHUB_STEP_SUMMARY
+ exit 1
+ fi
+
+ echo "✅ Current HEAD matches RC tag \`${rc_tag}\`" >>
$GITHUB_STEP_SUMMARY
+
# Create final release tag name
final_release_tag="apache-polaris-${version_without_rc}"
diff --git a/releasey/libs/_version.sh b/releasey/libs/_version.sh
index 7d812f130..d882af463 100644
--- a/releasey/libs/_version.sh
+++ b/releasey/libs/_version.sh
@@ -146,19 +146,23 @@ function find_next_patch_number {
# This function finds the next available patch number for a given
major.minor version.
# It returns 0 and sets the global variable patch to the next available
patch number.
# Patch numbers start from 0. It takes major and minor as input (e.g., "1",
"0").
+ #
+ # The patch number should only be incremented if there is a final release
tag (without -rc suffix)
+ # for the current highest patch. If only RC tags exist for the highest
patch, we should reuse
+ # that patch number (allowing for additional RCs like rc1, rc2, etc.).
local major="$1"
local minor="$2"
- # Get all existing tags for this major.minor version
- local tag_pattern="apache-polaris-${major}.${minor}.*-incubating-rc*"
- local existing_tags
- existing_tags=$(git tag -l "${tag_pattern}" | sort -V)
+ # Get all existing RC tags for this major.minor version
+ local rc_tag_pattern="apache-polaris-${major}.${minor}.*-incubating-rc*"
+ local existing_rc_tags
+ existing_rc_tags=$(git tag -l "${rc_tag_pattern}" | sort -V)
- if [[ -z "${existing_tags}" ]]; then
- # No existing tags, start with patch 0
+ if [[ -z "${existing_rc_tags}" ]]; then
+ # No existing RC tags, start with patch 0
patch=0
else
- # Extract all patch numbers and find the highest
+ # Extract all patch numbers from RC tags and find the highest
local highest_patch=-1
while IFS= read -r tag; do
if [[ ${tag} =~
apache-polaris-${major}\.${minor}\.([0-9]+)-incubating-rc[0-9]+ ]]; then
@@ -167,10 +171,17 @@ function find_next_patch_number {
highest_patch=${current_patch}
fi
fi
- done <<< "${existing_tags}"
-
- # Increment the highest patch number found
- patch=$((highest_patch + 1))
+ done <<< "${existing_rc_tags}"
+
+ # Check if a final release tag exists for the highest patch (without -rc
suffix)
+ local
final_tag="apache-polaris-${major}.${minor}.${highest_patch}-incubating"
+ if git rev-parse "${final_tag}" >/dev/null 2>&1; then
+ # Final release tag exists, increment to next patch number
+ patch=$((highest_patch + 1))
+ else
+ # No final release tag yet, reuse the same patch number for additional
RCs
+ patch=${highest_patch}
+ fi
fi
return 0
diff --git
a/site/content/community/release-guides/semi-automated-release-guide.md
b/site/content/community/release-guides/semi-automated-release-guide.md
index d59bdae49..5d85832ee 100644
--- a/site/content/community/release-guides/semi-automated-release-guide.md
+++ b/site/content/community/release-guides/semi-automated-release-guide.md
@@ -44,16 +44,17 @@ Polaris follows a schedule-driven release model. The first
thing to do is to sen
Note that the tentative date is only a suggestion. The actual date of the
release will be determined by taking community feedback into account. For
instance, if specific pull requests are about to be merged, the release may be
delayed by a couple of days to include them.
```
-[DISCUSS] Apache Polaris x.y.z
+[DISCUSS] Apache Polaris [major].[minor].[patch]
```
```
Hello everyone,
The purpose of this e-mail is to collect feedback on the upcoming Apache
-Polaris x.y.z release. The tentative release date is YYYY-MM-DD. Please let
-me know if you have any concerns or comments, or if there are some specific
-pull requests that you would like to see included in the release.
+Polaris [major].[minor].[patch] release. The tentative release date is
+YYYY-MM-DD. Please let me know if you have any concerns or comments, or if
+there are some specific pull requests that you would like to see included in
+the release.
Thanks,
```
@@ -71,17 +72,20 @@ Once the workflow has run, the run details page contains a
recap of the main inf

-## RC0 only - Changelog and version update workflow
+## Release candidate tag creation workflow
The second Github workflow to run is [`Release - 2 - Update version and
Changelog for Release
Candidate`](https://github.com/apache/polaris/actions/workflows/release-2-update-release-candidate.yml).
This workflow will:
* Verify that all Github checks are green for the release branch.
-* Increase the patch version number by 1 if the workflow has already been run
for that `major.minor` version.
-* Update the project version files with the final version number
-* Commit the changes to the release branch
-* Create the `major.minor.patch-rc0` tag
+* For RC0 only: update the project version files with the final version
number, update the changelog, and commit the changes to the release branch.
+* Create the `apache-polaris-[major].[minor].[patch]-incubating-rc[N]` tag
-This workflow can only be run from a `release/x.y.z` branch. Selecting any
other branch in the Github Actions UI will result in a failure.
+The rules to create the `[major].[minor].[patch]-rc[N]` tag are as follows:
+* Find the last patch number for the `[major].[minor]` version by looking at
existing tags, or 0 if no tag exists.
+* Find the last RC number for the `[major].[minor].[patch]` version by looking
at existing tags, or 0 if no tag exists.
+* If a final release tag exists for the `[major].[minor].[patch]` version,
then use `[major].[minor].[patch+1]-rc0`
+* Else if an RC tag exists for the `[major].[minor].[patch]-rc[N]` version,
then create `[major].[minor].[patch]-rc[N+1]`
+* Else create `[major].[minor].[patch]-rc0`
-Note that the tag that is created is for RC0. This workflow should **only be
executed only once** per `major.minor.patch` version.
+This workflow can only be run from a `release/[major].[minor].x` branch.
Selecting any other branch in the Github Actions UI will result in a failure.

@@ -90,22 +94,11 @@ Like for the other workflow runs, the run details page
contains a recap of the m

## RC≥1 only - Update release branch and create tag
-If the first release candidate is rejected, additional code changes may be
needed. These steps have not been automated yet.
+If the first release candidate is rejected, additional code changes may be
needed.
Each code change that should be added to the release branch must be
cherry-picked from the main branch and proposed in a dedicated pull request.
The pull request must be reviewed and approved before being merged. This step
is mandatory so that Github runs the CI checks. The subsequent workflows will
verify that those checks passed.
-Once the pull requests have been merged, create a new
`apache-polaris-[major].[minor].[patch]-incubating-rc[N]` tag. The commands
below assume that the `apache/polaris` Git repository corresponds to the
`apache` remote.
-
-```bash
-# Ensure you're on the correct release branch and have the latest changes
-git fetch apache
-git checkout release/[major].[minor].x
-git pull apache release/[major].[minor].x
-
-# Create and push the release candidate tag
-git tag -a apache-polaris-[major].[minor].[patch]-incubating-rc[N] -m "Apache
Polaris [major].[minor].[patch] (incubating) release candidate [N]"
-git push apache apache-polaris-[major].[minor].[patch]-incubating-rc[N]
-```
+Once the pull requests have been merged, run the second workflow again to
create a new RC tag. The workflow will automatically determine the next RC
number.
## Build and publish release artifacts
The third Github workflow to run is [`Release - 3 - Build and publish release
artifacts`](https://github.com/apache/polaris/actions/workflows/release-3-build-and-publish-artifacts.yml).
This workflow will:
@@ -118,7 +111,7 @@ The third Github workflow to run is [`Release - 3 - Build
and publish release ar
* Create signature and checksum for all package files
* Copy package files to Apache dist dev repository
-This workflow can only be run from a `release/x.y.z` branch. Selecting any
other branch in the Github Actions UI will result in a failure.
+This workflow must be run from an RC tag (e.g.,
`apache-polaris-1.3.0-incubating-rc0`). Select the tag from the `Use workflow
from` dropdown in the Github Actions UI. Selecting any other reference in the
Github Actions UI will result in a failure.

@@ -129,7 +122,7 @@ The last step for a release candidate is to create a VOTE
thread on the dev mail
Recommended title subject:
```
-[VOTE] Release Apache Polaris x.y.z (rci)
+[VOTE] Release Apache Polaris [major].[minor].[patch] (rc[N])
```
Recommended content:
@@ -137,18 +130,18 @@ Recommended content:
```
Hi everyone,
-I propose that we release the following RC as the official Apache Polaris x.y.z
+I propose that we release the following RC as the official Apache Polaris
[major].[minor].[patch]
release.
-* This corresponds to the tag: apache-polaris-x.y.z-incubating-rci
-* https://github.com/apache/polaris/commits/apache-polaris-x.y.z-incubating-rci
+* This corresponds to the tag:
apache-polaris-[major].[minor].[patch]-incubating-rc[N]
+*
https://github.com/apache/polaris/commits/apache-polaris-[major].[minor].[patch]-incubating-rc[N]
* https://github.com/apache/polaris/tree/<SHA1>
The release tarball, signature, and checksums are here:
-* https://dist.apache.org/repos/dist/dev/incubator/polaris/x.y.z-incubating
+*
https://dist.apache.org/repos/dist/dev/incubator/polaris/[major].[minor].[patch]-incubating
Helm charts are available on:
-*
https://dist.apache.org/repos/dist/dev/incubator/polaris/helm-chart/x.y.z-incubating/
+*
https://dist.apache.org/repos/dist/dev/incubator/polaris/helm-chart/[major].[minor].[patch]-incubating/
NB: you have to build the Docker images locally in order to test Helm charts.
@@ -164,7 +157,7 @@ https://polaris.apache.org/community/release-verify/.
Please vote in the next 72 hours.
-[ ] +1 Release this as Apache polaris x.y.z
+[ ] +1 Release this as Apache polaris [major].[minor].[patch]
[ ] +0
[ ] -1 Do not release this because...
@@ -183,13 +176,13 @@ The next steps depend on the vote result.
When a release candidate is rejected, reply with the vote result:
```
-[RESULT][VOTE] Release Apache Polaris x.y.z (rci)
+[RESULT][VOTE] Release Apache Polaris [major].[minor].[patch] (rc[N])
```
```
Hello everyone,
-Thanks to all who participated in the vote for Release Apache Polaris x.y.z
(rci).
+Thanks to all who participated in the vote for Release Apache Polaris
[major].[minor].[patch] (rc[N]).
The vote failed due to [reason].
@@ -202,11 +195,11 @@ Thanks,
When the release candidate vote passes, send a new e-mail with the vote result:
```
-[RESULT][VOTE] Release Apache Polaris x.y.z (rci)
+[RESULT][VOTE] Release Apache Polaris [major].[minor].[patch] (rc[N])
```
```
-Thanks everyone who participated in the vote for Release Apache Polaris x.y.z
(rci).
+Thanks everyone who participated in the vote for Release Apache Polaris
[major].[minor].[patch] (rc[N]).
The vote result is:
@@ -223,13 +216,13 @@ As Polaris is an Apache Incubator project, you now have
to start a new vote on t
You have to send this email to [email protected]:
```
-[VOTE] Release Apache Polaris x.y.z (rci)
+[VOTE] Release Apache Polaris [major].[minor].[patch] (rc[N])
```
```
Hello everyone,
-The Apache Polaris community has voted and approved the release of Apache
Polaris x.y.z (rci).
+The Apache Polaris community has voted and approved the release of Apache
Polaris [major].[minor].[patch] (rc[N]).
We now kindly request the IPMC members review and vote for this release.
Polaris community vote thread:
@@ -238,12 +231,12 @@ Polaris community vote thread:
Vote result thread:
* https://lists.apache.org/thread/<VOTE RESULT>
-* This corresponds to the tag: apache-polaris-x.y.z-rci
-* https://github.com/apache/polaris/commits/apache-polaris-x.y.z-rci
+* This corresponds to the tag:
apache-polaris-[major].[minor].[patch]-incubating-rc[N]
+*
https://github.com/apache/polaris/commits/apache-polaris-[major].[minor].[patch]-rc[N]
* https://github.com/apache/polaris/tree/<SHA1>
The release tarball, signature, and checksums are here:
-* https://dist.apache.org/repos/dist/dev/incubator/polaris/x.y.z
+*
https://dist.apache.org/repos/dist/dev/incubator/polaris/[major].[minor].[patch]
Helm charts are available on:
* https://dist.apache.org/repos/dist/dev/incubator/polaris/helm-chart
@@ -286,7 +279,7 @@ When a release candidate is rejected, reply in the same
thread with the vote res
```
Hello everyone,
-Thanks to all who participated in the vote for Release Apache Polaris x.y.z
(rci).
+Thanks to all who participated in the vote for Release Apache Polaris
[major].[minor].[patch] (rc[N]).
The vote failed due to [reason].
@@ -297,13 +290,13 @@ Thanks,
When the release candidate vote passes, send a new e-mail with the vote result:
```
-[RESULT][VOTE] Release Apache Polaris x.y.z (rci)
+[RESULT][VOTE] Release Apache Polaris [major].[minor].[patch] (rc[N])
```
```
Hello everyone,
-The vote to release Apache Polaris x.y.z (rci) has passed with [N] +1 binding
and [M] +1 non-binding votes.
+The vote to release Apache Polaris [major].[minor].[patch] (rc[N]) has passed
with [N] +1 binding and [M] +1 non-binding votes.
Binding +1 votes:
* [NAME]
@@ -322,6 +315,7 @@ We will proceed with publishing the approved artifacts and
sending out the annou
## Publish the release
The final workflow to run is [`Release - 4 - Publish Release After Vote
Success`](https://github.com/apache/polaris/actions/workflows/release-4-publish-release.yml).
This workflow will:
+* Verify that the release branch HEAD matches the last RC tag
* Copy artifacts from the dist dev to the dist release SVN repository
* Update the Helm index in dist release repository accordingly
* Create a final release tag
@@ -329,7 +323,7 @@ The final workflow to run is [`Release - 4 - Publish
Release After Vote Success`
* Create a Github release with the release artifacts
* Release the candidate repository on Apache Nexus
-This workflow can only be run from the `release/x.y.z` branch for which a vote
has passed. It also requires the Nexus staging repository id
(`orgapachepolaris-<ID>`) that was created by the previous workflow.
+This workflow can only be run from the `release/[major].[minor].x` branch for
which a vote has passed. The workflow verifies that no commits have been added
to the release branch since the last RC was created. It also requires the Nexus
staging repository id (`orgapachepolaris-<ID>`) that was created by the
previous workflow.

diff --git a/site/static/img/release-guides/github-workflow-3.png
b/site/static/img/release-guides/github-workflow-3.png
index d8e0e1c0e..3385f4b02 100644
Binary files a/site/static/img/release-guides/github-workflow-3.png and
b/site/static/img/release-guides/github-workflow-3.png differ