mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-10 00:11:19 +00:00
fix(ci): restore macOS and Windows QA gates
Restores Azure native Windows hydrated node_modules bootstrap, fixes the macOS settings SwiftFormat drift, and stabilizes lifecycle process-group CI proof. Proof: - `tbx_01kvrpr5kfc58wdnakx2zkc4k6`: `corepack pnpm test:serial test/scripts/plugin-lifecycle-measure.test.ts` passed. - `tbx_01kvrpvcrmsxgyb886pa127qq3`: `OPENCLAW_TESTBOX=1 ... corepack pnpm check:changed` passed. - `tbx_01kvrpzpafmp27tyb4tg9yvwvz`: touched-file `format:check` passed. - PR CI `27988226071` passed, including `macos-node`, `macos-swift`, and `checks-node-compact-small-whole-2`.
This commit is contained in:
parent
961130c707
commit
dcb6b0dd6f
4 changed files with 74 additions and 46 deletions
|
|
@ -680,7 +680,6 @@ struct GeneralSettings: View {
|
|||
case .missingNode, .missingGateway, .incompatible, .error: .orange
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private enum RemoteStatus: Equatable {
|
||||
|
|
|
|||
|
|
@ -1987,6 +1987,10 @@ function isAwsMacosRemoteTarget(commandArgs, providerName) {
|
|||
);
|
||||
}
|
||||
|
||||
function isHydratedNativeWindowsProvider(providerName) {
|
||||
return providerName === "aws" || providerName === "azure";
|
||||
}
|
||||
|
||||
function remoteWindowsHydratedNodeModulesBootstrap() {
|
||||
return [
|
||||
"$openclawModulesDir = $env:PNPM_CONFIG_MODULES_DIR",
|
||||
|
|
@ -2004,7 +2008,7 @@ function injectRemoteWindowsHydratedNodeModulesBootstrap(commandArgs, providerNa
|
|||
const runtimeEntrypoint = commandRuntimeEntrypoint(runCommandArgs(commandArgs));
|
||||
if (
|
||||
commandArgs[0] !== "run" ||
|
||||
providerName !== "aws" ||
|
||||
!isHydratedNativeWindowsProvider(providerName) ||
|
||||
!isNativeWindowsRemoteTarget(commandArgs) ||
|
||||
!hasOption(commandArgs, "--id") ||
|
||||
!runtimeEntrypoint
|
||||
|
|
|
|||
|
|
@ -2407,6 +2407,32 @@ describe.concurrent("scripts/crabbox-wrapper", () => {
|
|||
expect(remoteCommand).toContain("corepack pnpm check:changed");
|
||||
});
|
||||
|
||||
it("restores hydrated node_modules before Azure native Windows shell commands", () => {
|
||||
const result = runWrapper("provider: hetzner, aws, azure, local-container\n", [
|
||||
"run",
|
||||
"--provider",
|
||||
"azure",
|
||||
"--target",
|
||||
"windows",
|
||||
"--windows-mode",
|
||||
"normal",
|
||||
"--id",
|
||||
"cbx_test",
|
||||
"--shell",
|
||||
"--",
|
||||
"corepack pnpm check:changed",
|
||||
]);
|
||||
|
||||
const output = parseFakeCrabboxOutput(result);
|
||||
const remoteCommand = output.args.at(-1) ?? "";
|
||||
expect(result.status).toBe(0);
|
||||
expect(output.args).toContain("--shell");
|
||||
expect(remoteCommand).toContain("$openclawModulesDir = $env:PNPM_CONFIG_MODULES_DIR");
|
||||
expect(remoteCommand).toContain('mklink /J "$openclawSelfModules" "$openclawModulesDir"');
|
||||
expect(remoteCommand).toContain('mklink /J "$openclawWorkspaceModules" "$openclawModulesDir"');
|
||||
expect(remoteCommand).toContain("corepack pnpm check:changed");
|
||||
});
|
||||
|
||||
it("restores hydrated node_modules before AWS native Windows direct commands", () => {
|
||||
const result = runWrapper("provider: hetzner, aws, azure, local-container\n", [
|
||||
"run",
|
||||
|
|
|
|||
|
|
@ -15,9 +15,6 @@ import { afterEach, describe, expect, it } from "vitest";
|
|||
|
||||
const tempDirs: string[] = [];
|
||||
const scriptPath = "scripts/e2e/lib/plugin-lifecycle-matrix/measure.mjs";
|
||||
const hasTimeoutCommand =
|
||||
process.platform === "linux" &&
|
||||
spawnSync("bash", ["-lc", "command -v timeout >/dev/null 2>&1"]).status === 0;
|
||||
|
||||
function makeTempDir(): string {
|
||||
const dir = mkdtempSync(path.join(tmpdir(), "openclaw-plugin-lifecycle-measure-"));
|
||||
|
|
@ -317,8 +314,8 @@ describe("plugin lifecycle resource sampler", () => {
|
|||
encoding: "utf8",
|
||||
env: {
|
||||
...process.env,
|
||||
OPENCLAW_PLUGIN_LIFECYCLE_PHASE_TIMEOUT_MS: "150",
|
||||
OPENCLAW_PLUGIN_LIFECYCLE_TIMEOUT_KILL_GRACE_MS: "100",
|
||||
OPENCLAW_PLUGIN_LIFECYCLE_PHASE_TIMEOUT_MS: "1000",
|
||||
OPENCLAW_PLUGIN_LIFECYCLE_TIMEOUT_KILL_GRACE_MS: "200",
|
||||
PID_FILE: pidFile,
|
||||
},
|
||||
timeout: 5000,
|
||||
|
|
@ -340,49 +337,51 @@ describe("plugin lifecycle resource sampler", () => {
|
|||
},
|
||||
);
|
||||
|
||||
it.runIf(hasTimeoutCommand)("forwards external termination to the measured process group", () => {
|
||||
const dir = makeTempDir();
|
||||
const summary = path.join(dir, "summary.tsv");
|
||||
const pidFile = path.join(dir, "descendant.pid");
|
||||
let descendantPid;
|
||||
it.runIf(process.platform === "linux")(
|
||||
"forwards external termination to the measured process group",
|
||||
async () => {
|
||||
const dir = makeTempDir();
|
||||
const summary = path.join(dir, "summary.tsv");
|
||||
const pidFile = path.join(dir, "descendant.pid");
|
||||
let descendantPid;
|
||||
|
||||
try {
|
||||
const result = spawnSync(
|
||||
"timeout",
|
||||
[
|
||||
"--kill-after=1s",
|
||||
"0.2s",
|
||||
"node",
|
||||
scriptPath,
|
||||
summary,
|
||||
"external-stop",
|
||||
"--",
|
||||
"bash",
|
||||
"-lc",
|
||||
'bash -c \'trap "" TERM; printf "%s\\n" "$$" >"$PID_FILE"; while :; do sleep 1; done\' & wait',
|
||||
],
|
||||
{
|
||||
cwd: process.cwd(),
|
||||
encoding: "utf8",
|
||||
env: {
|
||||
...process.env,
|
||||
OPENCLAW_PLUGIN_LIFECYCLE_PHASE_TIMEOUT_MS: "5000",
|
||||
OPENCLAW_PLUGIN_LIFECYCLE_TIMEOUT_KILL_GRACE_MS: "100",
|
||||
PID_FILE: pidFile,
|
||||
try {
|
||||
const result = spawn(
|
||||
process.execPath,
|
||||
[
|
||||
scriptPath,
|
||||
summary,
|
||||
"external-stop",
|
||||
"--",
|
||||
"bash",
|
||||
"-lc",
|
||||
'bash -c \'trap "" TERM; printf "%s\\n" "$$" >"$PID_FILE"; while :; do sleep 1; done\' & wait',
|
||||
],
|
||||
{
|
||||
cwd: process.cwd(),
|
||||
env: {
|
||||
...process.env,
|
||||
OPENCLAW_PLUGIN_LIFECYCLE_PHASE_TIMEOUT_MS: "5000",
|
||||
OPENCLAW_PLUGIN_LIFECYCLE_TIMEOUT_KILL_GRACE_MS: "200",
|
||||
PID_FILE: pidFile,
|
||||
},
|
||||
stdio: "ignore",
|
||||
},
|
||||
timeout: 5000,
|
||||
},
|
||||
);
|
||||
);
|
||||
|
||||
descendantPid = Number.parseInt(readFileSync(pidFile, "utf8"), 10);
|
||||
expect(result.status).toBe(124);
|
||||
expect(waitForPidExit(descendantPid, 1000)).toBe(true);
|
||||
} finally {
|
||||
if (descendantPid > 0 && pidExists(descendantPid)) {
|
||||
process.kill(descendantPid, "SIGKILL");
|
||||
expect(waitForPath(pidFile, 2000)).toBe(true);
|
||||
descendantPid = Number.parseInt(readFileSync(pidFile, "utf8"), 10);
|
||||
result.kill("SIGTERM");
|
||||
const close = await waitForChildClose(result, 5000);
|
||||
expect(close.signal).toBe("SIGTERM");
|
||||
expect(waitForPidExit(descendantPid, 1000)).toBe(true);
|
||||
} finally {
|
||||
if (descendantPid > 0 && pidExists(descendantPid)) {
|
||||
process.kill(descendantPid, "SIGKILL");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
it.runIf(process.platform === "linux")(
|
||||
"exits promptly when externally terminated phases stop during grace",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue