fix(train-land): a rerun whose head is still the pin re-enters the stamp step after a journaled, unpushed stamp

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
garrytanandcapy-ai[bot] committed 2026-10-29 08:52:03 +00:00
1 parent 23a17b4b7e
commit 739a374090
2 files changed
+12 -1

No files matched your search

+1 -1
View File
@@ -70,7 +70,7 @@ export async function trainLand(ctx: QueueContext, o: { train: string; pr: strin
const retargeted = (b?: string) => b && b !== ctx.base ? outRefused({ code: 'QUEUE_NOT_READY', message: `#${o.pr} targets ${b}, not ${ctx.base}; train land merges only PRs on the base the train stamped` }, lines, `retarget #${o.pr} to ${ctx.base}, then ${rerun}`, run) : null;
const wrongBase = retargeted(info.baseRefName);
if (wrongBase) return wrongBase;
if (!j || j.base !== main.sha) {
if (!j || j.base !== main.sha || info.headRefOid !== j.stamp_commit) {
const commit = git(root, ['commit-tree', s.tree, '-p', pin, '-p', main.sha, '-m', `v${s.version} stamp: train ${t.nonce} S${s.index} (#${o.pr})`], { ...process.env, ...STAMP_IDENTITY }).out;
if (!isSha(commit)) return outFailed({ code: 'QUEUE_LAND_CONFLICT', message: `cannot create the stamp commit for tree ${s.tree.slice(0, 12)}; nothing pushed` }, lines, `${Q} train status --train ${t.nonce}`, run);
if (![pin, commit, j?.stamp_commit].includes(info.headRefOid)) return stopped(env, t, 'QUEUE_TRAIN_MOVED', `#${o.pr}'s head is ${info.headRefOid.slice(0, 12)}, not its pin ${pin.slice(0, 12)}`, main.sha, lines, true);
+11
View File
@@ -144,6 +144,17 @@ describe('stamped trains: build and land', () => {
expect(fx.repo.git('--git-dir', fx.repo.origin, 'rev-parse', 'main^{tree}')).toBe(fx.repo.git('--git-dir', fx.repo.origin, 'rev-parse', stamp + '^{tree}'));
}, 300_000);
test('a rerun after the journal but before the stamp push pushes the stamp instead of stopping', () => {
const { fx, h1, nonce } = stampedTrain();
expect(queue(fx, ['train', 'verdict', '--train', nonce]).status).toBe(EXIT.ok);
const stamp = /^PUSHED: ([0-9a-f]{40})/m.exec(land(fx, nonce, '1').out)![1]!;
fx.repo.git('push', '-q', '-f', 'origin', `${h1}:refs/heads/pr-1`);
const again = land(fx, nonce, '1');
expect(again.err).not.toContain('QUEUE_TRAIN_MOVED');
expect(again.out).toContain(`PUSHED: ${stamp}`);
expect(land(fx, nonce, '1').status).toBe(EXIT.ok);
}, 300_000);
test('a PR retargeted off the train base refuses before any push', () => {
const { fx, h1, nonce } = stampedTrain();
expect(queue(fx, ['train', 'verdict', '--train', nonce]).status).toBe(EXIT.ok);