-
Notifications
You must be signed in to change notification settings - Fork 5
feat: support version bump from tags to prevent race conditions #416
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- Add tag detection and branch preparation step - Implement automatic rebase when main has moved ahead - Split commit and push into separate steps for proper rebase flow - Add comprehensive error handling with clear user guidance - Maintain full backward compatibility with branch-based workflow - Update documentation and examples for tag-based usage Allows workflows to run from git tags, locking version bump to specific commits and preventing race conditions when PRs are merged during release. When main has moved ahead, automatically rebases version bump onto latest.
|
|
1 similar comment
|
|
| run: | | ||
| set -e | ||
| # Detect execution context | ||
| if ! git symbolic-ref -q HEAD > /dev/null; then | ||
| echo "::notice::Detached HEAD detected - running from tag" | ||
| IS_TAG_TRIGGER=true | ||
| TAG_COMMIT=$(git rev-parse HEAD) | ||
| echo "tag-commit=${TAG_COMMIT}" >> $GITHUB_ENV | ||
| else | ||
| CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) | ||
| echo "::notice::Running from branch: ${CURRENT_BRANCH}" | ||
| IS_TAG_TRIGGER=false | ||
| fi | ||
| echo "is-tag-trigger=${IS_TAG_TRIGGER}" >> $GITHUB_ENV | ||
| # Fetch latest remote state | ||
| echo "Fetching latest main from remote..." | ||
| git fetch origin main:refs/remotes/origin/main | ||
| REMOTE_MAIN_SHA=$(git rev-parse origin/main) | ||
| echo "remote-main-sha=${REMOTE_MAIN_SHA}" >> $GITHUB_ENV | ||
| # Handle tag trigger | ||
| if [ "$IS_TAG_TRIGGER" = "true" ]; then | ||
| echo "::group::Tag-based workflow preparation" | ||
| echo "Tag points to: ${TAG_COMMIT}" | ||
| echo "Remote main at: ${REMOTE_MAIN_SHA}" | ||
| # Validate tag is in main history | ||
| if ! git merge-base --is-ancestor "${TAG_COMMIT}" "${REMOTE_MAIN_SHA}"; then | ||
| echo "::error::Tag commit ${TAG_COMMIT} is not in main branch history" | ||
| echo "::error::The tag must point to a commit that exists in the main branch" | ||
| exit 1 | ||
| fi | ||
| # Create local main branch from tag commit | ||
| git checkout -B main "${TAG_COMMIT}" | ||
| echo "::notice::Created local main branch at tag commit" | ||
| # Check if rebase will be needed | ||
| if [ "${TAG_COMMIT}" != "${REMOTE_MAIN_SHA}" ]; then | ||
| echo "::warning::Main has moved ahead since tag was created" | ||
| echo "::warning::Version bump will be rebased onto latest main before pushing" | ||
| echo "needs-rebase=true" >> $GITHUB_ENV | ||
| # Calculate commits that will be rebased over | ||
| COMMITS_AHEAD=$(git rev-list --count ${TAG_COMMIT}..${REMOTE_MAIN_SHA}) | ||
| echo "::notice::Main is ${COMMITS_AHEAD} commit(s) ahead" | ||
| else | ||
| echo "::notice::Tag is at main HEAD - fast-forward push" | ||
| echo "needs-rebase=false" >> $GITHUB_ENV | ||
| fi | ||
| echo "::endgroup::" | ||
| else | ||
| # Running from branch - validate | ||
| CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) | ||
| if [ "${CURRENT_BRANCH}" != "main" ]; then | ||
| echo "::error::Running from branch '${CURRENT_BRANCH}' but expected 'main'" | ||
| echo "::error::This action must be run from main branch or from a tag" | ||
| exit 1 | ||
| fi | ||
| echo "needs-rebase=false" >> $GITHUB_ENV | ||
| fi |
Check failure
Code scanning / zizmor
dangerous use of environment file Error
| run: | | ||
| set -e | ||
| # Detect execution context | ||
| if ! git symbolic-ref -q HEAD > /dev/null; then | ||
| echo "::notice::Detached HEAD detected - running from tag" | ||
| IS_TAG_TRIGGER=true | ||
| TAG_COMMIT=$(git rev-parse HEAD) | ||
| echo "tag-commit=${TAG_COMMIT}" >> $GITHUB_ENV | ||
| else | ||
| CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) | ||
| echo "::notice::Running from branch: ${CURRENT_BRANCH}" | ||
| IS_TAG_TRIGGER=false | ||
| fi | ||
| echo "is-tag-trigger=${IS_TAG_TRIGGER}" >> $GITHUB_ENV | ||
| # Fetch latest remote state | ||
| echo "Fetching latest main from remote..." | ||
| git fetch origin main:refs/remotes/origin/main | ||
| REMOTE_MAIN_SHA=$(git rev-parse origin/main) | ||
| echo "remote-main-sha=${REMOTE_MAIN_SHA}" >> $GITHUB_ENV | ||
| # Handle tag trigger | ||
| if [ "$IS_TAG_TRIGGER" = "true" ]; then | ||
| echo "::group::Tag-based workflow preparation" | ||
| echo "Tag points to: ${TAG_COMMIT}" | ||
| echo "Remote main at: ${REMOTE_MAIN_SHA}" | ||
| # Validate tag is in main history | ||
| if ! git merge-base --is-ancestor "${TAG_COMMIT}" "${REMOTE_MAIN_SHA}"; then | ||
| echo "::error::Tag commit ${TAG_COMMIT} is not in main branch history" | ||
| echo "::error::The tag must point to a commit that exists in the main branch" | ||
| exit 1 | ||
| fi | ||
| # Create local main branch from tag commit | ||
| git checkout -B main "${TAG_COMMIT}" | ||
| echo "::notice::Created local main branch at tag commit" | ||
| # Check if rebase will be needed | ||
| if [ "${TAG_COMMIT}" != "${REMOTE_MAIN_SHA}" ]; then | ||
| echo "::warning::Main has moved ahead since tag was created" | ||
| echo "::warning::Version bump will be rebased onto latest main before pushing" | ||
| echo "needs-rebase=true" >> $GITHUB_ENV | ||
| # Calculate commits that will be rebased over | ||
| COMMITS_AHEAD=$(git rev-list --count ${TAG_COMMIT}..${REMOTE_MAIN_SHA}) | ||
| echo "::notice::Main is ${COMMITS_AHEAD} commit(s) ahead" | ||
| else | ||
| echo "::notice::Tag is at main HEAD - fast-forward push" | ||
| echo "needs-rebase=false" >> $GITHUB_ENV | ||
| fi | ||
| echo "::endgroup::" | ||
| else | ||
| # Running from branch - validate | ||
| CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) | ||
| if [ "${CURRENT_BRANCH}" != "main" ]; then | ||
| echo "::error::Running from branch '${CURRENT_BRANCH}' but expected 'main'" | ||
| echo "::error::This action must be run from main branch or from a tag" | ||
| exit 1 | ||
| fi | ||
| echo "needs-rebase=false" >> $GITHUB_ENV | ||
| fi |
Check failure
Code scanning / zizmor
dangerous use of environment file Error
| run: | | ||
| set -e | ||
| # Detect execution context | ||
| if ! git symbolic-ref -q HEAD > /dev/null; then | ||
| echo "::notice::Detached HEAD detected - running from tag" | ||
| IS_TAG_TRIGGER=true | ||
| TAG_COMMIT=$(git rev-parse HEAD) | ||
| echo "tag-commit=${TAG_COMMIT}" >> $GITHUB_ENV | ||
| else | ||
| CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) | ||
| echo "::notice::Running from branch: ${CURRENT_BRANCH}" | ||
| IS_TAG_TRIGGER=false | ||
| fi | ||
| echo "is-tag-trigger=${IS_TAG_TRIGGER}" >> $GITHUB_ENV | ||
| # Fetch latest remote state | ||
| echo "Fetching latest main from remote..." | ||
| git fetch origin main:refs/remotes/origin/main | ||
| REMOTE_MAIN_SHA=$(git rev-parse origin/main) | ||
| echo "remote-main-sha=${REMOTE_MAIN_SHA}" >> $GITHUB_ENV | ||
| # Handle tag trigger | ||
| if [ "$IS_TAG_TRIGGER" = "true" ]; then | ||
| echo "::group::Tag-based workflow preparation" | ||
| echo "Tag points to: ${TAG_COMMIT}" | ||
| echo "Remote main at: ${REMOTE_MAIN_SHA}" | ||
| # Validate tag is in main history | ||
| if ! git merge-base --is-ancestor "${TAG_COMMIT}" "${REMOTE_MAIN_SHA}"; then | ||
| echo "::error::Tag commit ${TAG_COMMIT} is not in main branch history" | ||
| echo "::error::The tag must point to a commit that exists in the main branch" | ||
| exit 1 | ||
| fi | ||
| # Create local main branch from tag commit | ||
| git checkout -B main "${TAG_COMMIT}" | ||
| echo "::notice::Created local main branch at tag commit" | ||
| # Check if rebase will be needed | ||
| if [ "${TAG_COMMIT}" != "${REMOTE_MAIN_SHA}" ]; then | ||
| echo "::warning::Main has moved ahead since tag was created" | ||
| echo "::warning::Version bump will be rebased onto latest main before pushing" | ||
| echo "needs-rebase=true" >> $GITHUB_ENV | ||
| # Calculate commits that will be rebased over | ||
| COMMITS_AHEAD=$(git rev-list --count ${TAG_COMMIT}..${REMOTE_MAIN_SHA}) | ||
| echo "::notice::Main is ${COMMITS_AHEAD} commit(s) ahead" | ||
| else | ||
| echo "::notice::Tag is at main HEAD - fast-forward push" | ||
| echo "needs-rebase=false" >> $GITHUB_ENV | ||
| fi | ||
| echo "::endgroup::" | ||
| else | ||
| # Running from branch - validate | ||
| CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) | ||
| if [ "${CURRENT_BRANCH}" != "main" ]; then | ||
| echo "::error::Running from branch '${CURRENT_BRANCH}' but expected 'main'" | ||
| echo "::error::This action must be run from main branch or from a tag" | ||
| exit 1 | ||
| fi | ||
| echo "needs-rebase=false" >> $GITHUB_ENV | ||
| fi |
Check failure
Code scanning / zizmor
dangerous use of environment file Error
|
😢 zizmor failed with exit code 14. Expand for full output |
Fixes: #403
Allows workflows to run from git tags, locking version bump to specific commits and preventing race conditions when PRs are merged during release. When main has moved ahead, automatically rebases version bump onto latest.