Files
tutti/tools/scripts/run-changed-go-validation.mjs
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

170 lines
4.6 KiB
JavaScript

import { execFileSync } from "node:child_process";
import { dirname, join, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { createIsolatedGitEnvironment } from "./git-environment.mjs";
import {
buildGoLintLane,
buildGoTestLane,
discoverGoModuleRoots,
isBuiltinGenerateRequired,
resolveGoValidationTargets,
selectGoLintModuleRoots
} from "./run-check-changed-targets.mjs";
import { runValidationLanes } from "./run-validation-lanes.mjs";
const scriptDirectory = dirname(fileURLToPath(import.meta.url));
const workspaceRoot = join(scriptDirectory, "..", "..");
export function buildChangedGoValidationLanes({
changedFiles,
kind,
moduleRoots,
pathExists,
pnpmCommand = "pnpm",
root = workspaceRoot
}) {
if (kind !== "lint" && kind !== "test") {
throw new Error("kind requires lint or test");
}
const resolved = resolveGoValidationTargets(changedFiles, {
lintModuleRoots: selectGoLintModuleRoots(moduleRoots),
moduleRoots,
...(pathExists ? { pathExists } : {})
});
if (!resolved) {
return [];
}
const targetsByModule =
kind === "lint" ? resolved.lintByModule : resolved.testByModule;
const forceBuiltinGenerate = isBuiltinGenerateRequired(changedFiles);
return Array.from(targetsByModule, ([moduleRoot, targets]) =>
kind === "lint"
? buildGoLintLane({
forceBuiltinGenerate,
moduleRoot,
pnpmCommand,
shellQuote,
targets,
workspaceRoot: root
})
: buildGoTestLane({
forceBuiltinGenerate,
moduleRoot,
pnpmCommand,
shellQuote,
targets
})
);
}
export function parseChangedGoValidationArgs(inputArgs) {
const args = inputArgs.filter((arg) => arg !== "--");
const options = {
baseRef: null,
headRef: "HEAD",
kind: null,
maxParallel: 3,
tailLines: 80
};
for (let index = 0; index < args.length; index += 1) {
const arg = args[index];
switch (arg) {
case "--base":
options.baseRef = readValue(args, ++index, arg);
break;
case "--head":
options.headRef = readValue(args, ++index, arg);
break;
case "--kind": {
const kind = readValue(args, ++index, arg);
if (kind !== "lint" && kind !== "test") {
throw new Error("--kind requires lint or test");
}
options.kind = kind;
break;
}
case "--max-parallel":
options.maxParallel = readPositiveInteger(args, ++index, arg);
break;
case "--tail-lines":
options.tailLines = readPositiveInteger(args, ++index, arg);
break;
default:
throw new Error(`unknown option: ${arg}`);
}
}
if (!options.baseRef) {
throw new Error("--base is required");
}
if (!options.kind) {
throw new Error("--kind is required");
}
return options;
}
async function main() {
const options = parseChangedGoValidationArgs(process.argv.slice(2));
const changedFiles = execFileSync(
"git",
["diff", "--name-only", `${options.baseRef}...${options.headRef}`],
{
cwd: workspaceRoot,
encoding: "utf8",
env: createIsolatedGitEnvironment(workspaceRoot)
}
)
.split("\n")
.map((line) => line.trim())
.filter(Boolean);
const moduleRoots = discoverGoModuleRoots({ root: workspaceRoot });
const lanes = buildChangedGoValidationLanes({
changedFiles,
kind: options.kind,
moduleRoots
});
const label =
options.kind === "lint" ? "Changed Go lint" : "Changed Go tests";
const result = await runValidationLanes({
lanes,
maxParallel: options.maxParallel,
summaryLabel: label,
tailLines: options.tailLines,
tmpDirectoryName:
options.kind === "lint" ? "lint-runs/go-changed" : "test-runs/go-changed",
workspaceRoot
});
process.exitCode = result.exitCode;
}
function readValue(args, index, option) {
const value = args[index];
if (!value || value.startsWith("--")) {
throw new Error(`${option} requires a value`);
}
return value;
}
function readPositiveInteger(args, index, option) {
const value = readValue(args, index, option);
if (!/^[1-9]\d*$/u.test(value)) {
throw new Error(`${option} requires a positive integer`);
}
return Number.parseInt(value, 10);
}
function shellQuote(value) {
if (/^[A-Za-z0-9_./:=@+-]+$/u.test(value)) {
return value;
}
return `'${value.replaceAll("'", "'\\''")}'`;
}
const currentPath = fileURLToPath(import.meta.url);
if (process.argv[1] && resolve(process.argv[1]) === currentPath) {
main().catch((error) => {
console.error(error instanceof Error ? error.message : error);
process.exitCode = 1;
});
}