From 8b5b150e02a71c4091392fb4946582b347ff6904 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sat, 20 Jun 2026 03:27:15 +0200 Subject: [PATCH] fix(test): guard platform sync cli values --- scripts/android-sync-versioning.ts | 62 +++++++++++++++++++--------- scripts/ios-sync-versioning.ts | 62 +++++++++++++++++++--------- test/scripts/android-version.test.ts | 14 +++++++ test/scripts/ios-version.test.ts | 14 +++++++ 4 files changed, 114 insertions(+), 38 deletions(-) diff --git a/scripts/android-sync-versioning.ts b/scripts/android-sync-versioning.ts index ba942b2fb8c5..035bb4f6cdd2 100644 --- a/scripts/android-sync-versioning.ts +++ b/scripts/android-sync-versioning.ts @@ -4,7 +4,8 @@ import { syncAndroidVersioning } from "./lib/android-version.ts"; type Mode = "check" | "write"; -export function parseArgs(argv: string[]): { mode: Mode; rootDir: string } { +export function parseArgs(argv: string[]): { help: boolean; mode: Mode; rootDir: string } { + let help = false; let mode: Mode = "write"; let rootDir = path.resolve("."); @@ -20,20 +21,14 @@ export function parseArgs(argv: string[]): { mode: Mode; rootDir: string } { break; } case "--root": { - const value = argv[index + 1]; - if (!value) { - throw new Error("Missing value for --root."); - } - rootDir = path.resolve(value); + rootDir = path.resolve(readOptionValue(argv, index, "--root")); index += 1; break; } case "-h": case "--help": { - console.log( - "Usage: node --import tsx scripts/android-sync-versioning.ts [--write|--check] [--root dir]", - ); - process.exit(0); + help = true; + break; } default: { throw new Error(`Unknown argument: ${arg}`); @@ -41,18 +36,47 @@ export function parseArgs(argv: string[]): { mode: Mode; rootDir: string } { } } - return { mode, rootDir }; + return { help, mode, rootDir }; } -const options = parseArgs(process.argv.slice(2)); -const result = syncAndroidVersioning({ mode: options.mode, rootDir: options.rootDir }); +function readOptionValue(argv: string[], index: number, flag: string): string { + const value = argv[index + 1]; + if (!value || value.startsWith("--")) { + throw new Error(`Missing value for ${flag}.`); + } + return value; +} -if (options.mode === "check") { - process.stdout.write("Android versioning artifacts are up to date.\n"); -} else if (result.updatedPaths.length === 0) { - process.stdout.write("Android versioning artifacts already up to date.\n"); -} else { +function printUsage(): void { process.stdout.write( - `Updated Android versioning artifacts:\n- ${result.updatedPaths.map((filePath) => path.relative(process.cwd(), filePath)).join("\n- ")}\n`, + "Usage: node --import tsx scripts/android-sync-versioning.ts [--write|--check] [--root dir]\n", ); } + +function main(argv = process.argv.slice(2)): number { + const options = parseArgs(argv); + if (options.help) { + printUsage(); + return 0; + } + + const result = syncAndroidVersioning({ mode: options.mode, rootDir: options.rootDir }); + + if (options.mode === "check") { + process.stdout.write("Android versioning artifacts are up to date.\n"); + } else if (result.updatedPaths.length === 0) { + process.stdout.write("Android versioning artifacts already up to date.\n"); + } else { + process.stdout.write( + `Updated Android versioning artifacts:\n- ${result.updatedPaths.map((filePath) => path.relative(process.cwd(), filePath)).join("\n- ")}\n`, + ); + } + return 0; +} + +try { + process.exitCode = main(); +} catch (error) { + process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`); + process.exitCode = 1; +} diff --git a/scripts/ios-sync-versioning.ts b/scripts/ios-sync-versioning.ts index 28356bf7226e..45540734268c 100644 --- a/scripts/ios-sync-versioning.ts +++ b/scripts/ios-sync-versioning.ts @@ -4,7 +4,8 @@ import { syncIosVersioning } from "./lib/ios-version.ts"; type Mode = "check" | "write"; -export function parseArgs(argv: string[]): { mode: Mode; rootDir: string } { +export function parseArgs(argv: string[]): { help: boolean; mode: Mode; rootDir: string } { + let help = false; let mode: Mode = "write"; let rootDir = path.resolve("."); @@ -20,20 +21,14 @@ export function parseArgs(argv: string[]): { mode: Mode; rootDir: string } { break; } case "--root": { - const value = argv[index + 1]; - if (!value) { - throw new Error("Missing value for --root."); - } - rootDir = path.resolve(value); + rootDir = path.resolve(readOptionValue(argv, index, "--root")); index += 1; break; } case "-h": case "--help": { - console.log( - "Usage: node --import tsx scripts/ios-sync-versioning.ts [--write|--check] [--root dir]", - ); - process.exit(0); + help = true; + break; } default: { throw new Error(`Unknown argument: ${arg}`); @@ -41,18 +36,47 @@ export function parseArgs(argv: string[]): { mode: Mode; rootDir: string } { } } - return { mode, rootDir }; + return { help, mode, rootDir }; } -const options = parseArgs(process.argv.slice(2)); -const result = syncIosVersioning({ mode: options.mode, rootDir: options.rootDir }); +function readOptionValue(argv: string[], index: number, flag: string): string { + const value = argv[index + 1]; + if (!value || value.startsWith("--")) { + throw new Error(`Missing value for ${flag}.`); + } + return value; +} -if (options.mode === "check") { - process.stdout.write("iOS versioning artifacts are up to date.\n"); -} else if (result.updatedPaths.length === 0) { - process.stdout.write("iOS versioning artifacts already up to date.\n"); -} else { +function printUsage(): void { process.stdout.write( - `Updated iOS versioning artifacts:\n- ${result.updatedPaths.map((filePath) => path.relative(process.cwd(), filePath)).join("\n- ")}\n`, + "Usage: node --import tsx scripts/ios-sync-versioning.ts [--write|--check] [--root dir]\n", ); } + +function main(argv = process.argv.slice(2)): number { + const options = parseArgs(argv); + if (options.help) { + printUsage(); + return 0; + } + + const result = syncIosVersioning({ mode: options.mode, rootDir: options.rootDir }); + + if (options.mode === "check") { + process.stdout.write("iOS versioning artifacts are up to date.\n"); + } else if (result.updatedPaths.length === 0) { + process.stdout.write("iOS versioning artifacts already up to date.\n"); + } else { + process.stdout.write( + `Updated iOS versioning artifacts:\n- ${result.updatedPaths.map((filePath) => path.relative(process.cwd(), filePath)).join("\n- ")}\n`, + ); + } + return 0; +} + +try { + process.exitCode = main(); +} catch (error) { + process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`); + process.exitCode = 1; +} diff --git a/test/scripts/android-version.test.ts b/test/scripts/android-version.test.ts index eb454456b9de..83d668337ae6 100644 --- a/test/scripts/android-version.test.ts +++ b/test/scripts/android-version.test.ts @@ -62,6 +62,20 @@ describe("resolveAndroidVersion", () => { expect(result.stderr).toBe(""); }); + it("rejects missing Android sync CLI root values before reading version files", () => { + const result = spawnSync( + process.execPath, + ["--import", "tsx", "scripts/android-sync-versioning.ts", "--root", "--check"], + { + cwd: process.cwd(), + encoding: "utf8", + }, + ); + + expect(result.status).toBe(1); + expect(result.stderr).toBe("Missing value for --root.\n"); + }); + it("parses pinned release versions and Android version codes", () => { const rootDir = writeAndroidFixture({ version: "2026.6.2", diff --git a/test/scripts/ios-version.test.ts b/test/scripts/ios-version.test.ts index ebb5835aeb16..789a7100853f 100644 --- a/test/scripts/ios-version.test.ts +++ b/test/scripts/ios-version.test.ts @@ -58,6 +58,20 @@ describe("resolveIosVersion", () => { expect(result.stderr).toBe(""); }); + it("rejects missing iOS sync CLI root values before reading version files", () => { + const result = spawnSync( + process.execPath, + ["--import", "tsx", "scripts/ios-sync-versioning.ts", "--root", "--check"], + { + cwd: process.cwd(), + encoding: "utf8", + }, + ); + + expect(result.status).toBe(1); + expect(result.stderr).toBe("Missing value for --root.\n"); + }); + it("parses pinned release versions and derives Apple marketing fields", () => { const rootDir = writeIosFixture({ version: "2026.4.6",