mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-22 04:40:44 +02:00
* v1.87.5.0 perf: remove idle waits from tests and CI planning * fix: settle split PTY redraws before routing input * docs: record final burst-safe test benchmarks * fix: keep cold-setup snapshot metadata dependency-free * fix: avoid early-reader pipe races in artifact URL parsing * fix: preserve safety matches for multiline command payloads * fix: recognize concurrent CSO publication removal * test: preload the UI design-review target before invocation * docs: record validation blocker fixes * fix: bind plan observer rejection to the invoked command * fix: count only native design decisions in the UI gate * docs: clarify UI-positive eval evidence requirements * test: recognize native UI decisions without weakening finding counts * test: decouple native UI evidence from question punctuation * test: recognize concrete native UI decisions independently of prose format * fix: retain failed eval logs under the hidden CI cache * test: await telemetry completion instead of racing disk writes
116 lines
4.4 KiB
TypeScript
116 lines
4.4 KiB
TypeScript
/**
|
|
* gstack-artifacts-url — URL canonicalization helper.
|
|
*
|
|
* Centralizes HTTPS↔SSH conversion so callers don't each string-mangle. Per
|
|
* codex Finding #10: store one canonical form (HTTPS) and derive all others.
|
|
*/
|
|
|
|
import { describe, test, expect } from 'bun:test';
|
|
import * as path from 'path';
|
|
import { spawnSync } from 'child_process';
|
|
|
|
const ROOT = path.resolve(import.meta.dir, '..');
|
|
const URL_BIN = path.join(ROOT, 'bin', 'gstack-artifacts-url');
|
|
|
|
function run(args: string[]): { code: number; stdout: string; stderr: string } {
|
|
const r = spawnSync(URL_BIN, args, { encoding: 'utf-8', timeout: 30_000 });
|
|
return {
|
|
code: r.status ?? -1,
|
|
stdout: (r.stdout || '').trim(),
|
|
stderr: (r.stderr || '').trim(),
|
|
};
|
|
}
|
|
|
|
describe('gstack-artifacts-url', () => {
|
|
test('normalization does not depend on external line readers', () => {
|
|
for (const url of ['git@github.com:team/repo.git', 'https://github.com/team/repo.git']) {
|
|
const result = spawnSync(Bun.which('bash')!, [URL_BIN, '--to', 'https', url], {
|
|
env: { PATH: '' }, encoding: 'utf8', timeout: 30_000,
|
|
});
|
|
expect(result.status, result.stderr).toBe(0);
|
|
expect(result.stdout.trim()).toBe('https://github.com/team/repo');
|
|
}
|
|
});
|
|
|
|
test('--to ssh from canonical https', () => {
|
|
const r = run(['--to', 'ssh', 'https://github.com/garrytan/gstack-artifacts-garrytan']);
|
|
expect(r.code).toBe(0);
|
|
expect(r.stdout).toBe('git@github.com:garrytan/gstack-artifacts-garrytan.git');
|
|
});
|
|
|
|
test('--to ssh from https-with-.git', () => {
|
|
const r = run(['--to', 'ssh', 'https://github.com/garrytan/gstack-artifacts-garrytan.git']);
|
|
expect(r.stdout).toBe('git@github.com:garrytan/gstack-artifacts-garrytan.git');
|
|
});
|
|
|
|
test('--to https is idempotent on https input', () => {
|
|
const r = run(['--to', 'https', 'https://github.com/garrytan/gstack-artifacts-garrytan']);
|
|
expect(r.stdout).toBe('https://github.com/garrytan/gstack-artifacts-garrytan');
|
|
});
|
|
|
|
test('--to https from git@host:owner/repo.git', () => {
|
|
const r = run(['--to', 'https', 'git@github.com:garrytan/gstack-artifacts-garrytan.git']);
|
|
expect(r.stdout).toBe('https://github.com/garrytan/gstack-artifacts-garrytan');
|
|
});
|
|
|
|
test('--to https from ssh:// scheme (gitlab self-hosted style)', () => {
|
|
const r = run(['--to', 'https', 'ssh://git@gitlab.example.org/team/gstack-artifacts-team.git']);
|
|
expect(r.stdout).toBe('https://gitlab.example.org/team/gstack-artifacts-team');
|
|
});
|
|
|
|
test('--host extracts hostname from any form', () => {
|
|
expect(run(['--host', 'https://github.com/x/y']).stdout).toBe('github.com');
|
|
expect(run(['--host', 'git@gitlab.com:x/y.git']).stdout).toBe('gitlab.com');
|
|
expect(run(['--host', 'ssh://git@gitlab.example.org/x/y.git']).stdout).toBe('gitlab.example.org');
|
|
});
|
|
|
|
test('--owner-repo extracts the path segment', () => {
|
|
expect(run(['--owner-repo', 'https://github.com/garrytan/gstack-artifacts-garrytan']).stdout)
|
|
.toBe('garrytan/gstack-artifacts-garrytan');
|
|
expect(run(['--owner-repo', 'git@github.com:team/gstack-artifacts-team.git']).stdout)
|
|
.toBe('team/gstack-artifacts-team');
|
|
});
|
|
|
|
test('rejects unrecognized URL form with exit 3', () => {
|
|
const r = run(['--to', 'ssh', 'not a url']);
|
|
expect(r.code).toBe(3);
|
|
expect(r.stderr).toContain('unrecognized URL form');
|
|
});
|
|
|
|
test('rejects remotes without both owner and repo path segments', () => {
|
|
const malformed = [
|
|
'https://github.com',
|
|
'https://github.com/owner',
|
|
'https://github.com/owner/',
|
|
'https://github.com/owner//repo',
|
|
'git@github.com:owner',
|
|
'ssh://git@github.com',
|
|
'ssh://git@github.com/owner',
|
|
];
|
|
|
|
for (const url of malformed) {
|
|
const r = run(['--to', 'ssh', url]);
|
|
expect(r.code, url).toBe(3);
|
|
expect(r.stderr, url).toContain('failed to parse host/owner');
|
|
}
|
|
});
|
|
|
|
test('rejects missing args with exit 2', () => {
|
|
expect(run([]).code).toBe(2);
|
|
expect(run(['--to']).code).toBe(2);
|
|
expect(run(['--to', 'ssh']).code).toBe(2);
|
|
});
|
|
|
|
test('rejects unknown --to target', () => {
|
|
const r = run(['--to', 'svn', 'https://github.com/x/y']);
|
|
expect(r.code).toBe(2);
|
|
});
|
|
|
|
test('round-trip: https → ssh → https is identity', () => {
|
|
const original = 'https://github.com/garrytan/gstack-artifacts-garrytan';
|
|
const ssh = run(['--to', 'ssh', original]).stdout;
|
|
const back = run(['--to', 'https', ssh]).stdout;
|
|
expect(back).toBe(original);
|
|
});
|
|
});
|