fix(scripts): handle helper cli help

This commit is contained in:
Vincent Koc
2026-05-27 06:09:13 +02:00
parent 6d5c15a744
commit 2cc6871553
7 changed files with 105 additions and 24 deletions

View File

@@ -108,21 +108,35 @@ function failedRerunCommands(summary) {
.map((lane) => lane.rerunCommand);
}
const [command, file, ...args] = process.argv.slice(2);
if (!command || !file) {
throw new Error(usage());
}
if (command === "github-outputs") {
process.stdout.write(`${githubOutputs(readJson(file)).join("\n")}\n`);
} else if (command === "summary") {
const title = args.join(" ").trim();
if (!title) {
function main(argv = process.argv.slice(2)) {
const [command, file, ...args] = argv;
if (command === "--help" || command === "-h") {
process.stdout.write(`${usage()}\n`);
return 0;
}
if (!command || !file) {
throw new Error(usage());
}
process.stdout.write(`${summaryMarkdown(readJson(file), title)}\n`);
} else if (command === "failed-reruns") {
process.stdout.write(`${failedRerunCommands(readJson(file)).join("\n")}\n`);
} else {
throw new Error(`unknown command: ${command}\n${usage()}`);
if (command === "github-outputs") {
process.stdout.write(`${githubOutputs(readJson(file)).join("\n")}\n`);
} else if (command === "summary") {
const title = args.join(" ").trim();
if (!title) {
throw new Error(usage());
}
process.stdout.write(`${summaryMarkdown(readJson(file), title)}\n`);
} else if (command === "failed-reruns") {
process.stdout.write(`${failedRerunCommands(readJson(file)).join("\n")}\n`);
} else {
throw new Error(`unknown command: ${command}\n${usage()}`);
}
return 0;
}
try {
process.exitCode = main();
} catch (error) {
console.error(error instanceof Error ? error.message : String(error));
process.exitCode = 1;
}

View File

@@ -2,7 +2,12 @@
import { readFile, writeFile } from "node:fs/promises";
import path from "node:path";
const args = parseArgs(process.argv.slice(2));
const rawArgs = process.argv.slice(2);
if (rawArgs.includes("--help") || rawArgs.includes("-h")) {
usage("", 0);
}
const args = parseArgs(rawArgs);
if (!args.report) {
usage("missing --report");
}
@@ -205,12 +210,16 @@ function parseArgs(argv) {
};
}
function usage(message) {
function usage(message, status = 2) {
const text =
"usage: node scripts/kova-ci-summary.mjs --report <report.json> [--output <summary.md>] [--lane <name>]\n";
if (message) {
console.error(`error: ${message}`);
}
console.error(
"usage: node scripts/kova-ci-summary.mjs --report <report.json> [--output <summary.md>] [--lane <name>]",
);
process.exit(2);
if (status === 0 && !message) {
process.stdout.write(text);
} else {
process.stderr.write(text);
}
process.exit(status);
}

View File

@@ -283,8 +283,10 @@ export function selectLiveShardFiles(shard, files = collectAllLiveTestFiles()) {
}
}
function usage() {
console.error(`Usage: node scripts/test-live-shard.mjs <${LIVE_TEST_SHARDS.join("|")}> [--list]`);
function usage(stream = process.stderr) {
stream.write(
`Usage: node scripts/test-live-shard.mjs <${LIVE_TEST_SHARDS.join("|")}> [--list]\n`,
);
}
export function parseLiveShardArgs(args) {
@@ -310,9 +312,17 @@ export function parseLiveShardArgs(args) {
}
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
const rawArgs = process.argv.slice(2);
const separatorIndex = rawArgs.indexOf("--");
const optionArgs = separatorIndex >= 0 ? rawArgs.slice(0, separatorIndex) : rawArgs;
if (optionArgs.includes("--help") || optionArgs.includes("-h")) {
usage(process.stdout);
process.exit(0);
}
let parsedArgs;
try {
parsedArgs = parseLiveShardArgs(process.argv.slice(2));
parsedArgs = parseLiveShardArgs(rawArgs);
} catch (error) {
console.error(error instanceof Error ? error.message : String(error));
usage();

View File

@@ -387,8 +387,10 @@ const TOOLING_SOURCE_TEST_TARGETS = new Map([
["scripts/run-oxlint.mjs", ["test/scripts/run-oxlint.test.ts"]],
["scripts/run-node.mjs", ["src/infra/run-node.test.ts"]],
["scripts/ci-run-timings.mjs", ["test/scripts/ci-run-timings.test.ts"]],
["scripts/docker-e2e.mjs", ["test/scripts/docker-e2e-helper-cli.test.ts"]],
["scripts/docker-e2e-rerun.mjs", ["test/scripts/docker-e2e-helper-cli.test.ts"]],
["scripts/docker-e2e-timings.mjs", ["test/scripts/docker-e2e-helper-cli.test.ts"]],
["scripts/kova-ci-summary.mjs", ["test/scripts/kova-ci-summary.test.ts"]],
["scripts/test-extension-batch.mjs", ["test/scripts/test-extension.test.ts"]],
["scripts/lib/extension-test-plan.mjs", ["test/scripts/test-extension.test.ts"]],
["scripts/lib/vitest-batch-runner.mjs", ["test/scripts/test-extension.test.ts"]],
@@ -428,6 +430,7 @@ const TOOLING_TEST_TARGETS = new Map([
["test/scripts/ci-docker-pull-retry.test.ts", ["test/scripts/ci-docker-pull-retry.test.ts"]],
["test/scripts/docker-build-helper.test.ts", ["test/scripts/docker-build-helper.test.ts"]],
["test/scripts/docker-e2e-helper-cli.test.ts", ["test/scripts/docker-e2e-helper-cli.test.ts"]],
["test/scripts/kova-ci-summary.test.ts", ["test/scripts/kova-ci-summary.test.ts"]],
["test/scripts/live-docker-stage.test.ts", ["test/scripts/live-docker-stage.test.ts"]],
["test/scripts/openclaw-test-state.test.ts", ["test/scripts/openclaw-test-state.test.ts"]],
[

View File

@@ -14,6 +14,24 @@ function runHelper(script: string, ...args: string[]) {
}
describe("Docker E2E helper CLIs", () => {
it("prints scheduler helper help without throwing a stack trace", () => {
const result = runHelper("scripts/docker-e2e.mjs", "--help");
expect(result.status).toBe(0);
expect(result.stderr).toBe("");
expect(result.stdout).toContain("node scripts/docker-e2e.mjs github-outputs <plan.json>");
});
it("prints scheduler helper usage errors without a Node stack trace", () => {
const result = runHelper("scripts/docker-e2e.mjs");
expect(result.status).toBe(1);
expect(result.stdout).toBe("");
expect(result.stderr).toContain("node scripts/docker-e2e.mjs github-outputs <plan.json>");
expect(result.stderr).not.toContain("Error:");
expect(result.stderr).not.toContain("at file:");
});
it("prints timings help without treating --help as an artifact path", () => {
const result = runHelper("scripts/docker-e2e-timings.mjs", "--help");

View File

@@ -0,0 +1,15 @@
import { spawnSync } from "node:child_process";
import { describe, expect, it } from "vitest";
describe("scripts/kova-ci-summary", () => {
it("prints help without treating --help as a valued option", () => {
const result = spawnSync(process.execPath, ["scripts/kova-ci-summary.mjs", "--help"], {
cwd: process.cwd(),
encoding: "utf8",
});
expect(result.status).toBe(0);
expect(result.stderr).toBe("");
expect(result.stdout).toContain("usage: node scripts/kova-ci-summary.mjs --report");
});
});

View File

@@ -1,3 +1,4 @@
import { spawnSync } from "node:child_process";
import fs, { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
import {
@@ -134,6 +135,17 @@ describe("scripts/test-live-shard", () => {
);
});
it("prints CLI help before validating shard options", () => {
const result = spawnSync(process.execPath, ["scripts/test-live-shard.mjs", "--help"], {
cwd: process.cwd(),
encoding: "utf8",
});
expect(result.status).toBe(0);
expect(result.stderr).toBe("");
expect(result.stdout).toContain("Usage: node scripts/test-live-shard.mjs");
});
it("preserves Vitest passthrough args after the live shard separator", () => {
expect(parseLiveShardArgs(["native-live-test", "--", "-t", "smoke"])).toEqual({
shard: "native-live-test",