























@@ -0,0 +1,144 @@
1+#!/usr/bin/env node
2+import fs from "node:fs";
3+import path from "node:path";
4+import { fileURLToPath } from "node:url";
5+import { spawnPnpmRunner } from "./pnpm-runner.mjs";
6+7+const LIVE_TEST_SUFFIX = ".live.test.ts";
8+9+export const LIVE_TEST_SHARDS = Object.freeze([
10+"native-live-src-agents",
11+"native-live-src-gateway",
12+"native-live-test",
13+"native-live-extensions-a-k",
14+"native-live-extensions-l-z",
15+]);
16+17+function walkFiles(rootDir) {
18+const files = [];
19+if (!fs.existsSync(rootDir)) {
20+return files;
21+}
22+const stack = [rootDir];
23+while (stack.length > 0) {
24+const current = stack.pop();
25+const entries = fs.readdirSync(current, { withFileTypes: true });
26+for (const entry of entries) {
27+const fullPath = path.join(current, entry.name);
28+if (entry.isDirectory()) {
29+if (
30+entry.name === "node_modules" ||
31+entry.name === "dist" ||
32+entry.name === "vendor" ||
33+entry.name === "fixtures"
34+) {
35+continue;
36+}
37+stack.push(fullPath);
38+continue;
39+}
40+if (entry.isFile()) {
41+files.push(fullPath);
42+}
43+}
44+}
45+return files;
46+}
47+48+export function collectAllLiveTestFiles(repoRoot = process.cwd()) {
49+return ["src", "test", "extensions"]
50+.flatMap((dir) => walkFiles(path.join(repoRoot, dir)))
51+.map((file) => path.relative(repoRoot, file).split(path.sep).join("/"))
52+.filter((file) => file.endsWith(LIVE_TEST_SUFFIX))
53+.sort((a, b) => a.localeCompare(b));
54+}
55+56+function extensionKey(file) {
57+const relative = file.slice("extensions/".length);
58+return relative.split("/", 1)[0]?.toLowerCase() ?? "";
59+}
60+61+function isExtensionInRange(file, start, end) {
62+if (!file.startsWith("extensions/")) {
63+return false;
64+}
65+const key = extensionKey(file);
66+if (!key) {
67+return false;
68+}
69+const first = key[0];
70+return first >= start && first <= end;
71+}
72+73+export function selectLiveShardFiles(shard, files = collectAllLiveTestFiles()) {
74+switch (shard) {
75+case "native-live-src-agents":
76+return files.filter((file) => file.startsWith("src/agents/"));
77+case "native-live-src-gateway":
78+return files.filter(
79+(file) => file.startsWith("src/gateway/") || file.startsWith("src/crestodian/"),
80+);
81+case "native-live-test":
82+return files.filter((file) => file.startsWith("test/"));
83+case "native-live-extensions-a-k":
84+return files.filter((file) => isExtensionInRange(file, "a", "k"));
85+case "native-live-extensions-l-z":
86+return files.filter((file) => isExtensionInRange(file, "l", "z"));
87+default:
88+throw new Error(
89+`Unknown live test shard '${shard}'. Expected one of: ${LIVE_TEST_SHARDS.join(", ")}`,
90+);
91+}
92+}
93+94+function usage() {
95+console.error(`Usage: node scripts/test-live-shard.mjs <${LIVE_TEST_SHARDS.join("|")}> [--list]`);
96+}
97+98+if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
99+const args = process.argv.slice(2);
100+const shard = args.find((arg) => !arg.startsWith("-"));
101+const listOnly = args.includes("--list");
102+if (!shard) {
103+usage();
104+process.exit(2);
105+}
106+107+let files;
108+try {
109+files = selectLiveShardFiles(shard);
110+} catch (error) {
111+console.error(error instanceof Error ? error.message : String(error));
112+usage();
113+process.exit(2);
114+}
115+if (files.length === 0) {
116+console.error(`Live test shard '${shard}' selected no files.`);
117+process.exit(2);
118+}
119+120+if (listOnly) {
121+for (const file of files) {
122+console.log(file);
123+}
124+process.exit(0);
125+}
126+127+console.log(`[test:live:shard] ${shard}: ${files.length} file(s)`);
128+const child = spawnPnpmRunner({
129+stdio: "inherit",
130+pnpmArgs: ["test:live", "--", ...files],
131+env: process.env,
132+});
133+child.on("exit", (code, signal) => {
134+if (signal) {
135+process.kill(process.pid, signal);
136+return;
137+}
138+process.exit(code ?? 1);
139+});
140+child.on("error", (error) => {
141+console.error(error);
142+process.exit(1);
143+});
144+}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。