Skip to content

ci(release): add automatic cleanup of stale release branches#24

Merged
Xe merged 1 commit intomainfrom
Xe/fix-semantic-release-config
Jan 30, 2026
Merged

ci(release): add automatic cleanup of stale release branches#24
Xe merged 1 commit intomainfrom
Xe/fix-semantic-release-config

Conversation

@Xe
Copy link
Copy Markdown
Collaborator

@Xe Xe commented Jan 30, 2026

Summary

  • Adds cleanup step to release workflow to delete old release-* branches
  • Prevents accumulation of stale branches that break semantic-release

Details

The semantic-release configuration allows only 1-3 release branches, but stale release-* branches from previous release PRs were accumulating. This caused semantic-release to fail with "ERELEASEBRANCHES" errors.

The fix adds a cleanup step that runs at the end of the release workflow (even if earlier steps fail) and deletes all old release-* branches except the one just created.

Test plan

  • Code compiles with go build ./...
  • Code formatted with npm run format
  • Manual testing

Adds a cleanup step to the release workflow that automatically deletes
old release-* branches after creating a new release. This prevents
accumulation of stale branches that was causing semantic-release to
fail with "too many release branches" errors.

Assisted-by: GLM 4.7 via Claude Code
Signed-off-by: Xe Iaso <xe@tigrisdata.com>
Copilot AI review requested due to automatic review settings January 30, 2026 17:59
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds an automatic cleanup step to the release workflow that deletes old release-* branches to prevent accumulation of stale branches that can cause semantic-release to fail with "ERELEASEBRANCHES" errors. The cleanup runs at the end of the workflow using if: always() to ensure it executes even if earlier steps fail.

Changes:

  • Added a cleanup step at the end of the release workflow that fetches all release-* branches and deletes them except the current one
  • The step uses if: always() to run even on workflow failure

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Get all release branches except the current one
for branch in $(git ls-remote --heads origin "release-*" | awk '{print $2}' | sed 's|refs/heads/||' | grep -v "^${BRANCH_NAME}$"); do
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The BRANCH_NAME variable is not available in this step. BRANCH_NAME is defined in the "Create release branch and run semantic-release" step's script (line 41), but environment variables set within a step's run script are not automatically available to subsequent steps. This means the grep filter will not work correctly, and the script may attempt to delete the newly created branch.

To fix this, you need to export BRANCH_NAME as a step output in the previous step using GITHUB_OUTPUT, and then reference it in this step. Alternatively, you could recalculate the branch name in this step or use a different approach to identify which branch to keep.

Copilot uses AI. Check for mistakes.
--label "release"

- name: Clean up old release branches
if: always()
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cleanup step runs with if: always(), which means it executes even when the previous step fails. If the "Create release branch and run semantic-release" step fails before creating and pushing a release branch (e.g., during npm ci or semantic-release execution), this cleanup will still run and delete all existing release-* branches, potentially including branches with open PRs that haven't been merged yet.

Consider adding a condition to only run cleanup if a branch was successfully created and pushed, or add logic to preserve branches that have open PRs. You could check if the branch was pushed by verifying the exit status of line 56, or check for open PRs using the GitHub API before deleting branches.

Copilot uses AI. Check for mistakes.
Comment on lines +73 to +78
run: |
# Get all release branches except the current one
for branch in $(git ls-remote --heads origin "release-*" | awk '{print $2}' | sed 's|refs/heads/||' | grep -v "^${BRANCH_NAME}$"); do
echo "Deleting old release branch: ${branch}"
git push origin --delete "${branch}" || true
done
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cleanup script could potentially cause race conditions if multiple release workflows run concurrently. If two workflows are running simultaneously, they could both try to clean up the same branches, or one workflow's cleanup could delete the branch that the other workflow just created (especially given that BRANCH_NAME filtering won't work as currently implemented).

While workflow_dispatch typically prevents concurrent runs by default, consider adding a concurrency group to the workflow to ensure only one release workflow runs at a time, or add more robust synchronization logic to the cleanup step.

Copilot uses AI. Check for mistakes.
@Xe Xe merged commit 0383375 into main Jan 30, 2026
17 checks passed
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 6, 2026

🎉 This PR is included in version 0.6.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants