diff --git a/bin/gstack-state-matrix b/bin/gstack-state-matrix index 1b5c9cfd9..f4d039b33 100755 --- a/bin/gstack-state-matrix +++ b/bin/gstack-state-matrix @@ -43,7 +43,7 @@ function detect(rest: string[]): number { const repoRoot = root.out.trim(); const base = resolveBaseBranch(repoRoot, flag(rest, '--base')); const mb = flag(rest, '--diff-base') ?? git(['merge-base', `origin/${base}`, 'HEAD'], repoRoot).out.trim(); - const diff = mb ? git(['diff', '--unified=0', '--no-color', mb], repoRoot) : { ok: false, out: '' }; + const diff = mb ? git(['-c', 'core.quotePath=false', 'diff', '--no-ext-diff', '--no-textconv', '--unified=0', '--no-color', mb], repoRoot) : { ok: false, out: '' }; if (!diff.ok) { process.stdout.write(`SCOPE_STATE_MACHINE=false\n# no merge base with origin/${base}; run: git fetch origin ${base}\n`); return EXIT.usage; } const { detected, hits } = detectStateMachine(addedLines(diff.out)); const lines = [`SCOPE_STATE_MACHINE=${detected}`, ...hits.slice(0, 12).map(h => `# state-machine: ${h.file}:${h.line} ${[...h.subject, ...h.action].join(',')}`)]; diff --git a/test/state-matrix.test.ts b/test/state-matrix.test.ts index e41b06b0a..59cab815a 100644 --- a/test/state-matrix.test.ts +++ b/test/state-matrix.test.ts @@ -47,6 +47,16 @@ describe('gstack-state-matrix detect', () => { expect(d.out.trim().split('\n').every(l => /^SCOPE_STATE_MACHINE=(true|false)$/.test(l) || l.startsWith('# '))).toBe(true); }); + test('review #3235 P1-4: diff.external and a textconv driver cannot hide the state machine from detect', () => { + const r = repo(); + r.git('config', 'diff.external', '/bin/true'); + expect(run(r.work, ['detect', '--base', 'main']).out.split('\n')[0]).toBe('SCOPE_STATE_MACHINE=true'); + r.git('config', '--unset', 'diff.external'); + fs.writeFileSync(path.join(r.work, '.git', 'info', 'attributes'), '*.ts diff=blank\n'); + r.git('config', 'diff.blank.textconv', 'true'); + expect(run(r.work, ['detect', '--base', 'main']).out.split('\n')[0]).toBe('SCOPE_STATE_MACHINE=true'); + }); + test('negative controls: a test-only change and words that merely contain "hold" or "accept" do not dispatch', () => { const r = repo(); r.git('checkout', '-q', '-b', 'unrelated', 'origin/main');