mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-11 03:00:26 +01:00
fix: pre-landing review fixes (ready at the stamp commit, screen on a stale merge ref, ship-run.json)
- ready accepts the pin's receipt at a slot's stamp commit (plus the slot-2 merge of main), as verify --train already did; a real edit stays STALE - ready --screen refuses QUEUE_SCREEN_STALE_REF when refs/pull/<n>/merge is missing or merges an older head; a finished screen that planned 0 cases is never followed, and train build seats that slot unscreened (GSTA-95 on #3431) - gstack-ship-receipt result writes ship-run.json (a /ship record, not a run v1 manifest), validates --head, and prints status=incomplete on gh failures - bindReceipt takes an optional pr and renders one-line SHIP_RECEIPT lines - tests for every state-matrix cell the review named; the train fixture's merge ref is a real merge commit Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
268b0125a5
commit
ec438fe8b1
17 files changed
+368
-44
No files matched your search
@@ -295,6 +295,43 @@ describe('ready', () => {
|
||||
fs.appendFileSync(path.join(repo.work, 'pr-a.txt'), 'dirty\n');
|
||||
expect(queue(repo, ['ready', '--pr', '1'], shim(moved, green)).err).toMatch(/uncommitted tracked changes: pr-a\.txt.*\(QUEUE_NOT_READY\)/);
|
||||
}, 180_000);
|
||||
|
||||
// Value: protects=the re-READY after a slot's stamp push accepts the receipt /ship wrote for the pinned head, and only then;
|
||||
// fails_when=ready binds the receipt to HEAD alone (every stamped READY turns QUEUE_RECEIPT_STALE) or accepts any ancestor's receipt;
|
||||
// why_new=the READY test above binds receipts to the exact head only; seam=none; no_claim=real gh and CI (shims; unit only)
|
||||
test('ready at the stamp commit accepts the receipt written for the pinned head; a real edit on top of the pin is stale', () => {
|
||||
const repo = fixture();
|
||||
const pin = makePr(repo, 'pr-s');
|
||||
fs.writeFileSync(path.join(repo.work, 'VERSION'), '1.2.4.0\n');
|
||||
repo.git('commit', '-qam', 'v1.2.4.0 stamp');
|
||||
const stamped = repo.git('rev-parse', 'HEAD');
|
||||
const shim = (prHead: string, body: string) => ghQueueShim(repo, { prs: { '1': { headRefOid: prHead, url: 'https://github.com/o/r/pull/1', body } }, checks: { [prHead]: green } });
|
||||
const ok = queue(repo, ['ready', '--pr', '1', '--pregate', pregateFor(repo, stamped)], shim(stamped, shippedBody('1', pin)));
|
||||
expect([ok.status, ok.err]).toEqual([EXIT.ok, '']);
|
||||
expect(ok.out.split('\n')[0]).toBe(`READY #1 ${stamped} STAMP_VERSION=1.2.4.0`);
|
||||
expect(ok.out).toContain(`SHIP_RECEIPT: pr=1 head=${pin.slice(0, 12)} version=- base=main`);
|
||||
repo.git('checkout', '-q', 'origin/main', '-B', 'main-moves');
|
||||
fs.writeFileSync(path.join(repo.work, 'other.txt'), 'another PR landed\n');
|
||||
repo.git('add', 'other.txt');
|
||||
repo.git('commit', '-qm', 'other PR');
|
||||
repo.git('push', '-q', 'origin', 'HEAD:main');
|
||||
repo.git('fetch', '-q', 'origin');
|
||||
repo.git('checkout', '-q', 'pr-s');
|
||||
repo.git('merge', '-q', '--no-edit', 'origin/main');
|
||||
fs.writeFileSync(path.join(repo.work, 'VERSION'), '1.2.5.0\n');
|
||||
repo.git('commit', '-qam', 'v1.2.5.0 stamp');
|
||||
const slot2 = repo.git('rev-parse', 'HEAD');
|
||||
const merged = queue(repo, ['ready', '--pr', '1', '--pregate', pregateFor(repo, slot2)], shim(slot2, shippedBody('1', pin)));
|
||||
expect([merged.status, merged.err]).toEqual([EXIT.ok, '']);
|
||||
expect(merged.out).toContain(`SHIP_RECEIPT: pr=1 head=${pin.slice(0, 12)} version=- base=main`);
|
||||
repo.git('reset', '-q', '--hard', stamped);
|
||||
fs.appendFileSync(path.join(repo.work, 'pr-s.txt'), 'real change after /ship\n');
|
||||
repo.git('commit', '-qam', 'more');
|
||||
const edited = repo.git('rev-parse', 'HEAD');
|
||||
const stale = queue(repo, ['ready', '--pr', '1', '--pregate', pregateFor(repo, edited)], shim(edited, shippedBody('1', pin)));
|
||||
expect(stale.status).toBe(EXIT.refused);
|
||||
expect(stale.err).toMatch(new RegExp(`PR #1's ship receipt is for ${pin.slice(0, 12)}, not the head ${edited.slice(0, 12)} being merged.*\\(QUEUE_RECEIPT_STALE\\)`));
|
||||
}, 180_000);
|
||||
});
|
||||
|
||||
describe('receipt digest', () => {
|
||||
|
||||
Reference in new issue
Block a user