Skip to content

Workflow Cycle Prevention Fix

The project was experiencing excessive version releases due to a cyclic dependency between two GitHub workflows:

  1. smart-version-bump.yml - Triggers on main branch pushes
  2. sync-package-version.yml - Triggers on tag creation
  1. Main branch push → triggers smart-version-bump.yml
  2. Smart version bump creates tag and pushes commit → triggers sync-package-version.yml
  3. Sync workflow creates PR and merges back to main → potentially triggers step 1 again

This created a cycle where workflows would trigger each other, leading to multiple version releases.

Option 2: Conditional Approach with Safeguards

Section titled “Option 2: Conditional Approach with Safeguards”

Instead of removing the sync workflow entirely, we implemented comprehensive safeguards to prevent the cycle while maintaining both workflows for different scenarios.

1. Smart Version Bump Workflow (smart-version-bump.yml)

Section titled “1. Smart Version Bump Workflow (smart-version-bump.yml)”
on:
push:
branches: [main]
paths-ignore:
- '.github/**'
- 'docs/**'
- '*.md'
  • Prevents workflow from triggering on documentation or workflow file changes
Terminal window
# Check if the latest commit is a workflow-generated commit
LATEST_COMMIT_MSG=$(git log -1 --pretty=format:"%s")
if [[ "$LATEST_COMMIT_MSG" =~ ^chore:\ (bump\ version|sync\ package\.json\ version) ]] || [[ "$LATEST_COMMIT_MSG" =~ \[skip\ ci\] ]]; then
echo "🛑 Skipping version bump to prevent cycle"
exit 0
fi
  • Detects commits made by workflows and skips version bumping
concurrency:
group: version-bump-${{ github.ref }}
cancel-in-progress: false
  • Prevents multiple instances from running simultaneously

2. Sync Package Version Workflow (sync-package-version.yml)

Section titled “2. Sync Package Version Workflow (sync-package-version.yml)”
jobs:
check-sync-needed:
name: Check if version sync is needed
outputs:
sync_needed: ${{ steps.check.outputs.sync_needed }}
  • Adds a job that checks if sync is actually needed before running the main job
sync-package-version:
needs: check-sync-needed
if: needs.check-sync-needed.outputs.sync_needed == 'true'
  • Only runs the sync job if package.json version doesn’t match the tag
workflow_dispatch:
inputs:
tag:
description: 'Tag to sync (e.g., v1.2.3)'
required: true
type: string
  • Allows manual testing of the sync workflow
// Check if this tag was created very recently (potential race condition)
const tagDate = exec(`git log -1 --format=%ct ${tag} 2>/dev/null`);
const currentTime = Math.floor(Date.now() / 1000);
const tagAge = currentTime - parseInt(tagDate);
if (tagAge < 30) {
// Less than 30 seconds old
console.log('⏳ Waiting 30 seconds to ensure tag creation is complete...');
await new Promise((resolve) => setTimeout(resolve, 30000));
}
  • Adds a 30-second delay for very recent tags to prevent race conditions
Terminal window
git commit -m "chore: sync package.json version to ${version} [skip ci]
Automatically generated by tag ${tag}
This commit should not trigger additional workflows.
[skip ci]"
  • More aggressive use of [skip ci] to prevent workflow retriggering
  1. PR merged to main → Smart version bump workflow runs
  2. Smart version bump → Updates package.json and creates tag in single commit
  3. Tag creation → Sync workflow checks → Finds package.json already correct → Skips
  1. Manual tag creation (without package.json update) → Sync workflow runs
  2. Sync workflow → Creates PR with [skip ci] → Merges without retriggering version bump
  1. Workflow commit pushed → Smart version bump detects workflow pattern → Skips
  2. No additional version bumps triggered by workflow maintenance commits
  1. Prevents Cycles: Multiple safeguards prevent workflows from triggering each other
  2. Maintains Flexibility: Both workflows remain available for different scenarios
  3. Race Condition Protection: Timing delays and concurrency controls prevent conflicts
  4. Clear Separation: Primary vs fallback paths are well defined
  5. Testable: Manual triggers allow for testing workflow behavior

After deployment, monitor for:

  • Reduced frequency of version releases
  • No workflow-generated commits triggering additional bumps
  • Sync workflow skipping when not needed
  • Proper functioning of the primary smart version bump flow

If issues persist, the changes can be rolled back and we can implement Option 1 (removing the sync workflow entirely) as the sync functionality is now redundant with the smart version bump workflow.