From 72a698dfe29a0c972c83c6aa58e68b5e4050f446 Mon Sep 17 00:00:00 2001 From: Chris Coutinho Date: Wed, 3 Jun 2026 02:19:26 +0200 Subject: [PATCH] ci: serialize bump-version and gate releases on actual version bump Prevent concurrent version bumps and spurious releases in the release pipeline: - Add a workflow-level concurrency group (cancel-in-progress: false) so only one bump-version run executes at a time. Concurrent runs have previously raced to bump the version and push tags, causing release failures. Subsequent pushes now queue instead of cancelling an in-flight bump/release. - Make commitizen the single source of truth for whether a release is warranted. The previous grep heuristic counted commits matching feat|fix|docs|refactor|perf|test|build|ci|chore, but commitizen only bumps for feat/fix/breaking changes. A CI- or docs-only push therefore set bumped=true and fired release+docker against the old, already released tag. Now we compare the latest tag before/after running bump-mcp.sh and only set bumped=true (and emit the new tag) when it actually changes, so release/docker exit early on non-release pushes. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/bump-version.yml | 40 ++++++++++++++++++------------ 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/.github/workflows/bump-version.yml b/.github/workflows/bump-version.yml index a8c95ad5..e2347b38 100644 --- a/.github/workflows/bump-version.yml +++ b/.github/workflows/bump-version.yml @@ -5,6 +5,13 @@ on: branches: - master +# Ensure only one version bump runs at a time. Concurrent runs would race to +# bump the version and push tags, which has caused release failures in the past. +# Queue subsequent pushes instead of cancelling an in-flight bump/release. +concurrency: + group: bump-version + cancel-in-progress: false + jobs: bump-version: if: "!startsWith(github.event.head_commit.message, 'bump:') && !startsWith(github.event.head_commit.message, 'chore(release):')" @@ -43,27 +50,28 @@ jobs: echo "Checking for version bump..." - # Get the most recent tag - last_tag=$(git tag --sort=-creatordate | grep -E "^v[0-9]" | head -n 1 || echo "") + # Record the current version tag before attempting a bump. commitizen + # is the single source of truth for whether a release is warranted: it + # only bumps for feat/fix/breaking changes and emits + # [NO_COMMITS_TO_BUMP] (exit 0) for release-irrelevant commits such as + # ci:, docs:, chore:, etc. We therefore let it decide and detect a + # release by whether the latest tag actually changed. + tag_before=$(git tag --sort=-creatordate | grep -E '^v[0-9]' | head -n 1 || echo "") + echo "Latest tag before bump: ${tag_before:-}" - if [ -z "$last_tag" ]; then - commit_range="master" - else - commit_range="${last_tag}..HEAD" - fi + # Run the bump. The script exits 0 both when it bumps and when there + # is nothing to bump, so we compare tags rather than trusting exit code. + ./scripts/bump-mcp.sh - # Count conventional commits - commit_count=$(git log "$commit_range" --oneline --grep="^(feat|fix|docs|refactor|perf|test|build|ci|chore)" -E | wc -l) + tag_after=$(git tag --sort=-creatordate | grep -E '^v[0-9]' | head -n 1 || echo "") + echo "Latest tag after bump: ${tag_after:-}" - if [ "$commit_count" -gt 0 ]; then - echo "Found $commit_count commits since $last_tag" - echo "Bumping version..." - ./scripts/bump-mcp.sh + if [ -n "$tag_after" ] && [ "$tag_after" != "$tag_before" ]; then + echo "Version bumped to $tag_after" echo "bumped=true" >> $GITHUB_OUTPUT - tag=$(git tag --sort=-creatordate | grep -E '^v[0-9]' | head -n 1) - echo "tag=$tag" >> $GITHUB_OUTPUT + echo "tag=$tag_after" >> $GITHUB_OUTPUT else - echo "No commits found since $last_tag" + echo "No version bump required (no release-relevant commits)" echo "bumped=false" >> $GITHUB_OUTPUT fi