chore(gateway): ignore .test.ts changes in gateway:watch (#36211)

This commit is contained in:
Harold Hunt
2026-03-15 11:14:28 -04:00
committed by GitHub
parent b2e9221a8c
commit 53462b990d
3 changed files with 211 additions and 61 deletions

View File

@@ -2,16 +2,24 @@
import { spawn } from "node:child_process";
import process from "node:process";
import { pathToFileURL } from "node:url";
import chokidar from "chokidar";
import { runNodeWatchedPaths } from "./run-node.mjs";
const WATCH_NODE_RUNNER = "scripts/run-node.mjs";
const WATCH_RESTART_SIGNAL = "SIGTERM";
const buildWatchArgs = (args) => [
...runNodeWatchedPaths.flatMap((watchPath) => ["--watch-path", watchPath]),
"--watch-preserve-output",
WATCH_NODE_RUNNER,
...args,
];
const buildRunnerArgs = (args) => [WATCH_NODE_RUNNER, ...args];
const normalizePath = (filePath) => String(filePath ?? "").replaceAll("\\", "/");
const isIgnoredWatchPath = (filePath) => {
const normalizedPath = normalizePath(filePath);
return (
normalizedPath.endsWith(".test.ts") ||
normalizedPath.endsWith(".test.tsx") ||
normalizedPath.endsWith("test-helpers.ts")
);
};
export async function runWatchMain(params = {}) {
const deps = {
@@ -21,6 +29,9 @@ export async function runWatchMain(params = {}) {
args: params.args ?? process.argv.slice(2),
env: params.env ? { ...params.env } : { ...process.env },
now: params.now ?? Date.now,
createWatcher:
params.createWatcher ?? ((watchPaths, options) => chokidar.watch(watchPaths, options)),
watchPaths: params.watchPaths ?? runNodeWatchedPaths,
};
const childEnv = { ...deps.env };
@@ -31,54 +42,96 @@ export async function runWatchMain(params = {}) {
childEnv.OPENCLAW_WATCH_COMMAND = deps.args.join(" ");
}
const watchProcess = deps.spawn(deps.process.execPath, buildWatchArgs(deps.args), {
cwd: deps.cwd,
env: childEnv,
stdio: "inherit",
});
let settled = false;
let onSigInt;
let onSigTerm;
const settle = (resolve, code) => {
if (settled) {
return;
}
settled = true;
if (onSigInt) {
deps.process.off("SIGINT", onSigInt);
}
if (onSigTerm) {
deps.process.off("SIGTERM", onSigTerm);
}
resolve(code);
};
return await new Promise((resolve) => {
onSigInt = () => {
if (typeof watchProcess.kill === "function") {
watchProcess.kill("SIGTERM");
let settled = false;
let shuttingDown = false;
let restartRequested = false;
let watchProcess = null;
let onSigInt;
let onSigTerm;
const watcher = deps.createWatcher(deps.watchPaths, {
ignoreInitial: true,
ignored: (watchPath) => isIgnoredWatchPath(watchPath),
});
const settle = (code) => {
if (settled) {
return;
}
settle(resolve, 130);
settled = true;
if (onSigInt) {
deps.process.off("SIGINT", onSigInt);
}
if (onSigTerm) {
deps.process.off("SIGTERM", onSigTerm);
}
watcher.close?.().catch?.(() => {});
resolve(code);
};
const startRunner = () => {
watchProcess = deps.spawn(deps.process.execPath, buildRunnerArgs(deps.args), {
cwd: deps.cwd,
env: childEnv,
stdio: "inherit",
});
watchProcess.on("exit", () => {
watchProcess = null;
if (shuttingDown) {
return;
}
if (restartRequested) {
restartRequested = false;
startRunner();
}
});
};
const requestRestart = (changedPath) => {
if (shuttingDown || isIgnoredWatchPath(changedPath)) {
return;
}
if (!watchProcess) {
startRunner();
return;
}
restartRequested = true;
if (typeof watchProcess.kill === "function") {
watchProcess.kill(WATCH_RESTART_SIGNAL);
}
};
watcher.on("add", requestRestart);
watcher.on("change", requestRestart);
watcher.on("unlink", requestRestart);
watcher.on("error", () => {
shuttingDown = true;
if (watchProcess && typeof watchProcess.kill === "function") {
watchProcess.kill(WATCH_RESTART_SIGNAL);
}
settle(1);
});
startRunner();
onSigInt = () => {
shuttingDown = true;
if (watchProcess && typeof watchProcess.kill === "function") {
watchProcess.kill(WATCH_RESTART_SIGNAL);
}
settle(130);
};
onSigTerm = () => {
if (typeof watchProcess.kill === "function") {
watchProcess.kill("SIGTERM");
shuttingDown = true;
if (watchProcess && typeof watchProcess.kill === "function") {
watchProcess.kill(WATCH_RESTART_SIGNAL);
}
settle(resolve, 143);
settle(143);
};
deps.process.on("SIGINT", onSigInt);
deps.process.on("SIGTERM", onSigTerm);
watchProcess.on("exit", (code, signal) => {
if (signal) {
settle(resolve, 1);
return;
}
settle(resolve, code ?? 1);
});
});
}