fix: stabilize parallels upgrade preflight

This commit is contained in:
Peter Steinberger
2026-04-08 02:17:36 +01:00
parent a8f8df7317
commit 0cb7168bc4
3 changed files with 33 additions and 21 deletions

View File

@@ -666,9 +666,7 @@ run_logged_guest_current_user_sh() {
local done_path="$3"
local timeout_s="$4"
local runner_path="$5"
local deadline rc runner_body launch_python
local runner_body_json runner_path_json log_path_json
local launch_python_b64
local deadline rc runner_body write_runner_cmd line
guest_current_user_exec /bin/rm -f "$log_path" "$done_path" "$runner_path"
runner_body="$(cat <<EOF
set -eu
@@ -681,15 +679,13 @@ cd "\$HOME"
$script
EOF
)"
runner_body_json="$(python3 -c 'import json, sys; print(json.dumps(sys.argv[1]))' "$runner_body")"
runner_path_json="$(python3 -c 'import json, sys; print(json.dumps(sys.argv[1]))' "$runner_path")"
log_path_json="$(python3 -c 'import json, sys; print(json.dumps(sys.argv[1]))' "$log_path")"
launch_python="import os, pathlib, subprocess; runner_path = $runner_path_json; log_path = $log_path_json; runner_body = $runner_body_json; pathlib.Path(runner_path).write_text(runner_body); os.chmod(runner_path, 0o755); log = open(log_path, 'ab', buffering=0); subprocess.Popen(['/bin/bash', runner_path], stdout=log, stderr=subprocess.STDOUT, stdin=subprocess.DEVNULL, start_new_session=True)"
launch_python_b64="$(printf '%s' "$launch_python" | /usr/bin/base64 | tr -d '\n')"
guest_current_user_exec /usr/bin/env \
"OPENCLAW_LAUNCH_PY_B64=$launch_python_b64" \
/usr/bin/python3 \
-c "import base64, os; exec(base64.b64decode(os.environ['OPENCLAW_LAUNCH_PY_B64']).decode())"
write_runner_cmd="/bin/rm -f $(shell_quote "$runner_path")"$'\n'
while IFS= read -r line; do
write_runner_cmd+="/usr/bin/printf '%s\\n' $(shell_quote "$line") >> $(shell_quote "$runner_path")"$'\n'
done <<< "$runner_body"
write_runner_cmd+="/bin/chmod +x $(shell_quote "$runner_path")"$'\n'
write_runner_cmd+="nohup /bin/bash $(shell_quote "$runner_path") > $(shell_quote "$log_path") 2>&1 < /dev/null &"
guest_current_user_sh "$write_runner_cmd"
deadline=$((SECONDS + timeout_s))
while (( SECONDS < deadline )); do
if guest_current_user_exec /bin/test -f "$done_path" >/dev/null 2>&1; then

View File

@@ -581,6 +581,7 @@ describe("runGatewayUpdate", () => {
const doctorNodePath = await resolveStableNodePath(process.execPath);
const doctorCommand = `${doctorNodePath} ${path.join(tempDir, "openclaw.mjs")} doctor --non-interactive --fix`;
let preflightInstallAttempts = 0;
let preflightIgnoreScriptsAttempts = 0;
let finalInstallAttempts = 0;
const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32");
@@ -649,6 +650,9 @@ describe("runGatewayUpdate", () => {
}
}
if (key === "pnpm install --ignore-scripts") {
if (options?.cwd && /(?:openclaw-update-preflight-|ocu-pf-)/.test(options.cwd)) {
preflightIgnoreScriptsAttempts += 1;
}
return { stdout: "", stderr: "", code: 0 };
}
if (key === "pnpm build" || key === "pnpm lint" || key === "pnpm ui:build") {
@@ -675,7 +679,8 @@ describe("runGatewayUpdate", () => {
const result = await runWithCommand(runCommand, { channel: "dev" });
expect(result.status).toBe("ok");
expect(preflightInstallAttempts).toBe(1);
expect(preflightInstallAttempts).toBe(0);
expect(preflightIgnoreScriptsAttempts).toBe(1);
expect(finalInstallAttempts).toBe(1);
expect(result.steps.map((step) => step.name)).toContain(
"preflight deps install (ignore scripts) (upstream)",

View File

@@ -358,6 +358,10 @@ function shouldRetryWindowsInstallIgnoringScripts(manager: "pnpm" | "bun" | "npm
return process.platform === "win32" && manager === "pnpm";
}
function shouldPreferIgnoreScriptsForWindowsPreflight(manager: "pnpm" | "bun" | "npm"): boolean {
return process.platform === "win32" && manager === "pnpm";
}
function isSupersededInstallFailure(
step: UpdateStepResult,
steps: readonly UpdateStepResult[],
@@ -670,20 +674,27 @@ export async function runGatewayUpdate(opts: UpdateRunnerOptions = {}): Promise<
continue;
}
const preflightIgnoreScripts = shouldPreferIgnoreScriptsForWindowsPreflight(
manager.manager,
);
const preflightIgnoreScriptsArgv = managerInstallIgnoreScriptsArgs(manager.manager);
const depsStepArgv =
preflightIgnoreScripts && preflightIgnoreScriptsArgv
? preflightIgnoreScriptsArgv
: managerInstallArgs(manager.manager, {
compatFallback: manager.fallback && manager.manager === "npm",
});
const depsStepName = preflightIgnoreScripts
? `preflight deps install (ignore scripts) (${shortSha})`
: `preflight deps install (${shortSha})`;
const depsStep = await runStep(
step(
`preflight deps install (${shortSha})`,
managerInstallArgs(manager.manager, {
compatFallback: manager.fallback && manager.manager === "npm",
}),
worktreeDir,
manager.env,
),
step(depsStepName, depsStepArgv, worktreeDir, manager.env),
);
steps.push(depsStep);
let finalDepsStep = depsStep;
if (
depsStep.exitCode !== 0 &&
!preflightIgnoreScripts &&
shouldRetryWindowsInstallIgnoringScripts(manager.manager)
) {
const retryArgv = managerInstallIgnoreScriptsArgs(manager.manager);