@@ -12,6 +12,11 @@ type QaE2eDeps = {
|
12 | 12 | writeStdout?: (text: string) => void; |
13 | 13 | }; |
14 | 14 | |
| 15 | +type QaE2eArgs = { |
| 16 | +help: boolean; |
| 17 | +outputPath: string; |
| 18 | +}; |
| 19 | + |
15 | 20 | async function loadQaE2eRuntime(): Promise<QaE2eRuntime> { |
16 | 21 | return await import("../extensions/qa-lab/api.js"); |
17 | 22 | } |
@@ -23,18 +28,80 @@ export function enablePrivateQaScriptEnv(env: NodeJS.ProcessEnv = process.env) {
|
23 | 28 | } |
24 | 29 | |
25 | 30 | export function resolveQaE2eOutputPath(argv: readonly string[] = process.argv.slice(2)) { |
26 | | -return argv[0]?.trim() || ".artifacts/qa-e2e/self-check.md"; |
| 31 | +return parseQaE2eArgs(argv).outputPath; |
| 32 | +} |
| 33 | + |
| 34 | +export function usage(): string { |
| 35 | +return `Usage: pnpm qa:e2e [--output <path>] |
| 36 | + |
| 37 | +Options: |
| 38 | + --output <path> Markdown report output path |
| 39 | + -h, --help Display help |
| 40 | +`; |
| 41 | +} |
| 42 | + |
| 43 | +export function parseQaE2eArgs(argv: readonly string[]): QaE2eArgs { |
| 44 | +const args = argv[0] === "--" ? argv.slice(1) : argv; |
| 45 | +let outputPath = ""; |
| 46 | +let positionalMode = false; |
| 47 | +for (let index = 0; index < args.length; index += 1) { |
| 48 | +const arg = args[index] ?? ""; |
| 49 | +if (positionalMode) { |
| 50 | +if (!outputPath && arg.trim()) { |
| 51 | +outputPath = arg.trim(); |
| 52 | +continue; |
| 53 | +} |
| 54 | +throw new Error(`Unexpected qa:e2e argument: ${arg}`); |
| 55 | +} |
| 56 | +if (arg === "--") { |
| 57 | +positionalMode = true; |
| 58 | +continue; |
| 59 | +} |
| 60 | +if (arg === "--help" || arg === "-h") { |
| 61 | +return { help: true, outputPath: ".artifacts/qa-e2e/self-check.md" }; |
| 62 | +} |
| 63 | +const inlineOutput = arg.startsWith("--output=") ? arg.slice("--output=".length).trim() : null; |
| 64 | +if (inlineOutput !== null) { |
| 65 | +if (!inlineOutput) { |
| 66 | +throw new Error("--output requires a value"); |
| 67 | +} |
| 68 | +outputPath = inlineOutput; |
| 69 | +continue; |
| 70 | +} |
| 71 | +if (arg === "--output") { |
| 72 | +const value = args[index + 1]?.trim(); |
| 73 | +if (!value || value.startsWith("-")) { |
| 74 | +throw new Error("--output requires a value"); |
| 75 | +} |
| 76 | +outputPath = value; |
| 77 | +index += 1; |
| 78 | +continue; |
| 79 | +} |
| 80 | +if (arg.startsWith("-")) { |
| 81 | +throw new Error(`Unknown qa:e2e option: ${arg}`); |
| 82 | +} |
| 83 | +if (outputPath) { |
| 84 | +throw new Error(`Unexpected qa:e2e argument: ${arg}`); |
| 85 | +} |
| 86 | +outputPath = arg.trim(); |
| 87 | +} |
| 88 | +return { help: false, outputPath: outputPath || ".artifacts/qa-e2e/self-check.md" }; |
27 | 89 | } |
28 | 90 | |
29 | 91 | export async function main( |
30 | 92 | argv: readonly string[] = process.argv.slice(2), |
31 | 93 | deps: QaE2eDeps = {}, |
32 | 94 | ): Promise<number> { |
| 95 | +const args = parseQaE2eArgs(argv); |
| 96 | +if (args.help) { |
| 97 | +(deps.writeStdout ?? ((text: string) => process.stdout.write(text)))(usage()); |
| 98 | +return 0; |
| 99 | +} |
33 | 100 | enablePrivateQaScriptEnv(deps.env ?? process.env); |
34 | 101 | const { isQaSelfCheckSuccessful, runQaE2eSelfCheck } = await ( |
35 | 102 | deps.loadRuntime ?? loadQaE2eRuntime |
36 | 103 | )(); |
37 | | -const result = await runQaE2eSelfCheck({ outputPath: resolveQaE2eOutputPath(argv) }); |
| 104 | +const result = await runQaE2eSelfCheck({ outputPath: args.outputPath }); |
38 | 105 | (deps.writeStdout ?? ((text: string) => process.stdout.write(text)))( |
39 | 106 | `QA self-check report: ${result.outputPath}\n`, |
40 | 107 | ); |
@@ -47,5 +114,10 @@ function isMainModule() {
|
47 | 114 | } |
48 | 115 | |
49 | 116 | if (isMainModule()) { |
50 | | -process.exitCode = await main(); |
| 117 | +try { |
| 118 | +process.exitCode = await main(); |
| 119 | +} catch (error) { |
| 120 | +process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`); |
| 121 | +process.exitCode = 1; |
| 122 | +} |
51 | 123 | } |