mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-08 01:38:10 +01:00
* fix(review-exclude): one git grep per tree through a scratch index, batched blob reads; dispatch prints REVIEW_PLAN_STOPPED (GST-1442) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix(review-dispatch): the plan limit lives beside the scan deadline it must stay a minute above (GST-1442) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix: pre-landing review fixes Batched blob prefixes are copied, so each 64 MB cat-file --batch buffer is released after its group instead of staying alive until every blob is read. Review-Finding: v1/outside-voice#1 reader=outside-voice Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs(review-policy): a plan past the pass limit stops with REVIEW_PLAN_STOPPED (GST-1442) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --------- Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
38 lines
2.9 KiB
TypeScript
38 lines
2.9 KiB
TypeScript
/**
|
|
* gstack-review-dispatch pass stops with a REVIEW_PLAN_STOPPED line when gstack-review-plan runs past its limit (GST-1442):
|
|
* on harness-evals #279 the plan took about 214 s against the pass's 180 s, and the pass was killed with no output at all.
|
|
*/
|
|
import { afterEach, describe, expect, test } from 'bun:test';
|
|
import { spawnSync } from 'node:child_process';
|
|
import * as fs from 'node:fs';
|
|
import * as os from 'node:os';
|
|
import * as path from 'node:path';
|
|
|
|
const DISPATCH = path.join(import.meta.dir, '..', 'bin', 'gstack-review-dispatch');
|
|
const dirs: string[] = [];
|
|
afterEach(() => { while (dirs.length) fs.rmSync(dirs.pop()!, { recursive: true, force: true }); });
|
|
|
|
describe('pass names the plan step and its limit when the plan does not finish (GST-1442)', () => {
|
|
// Value: protects=a plan past the pass's limit ends in a line naming the step, the reason and the limit, with no manifest;
|
|
// fails_when=the pass treats the killed plan like any failed plan and exits 1 with empty output (the #279 silent kill);
|
|
// why_new=GST-1442; seam=gstack-review-dispatch pass with GSTACK_REVIEW_PLAN_TIMEOUT_MS=1; no_claim=the 180 s default
|
|
test('a plan that runs past the limit prints REVIEW_PLAN_STOPPED with reason=timeout and writes no manifest', () => {
|
|
const root = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), 'rd-plan-timeout-')));
|
|
dirs.push(root);
|
|
const work = path.join(root, 'work');
|
|
const env = { ...process.env, GSTACK_STATE_ROOT: path.join(root, 'state'), GIT_AUTHOR_NAME: 't', GIT_AUTHOR_EMAIL: 't@t', GIT_COMMITTER_NAME: 't', GIT_COMMITTER_EMAIL: 't@t', GIT_CONFIG_GLOBAL: path.join(root, 'gitconfig') };
|
|
fs.writeFileSync(path.join(root, 'gitconfig'), '[commit]\n\tgpgsign = false\n');
|
|
const sh = (cwd: string, c: string) => { const r = spawnSync('bash', ['-c', c], { cwd, env, encoding: 'utf8', timeout: 60_000 }); if (r.status !== 0) throw new Error(`${c}: ${r.stderr}`); };
|
|
sh(root, 'git init -q --bare -b main origin.git && git clone -q origin.git work 2>/dev/null');
|
|
sh(work, "mkdir src && echo 'export const a = 1;' > src/a.ts && git add -A && git commit -qm base && git push -q origin main && git checkout -qb feat && echo 'export const b = 2;' >> src/a.ts && git commit -qam feat");
|
|
const out = path.join(root, 'run');
|
|
const r = spawnSync(DISPATCH, ['pass', '--base', 'main', '--out', out, '--pass', 'timeout-p1'], { cwd: work, env: { ...env, GSTACK_REVIEW_PLAN_TIMEOUT_MS: '1' }, encoding: 'utf8', timeout: 120_000 });
|
|
expect(r.status, r.stdout + r.stderr).toBe(1);
|
|
expect(r.stderr).toContain('gstack-review-dispatch pass: gstack-review-plan did not finish inside the pass');
|
|
expect(r.stderr).toContain('step="gstack-review-plan --base main" reason=timeout timeout_ms=1 signal=SIGTERM');
|
|
expect(r.stderr.trimEnd().endsWith('(REVIEW_PLAN_STOPPED)')).toBe(true);
|
|
expect(r.stdout).not.toContain('MANIFEST:');
|
|
expect(fs.existsSync(path.join(out, 'pass-manifest.json'))).toBe(false);
|
|
}, 180_000);
|
|
});
|