test(windows): the #3541 ship-receipt session_kind test runs in the Windows lane

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
garrytanandcapy-ai[bot] committed 2026-11-01 21:36:20 +00:00
1 parent f396bd5ca8
commit 83c48e90ae
4 files changed
+58 -16

No files matched your search

@@ -4,4 +4,4 @@
- **`bin/gstack-ship-receipt`** starts `gstack-session-kind` with `runScriptSync`.
### Tests
- `test/gstack-ship-receipt.test.ts`: a receipt written without a session kind takes it from `gstack-session-kind`.
- `test/ship-receipt-session-kind.test.ts` (windows-free-tests too): a receipt written without a session kind records what `gstack-session-kind` prints.
+1
View File
@@ -405,6 +405,7 @@ export const KNOWN_WINDOWS_SAFE: Array<{ file: string; reason: string }> = [
{ file: 'test/gstack-wtree-windows-paths.test.ts', reason: '#3101: runs bin/gstack-wtree through explicit bash in an os.tmpdir linked worktree with forward-slash paths; never executes a shebang; the drive-letter simulation is skipIf win32' },
{ file: 'test/setup-hook-syntax-gate.test.ts', reason: '#3088/#3100: runs bin/gstack-hook-check and the setup hook sections through explicit bash with forward-slash paths; never executes a shebang. Its Bun drive-path spelling is the Windows bug it guards' },
{ file: 'test/bun-config-shell-bins.test.ts', reason: '#3415: runs the record bins through lib/script-invocation.ts (Git Bash on Windows) with MSYS path conversion off, the case it guards; its bun and cygpath stand-ins and simulated-OSTYPE cases are skipIf win32' },
{ file: 'test/ship-receipt-session-kind.test.ts', reason: '#3541: runs gstack-ship-receipt write through lib/script-invocation.ts, which must reach the bash gstack-session-kind through Git Bash; os.tmpdir git fixture only' },
{ file: 'test/path-spelling.test.ts', reason: 'sources bin/gstack-path-spelling.sh through explicit bash and checks lib/path-spelling.ts; on Windows it exercises the real Git Bash spellings' },
{ file: 'test/state-root-parity.test.ts', reason: 'runs the bash twin and lib/state-root.ts over an env table with PATH empty; no shebang execution, raw-string comparison is platform-neutral' },
{ file: 'test/generator-eexist.test.ts',
-15
View File
@@ -72,21 +72,6 @@ describe('gstack-ship-receipt write', () => {
expect(rewritten).toContain('## Summary');
});
test('without --session-kind or GSTACK_SESSION_KIND, session_kind comes from gstack-session-kind (#3541)', () => {
const repo = fixture();
makePr(repo, 'pr-a', { expects: '1.2.4.0' });
expect(restamp(repo, ['--version', '1.2.4.0']).status).toBe(EXIT.ok);
repo.git('commit', '-qam', 'stamp');
const body = path.join(repo.root, 'body.md');
fs.writeFileSync(body, '## Summary\n\nProse.\n');
const env = { GSTACK_SESSION_KIND: '' };
const kind = runBin(repo, 'gstack-session-kind', [], env);
expect(kind.status, kind.err).toBe(0);
const w = runBin(repo, 'gstack-ship-receipt', ['write', '--pr', '44', '--base', 'main', '--body', body, '--json'], env);
expect(w.status, w.err).toBe(EXIT.ok);
expect(JSON.parse(w.out).session_kind).toBe(kind.out.trim());
});
test('refuses an invalid receipt before writing (RECEIPT_INVALID) and a non-integer --pr', () => {
const repo = fixture();
const body = path.join(repo.root, 'body.md');
+56
View File
@@ -0,0 +1,56 @@
/**
* #3541 (the /ship half): `gstack-ship-receipt write` with no --session-kind
* and no GSTACK_SESSION_KIND asks bin/gstack-session-kind, a bash script.
* Spawned by path it never starts on Windows (no shebangs), so every receipt
* written there carried no session_kind.
*
* Windows-safe by construction: both bins launch through
* lib/script-invocation.ts (Git Bash on win32), state lives under os.tmpdir().
*/
import { afterEach, beforeEach, expect, test } from 'bun:test';
import * as fs from 'node:fs';
import * as os from 'node:os';
import * as path from 'node:path';
import { spawnSync } from 'node:child_process';
import { runScriptSync } from '../lib/script-invocation';
const ROOT = path.resolve(import.meta.dir, '..');
let tmp = '', repo = '', env: NodeJS.ProcessEnv = {};
beforeEach(() => {
tmp = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), 'gstack-receipt-kind-')));
repo = path.join(tmp, 'repo');
fs.mkdirSync(repo);
const gitconfig = path.join(tmp, 'gitconfig');
fs.writeFileSync(gitconfig, '');
env = {
...process.env, HOME: tmp, USERPROFILE: tmp, GSTACK_STATE_ROOT: path.join(tmp, 'state'), GSTACK_HOME: path.join(tmp, 'state'), GSTACK_SESSION_KIND: '',
GIT_CONFIG_GLOBAL: gitconfig, GIT_CONFIG_NOSYSTEM: '1', GIT_DIR: undefined, GIT_WORK_TREE: undefined, GIT_INDEX_FILE: undefined,
};
const git = (...args: string[]) => {
const r = spawnSync('git', args, { cwd: repo, env, encoding: 'utf8', timeout: 30_000 });
expect(r.status, r.stderr).toBe(0);
};
git('init', '-q', '-b', 'main');
fs.writeFileSync(path.join(repo, 'a.txt'), 'a\n');
git('add', 'a.txt');
git('-c', 'user.email=fixture@example.test', '-c', 'user.name=Fixture', '-c', 'commit.gpgsign=false', 'commit', '-qm', 'fixture');
git('update-ref', 'refs/remotes/origin/main', 'HEAD');
git('switch', '-q', '-c', 'feat');
});
afterEach(() => fs.rmSync(tmp, { recursive: true, force: true }));
test('write without a session kind records what gstack-session-kind prints (#3541)', () => {
const kind = runScriptSync(path.join(ROOT, 'bin', 'gstack-session-kind'), [], { cwd: repo, env, encoding: 'utf8', timeout: 30_000 });
expect(kind.status, kind.stderr).toBe(0);
const body = path.join(tmp, 'body.md');
fs.writeFileSync(body, '## Summary\n');
const w = runScriptSync(path.join(ROOT, 'bin', 'gstack-ship-receipt'), ['write', '--pr', '1', '--base', 'main', '--body', body, '--json'], {
cwd: repo, env, encoding: 'utf8', timeout: 120_000,
});
expect(w.error).toBeUndefined();
expect(w.status, w.stderr).toBe(0);
expect(JSON.parse(w.stdout).session_kind).toBe(kind.stdout.trim());
}, 150_000);