diff --git a/CHANGELOG.md b/CHANGELOG.md index 048a4deff..370cb89b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ ### Tests - `test/changelog-fragments.test.ts`: blob-only reads and refusals, bump precedence, fold order with a legacy section, the restamp fold and its tree receipt, an edited fold refused. -- `test/ship-queue-land.test.ts` (bare origin and a gh shim): happy path; two PRs from one base without a collision; a legacy stamp plus a dependency edit; a title-derived entry; a product conflict; the lock and `--break-lock`; the base moving during CI; a foreign push never overwritten; a missing receipt; drift, `--repair` and the lock release; the census; a receipt that fails #3567's depth check refuses. +- `test/ship-queue-land.test.ts` (bare origin and a gh shim): happy path; two PRs from one base without a collision; a legacy stamp plus a dependency edit; a title-derived entry; a product conflict; the lock and `--break-lock`; the base moving during CI; a foreign push never overwritten; a missing receipt; drift, `--repair` and the lock release; the census; a receipt that fails #3567's depth check refuses; a base with a four-part package.json in `stamp_files` lands four parts (#3557), gstack's own shape stays three. - `test/version-gate-fragments.test.ts`: fragment heads, premature version changes, a bot author, an advanced base, an invalid fragment, the stamp commit's effective bump, and the workflow's missing path filter. - `test/restamp-command-boundary.test.ts`: the hook reads its counter from `GSTACK_RESTAMP_BASE_SHA`, not the branch. diff --git a/test/ship-queue-land.test.ts b/test/ship-queue-land.test.ts index 335a19f58..3773239ec 100644 --- a/test/ship-queue-land.test.ts +++ b/test/ship-queue-land.test.ts @@ -246,6 +246,32 @@ describe('land: lock, races and refusals', () => { }, 90_000); }); +describe('land: the base\'s manifest part count', () => { + test('a repo whose base holds a four-part package.json listed in stamp_files lands four parts (gbrain#7878 wrote three)', () => { + const fx = setup({ ...POLICY, stamp_files: ['VERSION', 'package.json', 'CHANGELOG.md', 'changelog.d/*.md'], stamp_patterns: ['"version": "{version}"'] }); + const { repo } = fx; + repo.git('checkout', '-q', 'main'); + const pkg = JSON.parse(readFile(repo, 'package.json')); + fs.writeFileSync(path.join(repo.work, 'package.json'), JSON.stringify({ ...pkg, version: '1.2.3.0' }, null, 2) + '\n'); + fs.rmSync(path.join(repo.work, 'package-lock.json')); + repo.git('add', '-A'); repo.git('commit', '-q', '-m', 'four-part manifest'); repo.git('push', '-q', 'origin', 'main'); + openPr(fx, '21'); + expect(land(fx, ['--pr', '21']).status).toBe(EXIT.ok); + const merged = land(fx, ['--pr', '21']); + expect(merged.status, merged.err).toBe(EXIT.ok); + expect(JSON.parse(show(fx, 'origin/main:package.json')).version).toBe('1.2.4.0'); + expect(show(fx, 'origin/main:VERSION')).toBe('1.2.4.0'); + }, 90_000); + + test('control: gstack\'s shape (a three-part manifest outside stamp_files) stays three parts', () => { + const fx = setup(); + openPr(fx, '22'); + land(fx, ['--pr', '22']); + expect(land(fx, ['--pr', '22']).status).toBe(EXIT.ok); + expect(JSON.parse(show(fx, 'origin/main:package.json')).version).toBe('1.2.4'); + }, 90_000); +}); + describe('resolveReleaseConflicts', () => { test('a manifest whose version conflicts keeps the clean dependency edit and takes the base version; a real dependency conflict stays a conflict', () => { const fx = setup();