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 to be updated; test-only changes skip .
33name : Check Version Bump
44
55on :
66 pull_request :
7- branches :
8- - master
9- - main
10- - development
117
128jobs :
139 version-bump :
@@ -19,45 +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- # Use three-dot diff so we only see changes introduced by the PR branch (works with merge commit checkout)
33- DIFF_REF="${BASE_SHA}...HEAD"
34- if [ -n "$BASE_SHA" ] && git rev-parse --verify "$BASE_SHA" >/dev/null 2>&1; then
35- CHANGED=$(git diff --name-only "$DIFF_REF" 2>/dev/null || true)
36- 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)
37- PROD_CHANGES=$(echo "$PROD_CHANGES" | sed '/^$/d')
38- if [ -z "$PROD_CHANGES" ]; then
39- echo "Only test/docs/config files changed. Skipping version bump check."
40- exit 0
41- fi
42- # Skip when only comments changed (any file/folder): JS, HTML, shell, YAML, SQL, etc.
43- if git diff "$DIFF_REF" 2>/dev/null | node -e "
44- try {
45- const lines = require('fs').readFileSync(0,'utf8').split('\n').filter(l=>l.startsWith('+')||l.startsWith('-'));
46- const isComment = (s) => {
47- const t = (s||'').slice(1).replace(/^\s+|\s+$/g,'');
48- if (!t) return true;
49- return /^\/\//.test(t) || /^\/\*/.test(t) || /^\*\//.test(t) || /^\s*\*(\s|$)/.test(t) || /^#/.test(t)
50- || /^<!--/.test(t) || /^-->/.test(t) || /^\s*--(\s|$)/.test(t)
51- || /^\s*[\"\']\s*/.test(t) || /^;\s*/.test(t) || /^\s*%/.test(t)
52- || /^[\s*\-=]+$/.test(t);
53- };
54- process.exit(lines.length > 0 && !lines.some(l => !isComment(l)) ? 0 : 1);
55- } catch(e) { process.exit(1); }
56- " 2>/dev/null; then
57- echo "Only comments changed in code. Skipping version bump check."
58- exit 0
59- fi
60- fi
6157 PKG_VERSION=$(node -p "require('./package.json').version.replace(/^v/, '')")
6258 if [ -z "$PKG_VERSION" ]; then
6359 echo "::error::Could not read version from package.json"
0 commit comments