diff --git a/scripts/release.ts b/scripts/release.ts index 9ac04f2..cf170d4 100644 --- a/scripts/release.ts +++ b/scripts/release.ts @@ -20,6 +20,26 @@ export const TARGETS: Target[] = [ const OUT = 'dist/release'; +/** + * Build arguments for one target. + * + * Executable metadata can only be stamped by a Windows host: bun rejects + * `--windows-title` when cross-compiling, and CI releases every target from one + * Ubuntu runner. The published binary goes without it rather than the release + * failing on the last of five builds. + */ +export function buildArgs(t: Target, outfile: string, host = process.platform): string[] { + const args = ['build', '--compile', '--minify', `--target=${t.target}`, 'src/cli.tsx', '--outfile', outfile]; + if (t.windows && host === 'win32') { + args.push( + '--windows-title=shiro-neko', + '--windows-description=Agentic coding CLI', + `--windows-version=${VERSION.split('-')[0]}.0`, + ); + } + return args; +} + /** * Builds one executable per platform. * @@ -58,16 +78,7 @@ async function main(): Promise { const base = `shiro-${t.name}`; const outfile = join(OUT, base); - const buildArgs = ['build', '--compile', '--minify', `--target=${t.target}`, 'src/cli.tsx', '--outfile', outfile]; - if (t.windows) { - buildArgs.push( - '--windows-title=shiro-neko', - '--windows-description=Agentic coding CLI', - `--windows-version=${VERSION.split('-')[0]}.0`, - ); - } - - const proc = Bun.spawn(['bun', ...buildArgs], { stdout: 'inherit', stderr: 'inherit' }); + const proc = Bun.spawn(['bun', ...buildArgs(t, outfile)], { stdout: 'inherit', stderr: 'inherit' }); const code = await proc.exited; if (code !== 0) { console.error(`\nbuild failed for ${t.name} (exit ${code})`); diff --git a/test/version.test.ts b/test/version.test.ts index 4947749..3876850 100644 --- a/test/version.test.ts +++ b/test/version.test.ts @@ -34,3 +34,24 @@ test('every release target is a real bun target triple', async () => { const { TARGETS } = await import('../scripts/release'); for (const t of TARGETS) expect(t.target).toMatch(/^bun-(linux|darwin|windows)-(x64|arm64)$/); }); + +test('windows metadata is stamped on a windows host and skipped elsewhere', async () => { + const { TARGETS, buildArgs } = await import('../scripts/release'); + const win = TARGETS.find((t) => t.windows)!; + + expect(buildArgs(win, 'out.exe', 'win32')).toContain('--windows-title=shiro-neko'); + // bun rejects --windows-title when cross-compiling, and CI releases from Ubuntu. + // Passing it there failed the whole release on the last of five builds. + expect(buildArgs(win, 'out.exe', 'linux').join(' ')).not.toContain('--windows-'); +}); + +test('every target compiles the same entrypoint with the same flags', async () => { + const { TARGETS, buildArgs } = await import('../scripts/release'); + for (const t of TARGETS) { + const args = buildArgs(t, `out-${t.name}`, 'linux'); + expect(args).toContain('--compile'); + expect(args).toContain('--minify'); + expect(args).toContain(`--target=${t.target}`); + expect(args).toContain('src/cli.tsx'); + } +});