|
1 | 1 | import assert from "node:assert/strict"; |
| 2 | +import { execFile } from "node:child_process"; |
2 | 3 | import { readFile } from "node:fs/promises"; |
3 | 4 | import path from "node:path"; |
4 | 5 | import test from "node:test"; |
| 6 | +import { promisify } from "node:util"; |
5 | 7 |
|
| 8 | +const execFileAsync = promisify(execFile); |
6 | 9 | const repoRoot = process.cwd(); |
7 | | -const embeddableCliEntrypoints = [ |
8 | | - "apps/gateway/src/index.ts", |
9 | | - "packages/core/scripts/release/check-source.mjs", |
10 | | - "packages/deploy/src/cli.ts", |
11 | | - "packages/sdk/scripts/release/check-source.mjs", |
12 | | - "scripts/benchmark.ts", |
13 | | - "scripts/deploy-storage-preflight.ts", |
14 | | - "scripts/docs-link-check.ts", |
15 | | - "scripts/package-runtime-coverage.ts", |
16 | | - "scripts/test.mjs", |
17 | | -]; |
18 | | - |
19 | | -test("embeddable CLI entrypoints avoid abrupt process exits", async () => { |
20 | | - for (const relativePath of embeddableCliEntrypoints) { |
21 | | - const contents = await readFile(path.join(repoRoot, relativePath), "utf8"); |
| 10 | +const sourceRoots = ["apps", "packages", "scripts"] as const; |
| 11 | +const sourceExtensions = new Set([".mjs", ".ts"]); |
| 12 | +const cliEntrypointGuardPattern = |
| 13 | + /import\.meta\.url\s*===\s*pathToFileURL\(process\.argv\[1\]\)\.href/; |
| 14 | + |
| 15 | +async function collectCheckedInSourceFiles(): Promise<string[]> { |
| 16 | + const { stdout } = await execFileAsync("git", ["ls-files", "--", ...sourceRoots], { |
| 17 | + cwd: repoRoot, |
| 18 | + maxBuffer: 1024 * 1024, |
| 19 | + }); |
| 20 | + |
| 21 | + return stdout |
| 22 | + .split(/\r?\n/) |
| 23 | + .filter( |
| 24 | + (relativePath) => |
| 25 | + sourceExtensions.has(path.extname(relativePath)) && !relativePath.endsWith(".test.ts"), |
| 26 | + ) |
| 27 | + .sort((left, right) => left.localeCompare(right)); |
| 28 | +} |
| 29 | + |
| 30 | +async function readRelativeSource(relativePath: string): Promise<string> { |
| 31 | + return await readFile(path.join(repoRoot, relativePath), "utf8"); |
| 32 | +} |
| 33 | + |
| 34 | +test("checked-in non-test source files avoid abrupt process exits", async () => { |
| 35 | + const sourceFiles = await collectCheckedInSourceFiles(); |
| 36 | + |
| 37 | + assert.ok(sourceFiles.length > 0); |
| 38 | + for (const relativePath of sourceFiles) { |
| 39 | + const contents = await readRelativeSource(relativePath); |
22 | 40 |
|
23 | 41 | assert.doesNotMatch(contents, /\bprocess\.exit\s*\(/, relativePath); |
| 42 | + } |
| 43 | +}); |
| 44 | + |
| 45 | +test("embeddable CLI entrypoints set process.exitCode", async () => { |
| 46 | + const entrypoints = []; |
| 47 | + |
| 48 | + for (const relativePath of await collectCheckedInSourceFiles()) { |
| 49 | + const contents = await readRelativeSource(relativePath); |
| 50 | + if (cliEntrypointGuardPattern.test(contents)) { |
| 51 | + entrypoints.push({ contents, relativePath }); |
| 52 | + } |
| 53 | + } |
| 54 | + |
| 55 | + assert.ok(entrypoints.length >= 20); |
| 56 | + for (const { contents, relativePath } of entrypoints) { |
24 | 57 | assert.match(contents, /\bprocess\.exitCode\s*=/, relativePath); |
25 | 58 | } |
26 | 59 | }); |
0 commit comments