* feat(ci): implement PR-based version bumps with docs sync Replace direct-push version bumping with PR-based workflow that respects branch protection rules and combines version updates with documentation sync. ## Changes ### New Workflow: post-merge-pr.yml - Creates automated PR for version bumps instead of pushing directly - Combines version bump with documentation sync in single PR - Respects branch protection rules (no bypass needed) - Follows semantic versioning based on commit message - Updates VERSION, package.json, and CHANGELOG.md - Labels PR for easy identification ### Workflow Behavior - Triggers on push to main (after PR merge) - Detects version bump type from commit message (feat/fix/breaking) - Creates branch: chore/version-docs-sync-TIMESTAMP - Commits version changes with [skip ci] to prevent loops - Creates PR with detailed description - Allows manual review before version is applied ### Benefits - ✅ Works with branch protection (no special permissions needed) - ✅ Combines version + docs in one reviewable PR - ✅ Maintains audit trail through PR process - ✅ Allows manual adjustments before merge - ✅ Prevents accidental version bumps - ✅ Clear separation of concerns ### Disabled - post-merge.yml → post-merge.yml.disabled (old direct-push workflow) ## Migration Notes Going forward: 1. Merge PR to main 2. Workflow creates version bump PR automatically 3. Review and merge version bump PR 4. Manually create GitHub release (or add release workflow later) This fixes the branch protection issues that were blocking automated version bumps. * chore: trigger CI checks * fix(ci): prevent version bump loop by checking PR labels Add PR label detection to prevent infinite loop: - Check if merged PR had 'version-bump' or 'automated' labels - Skip version bump workflow if labels are present - This prevents version bump PRs from triggering more version bump PRs Flow: 1. Regular PR merges → Creates version bump PR (with labels) 2. Version bump PR merges → Detects labels → Skips workflow ✅ This ensures only actual feature/fix PRs trigger version bumps.
170 lines
6.1 KiB
Text
170 lines
6.1 KiB
Text
name: Post-Merge Automation
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
workflow_dispatch:
|
|
inputs:
|
|
skip_version_bump:
|
|
description: 'Skip version bump (maintainer override)'
|
|
required: false
|
|
type: boolean
|
|
default: false
|
|
|
|
jobs:
|
|
check-trigger:
|
|
name: Check Trigger Type
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
should_bump: ${{ steps.check.outputs.should_bump }}
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 2
|
|
|
|
- name: Determine if version bump needed
|
|
id: check
|
|
run: |
|
|
COMMIT_MSG="${{ github.event.head_commit.message }}"
|
|
|
|
# Skip version bump commits to prevent loops
|
|
if echo "$COMMIT_MSG" | grep -qE "^\[skip ci\]|chore: bump version"; then
|
|
echo "should_bump=false" >> $GITHUB_OUTPUT
|
|
echo "Version bump commit detected - skipping to prevent loops"
|
|
else
|
|
echo "should_bump=true" >> $GITHUB_OUTPUT
|
|
echo "Will bump version based on commit message: $COMMIT_MSG"
|
|
fi
|
|
|
|
auto-version-bump:
|
|
name: Auto Version Bump
|
|
runs-on: ubuntu-latest
|
|
needs: check-trigger
|
|
if: |
|
|
needs.check-trigger.outputs.should_bump == 'true' &&
|
|
github.event.inputs.skip_version_bump != 'true'
|
|
permissions:
|
|
contents: write
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
token: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '20'
|
|
|
|
- name: Configure Git
|
|
run: |
|
|
git config user.name "github-actions[bot]"
|
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
|
|
- name: Determine version bump type
|
|
id: bump-type
|
|
run: |
|
|
# Get the last commit message
|
|
COMMIT_MSG=$(git log -1 --pretty=%B)
|
|
|
|
# Determine bump type from commit message
|
|
if echo "$COMMIT_MSG" | grep -qiE "^(feat|feature)\(.*\)!:|^BREAKING CHANGE:|^[a-z]+!:"; then
|
|
echo "type=major" >> $GITHUB_OUTPUT
|
|
echo "Detected BREAKING CHANGE - bumping major version"
|
|
elif echo "$COMMIT_MSG" | grep -qiE "^(feat|feature)(\(.*\))?:"; then
|
|
echo "type=minor" >> $GITHUB_OUTPUT
|
|
echo "Detected feature - bumping minor version"
|
|
elif echo "$COMMIT_MSG" | grep -qiE "^(fix|bugfix)(\(.*\))?:"; then
|
|
echo "type=patch" >> $GITHUB_OUTPUT
|
|
echo "Detected fix - bumping patch version"
|
|
elif echo "$COMMIT_MSG" | grep -qiE "^\[alpha\]"; then
|
|
echo "type=alpha" >> $GITHUB_OUTPUT
|
|
echo "Detected [alpha] tag - bumping alpha version"
|
|
elif echo "$COMMIT_MSG" | grep -qiE "^\[beta\]"; then
|
|
echo "type=beta" >> $GITHUB_OUTPUT
|
|
echo "Detected [beta] tag - bumping beta version"
|
|
elif echo "$COMMIT_MSG" | grep -qiE "^\[rc\]"; then
|
|
echo "type=rc" >> $GITHUB_OUTPUT
|
|
echo "Detected [rc] tag - bumping rc version"
|
|
else
|
|
echo "type=patch" >> $GITHUB_OUTPUT
|
|
echo "No specific type detected - defaulting to patch version bump"
|
|
fi
|
|
|
|
- name: Bump version
|
|
run: |
|
|
BUMP_TYPE="${{ steps.bump-type.outputs.type }}"
|
|
|
|
# Get current version
|
|
CURRENT_VERSION=$(cat VERSION)
|
|
echo "Current version: $CURRENT_VERSION"
|
|
|
|
# Bump version in package.json
|
|
npm run version:bump:$BUMP_TYPE
|
|
|
|
# Get new version
|
|
NEW_VERSION=$(cat VERSION)
|
|
echo "New version: $NEW_VERSION"
|
|
|
|
# Update CHANGELOG.md
|
|
DATE=$(date +%Y-%m-%d)
|
|
# Get only the first line (title) of commit message to avoid multiline issues
|
|
COMMIT_TITLE=$(git log -1 --pretty=%s)
|
|
|
|
# Create changelog entry (use printf to avoid heredoc issues)
|
|
printf "## [%s] - %s\n\n### Changes\n- %s\n\n" "$NEW_VERSION" "$DATE" "$COMMIT_TITLE" > /tmp/changelog_entry.md
|
|
|
|
# Prepend to CHANGELOG.md (after the header)
|
|
if [ -f CHANGELOG.md ]; then
|
|
# Insert after the first occurrence of "## ["
|
|
awk '/^## \[/ && !found {print; system("cat /tmp/changelog_entry.md"); found=1; next} 1' CHANGELOG.md > /tmp/changelog_new.md
|
|
mv /tmp/changelog_new.md CHANGELOG.md
|
|
fi
|
|
|
|
- name: Commit version bump
|
|
run: |
|
|
NEW_VERSION=$(cat VERSION)
|
|
|
|
git add VERSION package.json CHANGELOG.md
|
|
git commit -m "chore: bump version to v$NEW_VERSION [skip ci]"
|
|
git tag "v$NEW_VERSION"
|
|
|
|
- name: Push changes
|
|
run: |
|
|
git push origin main --tags
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Create GitHub Release
|
|
run: |
|
|
NEW_VERSION=$(cat VERSION)
|
|
|
|
# Extract changelog entry for this version
|
|
RELEASE_NOTES=$(awk '/^## \['"$NEW_VERSION"'\]/{flag=1; next} /^## \[/{flag=0} flag' CHANGELOG.md)
|
|
|
|
# If no specific notes found, use commit message
|
|
if [ -z "$RELEASE_NOTES" ]; then
|
|
RELEASE_NOTES="Release v$NEW_VERSION"
|
|
fi
|
|
|
|
# Create the release
|
|
gh release create "v$NEW_VERSION" \
|
|
--title "v$NEW_VERSION" \
|
|
--notes "$RELEASE_NOTES" \
|
|
--latest
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Summary
|
|
if: success()
|
|
run: |
|
|
NEW_VERSION=$(cat VERSION)
|
|
echo "## 🚀 Version Bumped to v$NEW_VERSION" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "- ✅ Version updated in VERSION and package.json" >> $GITHUB_STEP_SUMMARY
|
|
echo "- ✅ CHANGELOG.md updated" >> $GITHUB_STEP_SUMMARY
|
|
echo "- ✅ Git tag created: v$NEW_VERSION" >> $GITHUB_STEP_SUMMARY
|
|
echo "- ✅ GitHub release published" >> $GITHUB_STEP_SUMMARY
|