1- # Ensures package.json and CHANGELOG.md are bumped when merging to release branch (master/main) .
2- # Runs only on PRs targeting master or main (e.g. development → master) .
1+ # Catches when developers forget to add a version bump for their changes .
2+ # Code changes (e.g. lib/) require package.json + CHANGELOG.md; test-only or comment-only in lib/ skip .
33name : Check Version Bump
44
55on :
66 pull_request :
7- branches :
8- - master
9- - main
10- - development
117
128jobs :
139 version-bump :
@@ -19,36 +15,45 @@ jobs:
1915 with :
2016 fetch-depth : 0
2117
18+ - name : Detect changed files and version bump
19+ id : detect
20+ run : |
21+ if git rev-parse HEAD^2 >/dev/null 2>&1; then
22+ FILES=$(git diff --name-only HEAD^1 HEAD^2)
23+ else
24+ FILES=$(git diff --name-only HEAD~1 HEAD)
25+ fi
26+ VERSION_FILES_CHANGED=false
27+ echo "$FILES" | grep -qx 'package.json' && VERSION_FILES_CHANGED=true
28+ echo "$FILES" | grep -qx 'CHANGELOG.md' && VERSION_FILES_CHANGED=true
29+ echo "version_files_changed=$VERSION_FILES_CHANGED" >> $GITHUB_OUTPUT
30+ CODE_CHANGED=false
31+ echo "$FILES" | grep -qE '^lib/|^webpack/|^dist/' && CODE_CHANGED=true
32+ echo "$FILES" | grep -qx 'package.json' && CODE_CHANGED=true
33+ echo "code_changed=$CODE_CHANGED" >> $GITHUB_OUTPUT
34+
35+ - name : Skip when only test/docs/config changed
36+ if : steps.detect.outputs.code_changed != 'true'
37+ run : |
38+ echo "No release-affecting files changed (e.g. only test/docs). Skipping version-bump check."
39+ exit 0
40+
41+ - name : Fail when version bump was missed
42+ if : steps.detect.outputs.code_changed == 'true' && steps.detect.outputs.version_files_changed != 'true'
43+ run : |
44+ echo "::error::This PR has code changes but no version bump. Please bump the version in package.json and add an entry in CHANGELOG.md."
45+ exit 1
46+
2247 - name : Setup Node
48+ if : steps.detect.outputs.code_changed == 'true' && steps.detect.outputs.version_files_changed == 'true'
2349 uses : actions/setup-node@v4
2450 with :
2551 node-version : ' 22.x'
2652
2753 - name : Check version bump
28- env :
29- BASE_SHA : ${{ github.event.pull_request.base.sha }}
54+ if : steps.detect.outputs.code_changed == 'true' && steps.detect.outputs.version_files_changed == 'true'
3055 run : |
3156 set -e
32- # Skip version bump check when only test/docs/config files changed (no production code)
33- if [ -n "$BASE_SHA" ]; then
34- CHANGED=$(git diff --name-only "$BASE_SHA" HEAD 2>/dev/null || true)
35- PROD_CHANGES=$(echo "$CHANGED" | grep -v -e '^test/' -e '^package\.json$' -e '^CHANGELOG\.md$' -e '^\.github/' -e '^README' -e '^\.' -e '^docs/' -e '^jest\.config' -e '^\.eslintrc' -e '^\.prettierrc' || true)
36- PROD_CHANGES=$(echo "$PROD_CHANGES" | sed '/^$/d')
37- if [ -z "$PROD_CHANGES" ]; then
38- echo "Only test/docs/config files changed. Skipping version bump check."
39- exit 0
40- fi
41- # Skip when only comments changed in production files (//, /*, *, */, #)
42- if git diff "$BASE_SHA" HEAD | node -e "
43- const lines = require('fs').readFileSync(0,'utf8').split('\n').filter(l=>l.startsWith('+')||l.startsWith('-'));
44- const isComment = (s) => { const t=(s||'').slice(1).replace(/^\s+|\s+$/g,''); return !t || /^\/\//.test(t) || /^\/\*/.test(t) || /^\*\//.test(t) || /^\s*\*/.test(t) || /^#/.test(t); };
45- const hasCode = lines.some(l => !isComment(l));
46- process.exit(hasCode ? 1 : 0);
47- " 2>/dev/null; then
48- echo "Only comments changed in code. Skipping version bump check."
49- exit 0
50- fi
51- fi
5257 PKG_VERSION=$(node -p "require('./package.json').version.replace(/^v/, '')")
5358 if [ -z "$PKG_VERSION" ]; then
5459 echo "::error::Could not read version from package.json"
0 commit comments