mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-13 11:57:19 +01:00
fix(ship): the GST-906 restamp carry also holds after the slot merges main (red-team, ship round 1)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
cf39e6a30c
commit
6340025f17
2 files changed
+40
-4
No files matched your search
+9
-4
@@ -11,7 +11,7 @@
|
||||
*/
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import { normalizeChangelog } from './changelog-check';
|
||||
import { mergeChangelogs, normalizeChangelog } from './changelog-check';
|
||||
import { versionAtRef } from './restamp';
|
||||
import { classifyPath } from './review-depth';
|
||||
import { comparePath, contextPacket, gateEditedPaths, isTestCode, PACKET_SECTION_CAP, readScopedReview, touchedPaths, type PatchSides } from './ship-patch';
|
||||
@@ -221,8 +221,9 @@ function route(cwd: string, base: string, reviewed: string, reviewedBase: string
|
||||
|
||||
/**
|
||||
* Step 16 stage 3. Test code, paths only the base or a stamp moved, a slot restamp after the audit (the CHANGELOG's heading
|
||||
* move or re-heading, the version file's version, each against the audited bytes; GST-906), and --docs-requested fixes the
|
||||
* audit's own result asked for do not stale the audit (GST-391).
|
||||
* move or re-heading after the restamp writer's own merge of the base's CHANGELOG into the audited one, the version file's
|
||||
* version, each against the audited bytes; GST-906), and --docs-requested fixes the audit's own result asked for do not
|
||||
* stale the audit (GST-391).
|
||||
*/
|
||||
function docsFresh(cwd: string, base: string, postFile: string, moved: readonly string[], requested: string[], resultFile: string | undefined, r: Report): boolean {
|
||||
const cmp = bin(cwd, 'gstack-docs-candidate', ['compare', postFile], 120_000);
|
||||
@@ -268,7 +269,11 @@ function docsFresh(cwd: string, base: string, postFile: string, moved: readonly
|
||||
if (audited?.status !== 0) return false;
|
||||
let now: string;
|
||||
try { now = fs.readFileSync(path.join(cwd, p), 'utf8'); } catch { return false; }
|
||||
return isChangelog ? normalizeChangelog(audited.stdout) === normalizeChangelog(now) : !!parseVersion(audited.stdout.trim()) && !!parseVersion(now.trim());
|
||||
if (!isChangelog) return !!parseVersion(audited.stdout.trim()) && !!parseVersion(now.trim());
|
||||
const [atAuditBase, atNowBase] = [auditBase, nowBase].map(b => b ? git(cwd, ['show', `${b}:${p}`]) : null);
|
||||
if (atAuditBase?.status !== 0 || atNowBase?.status !== 0) return false;
|
||||
const merged = mergeChangelogs(audited.stdout, atNowBase.stdout, atAuditBase.stdout);
|
||||
return merged !== null && normalizeChangelog(merged) === normalizeChangelog(now);
|
||||
});
|
||||
const carried = { tests: stale.filter(isTestCode), base: stale.filter(p => !isTestCode(p) && (moved.includes(p) || restamped.includes(p) || (!!auditBase && !!nowBase && !branchAtAudit.has(p) && !branchNow.has(p)))), requested: [] as string[] };
|
||||
let audit: any = null;
|
||||
|
||||
@@ -553,4 +553,35 @@ describe('a CHANGELOG re-heading after the docs audit (GST-906, GBRA-258, gbrain
|
||||
else expect([name, r.status, lineOf(r.stdout, 'DOCS')]).toEqual([name, 3, 'DOCS: stale (CHANGELOG.md)']);
|
||||
}
|
||||
});
|
||||
|
||||
// Value: protects=the lost-slot restamp merges main first (CREW rule 6), so the CHANGELOG also gains main's new sections;
|
||||
// that merge plus the re-heading keeps the audit fresh, while a merge that drops or edits a main section, or hides an
|
||||
// entry edit, stays stale; fails_when=finish stops with DOCS: stale (CHANGELOG.md) after main merged a sibling's release,
|
||||
// or waves a changed section through; seam=lib/ship-release.ts docsFresh (mergeChangelogs as lib/restamp.ts calls it);
|
||||
// no_claim=the restamp writer
|
||||
test('a main merge before the re-heading keeps the audit fresh; a dropped or edited section stays stale', () => {
|
||||
const policy = JSON.stringify({ bump: 'patch', queue_mode: 'stamp-at-merge', changelog: 'CHANGELOG.md', stamp_files: ['VERSION', 'package.json', 'CHANGELOG.md'] });
|
||||
const section = (heading: string, entry: string) => `${heading}\n\n${entry}\n\n`;
|
||||
const log = (...sections: string[]) => `# Changelog\n\n${sections.join('')}## [1.0.0.0] - 2026-10-30\n\n- base entry\n`;
|
||||
const own = section('## [1.0.1.0] - 2026-11-01', '- b ships');
|
||||
const sibling = section('## [1.0.1.0] - 2026-11-01', '- sibling ships');
|
||||
const cases = [
|
||||
['main merged, then re-headed', log(section('## [1.0.2.0] - 2026-11-02', '- b ships'), sibling), 'fresh'],
|
||||
['merge drops a main section', log(section('## [1.0.2.0] - 2026-11-02', '- b ships')), 'stale'],
|
||||
['merge edits a main section', log(section('## [1.0.2.0] - 2026-11-02', '- b ships'), section('## [1.0.1.0] - 2026-11-01', '- sibling ships fast')), 'stale'],
|
||||
['entry edit hidden inside a merge', log(section('## [1.0.2.0] - 2026-11-02', '- b ships fast'), sibling), 'stale'],
|
||||
] as const;
|
||||
for (const [name, stampedLog, verdict] of cases) {
|
||||
const f = fx({ '.gstack/ship-policy.json': policy, VERSION: '1.0.0.0\n', 'CHANGELOG.md': log() });
|
||||
const reviewed = wtree(f);
|
||||
f.write({ VERSION: '1.0.1.0\n', 'CHANGELOG.md': log(own) }); f.commit('Steps 12-13: version and CHANGELOG');
|
||||
const post = snapshot(f);
|
||||
f.advanceBase({ VERSION: '1.0.1.0\n', 'CHANGELOG.md': log(sibling) });
|
||||
mergeMain(f, { VERSION: '1.0.1.0\n', 'CHANGELOG.md': log(own, sibling) });
|
||||
f.write({ VERSION: '1.0.2.0\n', 'CHANGELOG.md': stampedLog }); f.commit('slot restamp');
|
||||
const r = finish(f, reviewed, post, ['--reviewed-base', mergeBase(f)]);
|
||||
if (verdict === 'fresh') expect([name, r.status, lineOf(r.stdout, 'DOCS')]).toEqual([name, 0, expect.stringContaining('DOCS: fresh against the Step 14.5 post-audit snapshot')]);
|
||||
else expect([name, r.status, lineOf(r.stdout, 'DOCS')]).toEqual([name, 3, 'DOCS: stale (CHANGELOG.md)']);
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user