mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-02 23:14:33 +01:00
test(ship): failing-first Step 12 keep-current refusal and unattended early bump write (GST-380)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
514daebf5f
commit
c98560e3cc
2 files changed
+47
-1
No files matched your search
@@ -56,7 +56,8 @@ export function shipFixture(base: Record<string, string> = {}, feat: Record<stri
|
||||
must(gitIn(work, ['checkout', '-qb', 'feat']), 'branch');
|
||||
writeIn(work, feat);
|
||||
must(gitIn(work, ['add', '-A']), 'add feat'); must(gitIn(work, ['commit', '-qm', 'feat']), 'feat commit');
|
||||
const env = { ...process.env, PATH: `${stub}:${process.env.PATH}`, GSTACK_STATE_ROOT: state, GSTACK_HOME: state, GIT_AUTHOR_NAME: 'Fixture', GIT_AUTHOR_EMAIL: 'fixture@example.com',
|
||||
const { GSTACK_SESSION_KIND: _k, GSTACK_HEADLESS: _h, OPENCLAW_SESSION: _o, CI: _c, GITHUB_ACTIONS: _g, ...ambient } = process.env;
|
||||
const env = { ...ambient, PATH: `${stub}:${process.env.PATH}`, GSTACK_STATE_ROOT: state, GSTACK_HOME: state, GIT_AUTHOR_NAME: 'Fixture', GIT_AUTHOR_EMAIL: 'fixture@example.com',
|
||||
GIT_COMMITTER_NAME: 'Fixture', GIT_COMMITTER_EMAIL: 'fixture@example.com', GIT_CONFIG_GLOBAL: path.join(root, 'gitconfig') };
|
||||
fs.writeFileSync(path.join(root, 'gitconfig'), '[commit]\n\tgpgsign = false\n');
|
||||
const fx: ShipFx = {
|
||||
|
||||
@@ -60,6 +60,51 @@ describe('version (Step 12)', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('version (Step 12): keeping VERSION and waiting for the bump answer (GST-380)', () => {
|
||||
const UNATTENDED = { GSTACK_SESSION_KIND: 'unattended' };
|
||||
const untouched = (f: ShipFx) => {
|
||||
expect(read(f, 'VERSION')).toBe('1.0.0.0\n');
|
||||
expect(JSON.parse(read(f, 'package.json')).version).toBe('1.0.0');
|
||||
expect(read(f, 'CHANGELOG.md')).toContain('## [Unreleased]');
|
||||
expect(f.git('status', '--porcelain').stdout).toBe('');
|
||||
};
|
||||
|
||||
// Value: protects=a repo whose unit PRs never change VERSION can pass Step 12 with --keep-current or --version <current> on a FRESH branch, and nothing is written or claimed; fails_when=FRESH demands a level before it reads those flags (gstack-evals#85: BUMP_LEVEL needed for all three flags);
|
||||
// why_new=GST-380; seam=gstack-version-bump classify; no_claim=the queue's live host read
|
||||
test('FRESH under bump ask: --keep-current and --version <current> keep VERSION with no write', () => {
|
||||
for (const args of [['--keep-current'], ['--version', '1.0.0.0']]) {
|
||||
const f = fx();
|
||||
const r = f.run(RELEASE, ['version', '--base', 'main', ...args]);
|
||||
expect([r.status, lineOf(r.stdout, 'VERSION')]).toEqual([0, expect.stringMatching(/^VERSION: 1\.0\.0\.0 kept \(FRESH, /)]);
|
||||
expect(r.stdout).toContain('NEXT: Step 13');
|
||||
untouched(f);
|
||||
}
|
||||
const g = fx();
|
||||
const incomplete = g.run(RELEASE, ['version', '--base', 'main', '--accept-incomplete']);
|
||||
expect([incomplete.status, incomplete.stdout.includes('--keep-current')]).toEqual([3, true]);
|
||||
untouched(g);
|
||||
});
|
||||
|
||||
// Value: protects=in a session no person answers (unattended, spawned, OpenClaw, headless) a bump under bump ask waits for the owner's words before anything is written; fails_when=the bin writes VERSION on a --bump the agent took as the recommended option (gstack-evals#89 wrote 0.0.2 before anyone was asked);
|
||||
// why_new=GST-380; seam=gstack-session-kind's classification, gstack-version-bump write; no_claim=that the words came from the owner
|
||||
test('an unattended --bump under bump ask stops with BUMP_ANSWER_REQUIRED and writes nothing until --answer', () => {
|
||||
for (const env of [UNATTENDED, { GSTACK_SESSION_KIND: 'spawned' }, { OPENCLAW_SESSION: '1' }, { GSTACK_HEADLESS: '1' }]) {
|
||||
const f = fx();
|
||||
const r = f.run(RELEASE, ['version', '--base', 'main', '--bump', 'micro', '--why', 'small'], env);
|
||||
expect([r.status, /^STOP: BUMP_ANSWER_REQUIRED/m.test(r.stdout), r.stdout.includes('--keep-current')]).toEqual([3, true, true]);
|
||||
untouched(f);
|
||||
}
|
||||
const f = fx();
|
||||
expect(f.run(RELEASE, ['version', '--base', 'main', '--bump', 'micro', '--answer', '--why', 'x'], UNATTENDED).status).toBe(2);
|
||||
expect(f.run(RELEASE, ['version', '--base', 'main', '--bump', 'micro', '--answer', ' '], UNATTENDED).status).toBe(2);
|
||||
untouched(f);
|
||||
const ok = f.run(RELEASE, ['version', '--base', 'main', '--bump', 'micro', '--answer', 'micro is fine'], UNATTENDED);
|
||||
expect([ok.status, read(f, 'VERSION')]).toEqual([0, '1.0.0.1\n']);
|
||||
const patch = fx({ '.gstack/ship-policy.json': '{"bump":"patch"}\n' });
|
||||
expect([patch.run(RELEASE, ['version', '--base', 'main'], UNATTENDED).status, read(patch, 'VERSION')]).toEqual([0, '1.0.1.0\n']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('finish (Steps 15-16)', () => {
|
||||
// Value: protects=finish commits only release metadata with the trailer, then checks the reviewed-tree route, docs freshness, each lane receipt and the pregate; fails_when=it commits feature files, skips a stage, or pushes;
|
||||
// why_new=moved from Steps 15-16; seam=gstack-wtree, gstack-docs-candidate compare, gstack-evidence, gstack-pregate; no_claim=the stage 5 report
|
||||
|
||||
Reference in new issue
Block a user