diff --git a/.github/workflows/auto-backmerge.yml b/.github/workflows/auto-backmerge.yml index a13361562..3548234c5 100644 --- a/.github/workflows/auto-backmerge.yml +++ b/.github/workflows/auto-backmerge.yml @@ -108,6 +108,27 @@ jobs: NEXT_CODE=$(git diff --name-only "$BASE" origin/next -- . ':(exclude)CHANGELOG.md' ':(exclude).changeset' | sort) DROPPED=$(comm -23 <(printf '%s\n' "$MAIN_CODE") <(printf '%s\n' "$NEXT_CODE") | grep -v '^$' || true) + # The version-bearing manifests diverge every release by design (next + # runs a -dev version). A drop whose main-vs-base diff touches ONLY + # "version" lines is just the release stamp, not a straight-to-main + # fix — parking on it is what lets the back-merge sit and go stale, so + # filter those out. A substantive change still parks: it leaves + # non-"version" lines (deps in package.json; resolved/integrity in the + # lockfile when a dependency actually changes). + VERSION_STAMP_MANIFESTS='package.json package-lock.json .claude-plugin/plugin.json gemini-extension.json' + DROPPED=$(printf '%s\n' "$DROPPED" | while IFS= read -r f; do + [ -n "$f" ] || continue + case " $VERSION_STAMP_MANIFESTS " in + *" $f "*) + changed=$(git diff "$BASE" origin/main -- "$f" | grep -E '^[+-]' | grep -vE '^[+-]{3} ' || true) + if [ -z "$(printf '%s\n' "$changed" | grep -vE '^[+-][[:space:]]*"version":' || true)" ]; then + continue + fi + ;; + esac + printf '%s\n' "$f" + done | grep -v '^$' || true) + git commit -m "chore: back-merge main into next (${SHORT_SHA})" git push --force origin "$BR" diff --git a/tests/workflow-maintainer-skip.test.cjs b/tests/workflow-maintainer-skip.test.cjs index 8141e7855..7f87a1bb3 100644 --- a/tests/workflow-maintainer-skip.test.cjs +++ b/tests/workflow-maintainer-skip.test.cjs @@ -103,3 +103,33 @@ describe('Require Issue Link back-merge automation carve-out', () => { assert.match(workflow, /steps\.check\.outputs\.found == 'false'/); }); }); + +describe('Auto-backmerge needs_review version-manifest carve-out (#1404)', () => { + const workflow = readWorkflow('.github/workflows/auto-backmerge.yml'); + + test('all four version manifests are filtered via version-only detection', () => { + // package.json / package-lock.json / plugin.json / gemini-extension.json + // diverge every release; a drop that is ONLY "version" lines must not park + // (parking is what lets the back-merge go stale). A substantive change still + // parks. (#1404) + assert.ok( + workflow.includes("VERSION_STAMP_MANIFESTS='package.json package-lock.json .claude-plugin/plugin.json gemini-extension.json'"), + 'auto-backmerge.yml must version-only-filter all four version manifests' + ); + assert.ok( + workflow.includes(`grep -vE '^[+-][[:space:]]*"version":'`), + 'auto-backmerge.yml must filter version-only diffs via the "version" grep' + ); + }); + + test('package-lock.json is NOT blindly excluded (lockfile-only changes still park)', () => { + // A lockfile-only substantive change (e.g. npm audit fix) rewrites + // resolved/integrity lines, so version-only filtering lets it through to + // review rather than dropping it silently. Guard against regression to a + // blanket exclude. (#1404) + assert.ok( + !workflow.includes(":(exclude)package-lock.json"), + 'package-lock.json must not be globally excluded; rely on version-only filtering' + ); + }); +});