























@@ -561,7 +561,7 @@ describe("runGatewayUpdate", () => {
561561return { stdout: `HEAD is now at ${upstreamSha}`, stderr: "", code: 0 };
562562}
563563if (
564-key.startsWith("git -C /tmp/") &&
564+key.startsWith("git -C ") &&
565565preflightPrefixPattern.test(key) &&
566566key.includes(" checkout --detach ") &&
567567(key.endsWith(upstreamSha) || key.endsWith(selectedSha))
@@ -1081,6 +1081,191 @@ describe("runGatewayUpdate", () => {
10811081expect(preflightInstallCommands).toEqual(["pnpm install"]);
10821082});
108310831084+it("continues dev preflight after one candidate is missing its package manager", async () => {
1085+await setupGitCheckout({ packageManager: "npm@10.0.0" });
1086+await setupUiIndex();
1087+const upstreamSha = "bad123";
1088+const selectedSha = "good123";
1089+const calls: string[] = [];
1090+let managerVersionProbeCount = 0;
1091+const doctorNodePath = await resolveStableNodePath(process.execPath);
1092+const doctorCommand = `${doctorNodePath} ${path.join(tempDir, "openclaw.mjs")} doctor --non-interactive --fix`;
1093+1094+const writeCandidatePackageManager = async (key: string, packageManager: string) => {
1095+const match = /^git -C (?<root>\S+) checkout --detach /u.exec(key);
1096+const root = match?.groups?.root;
1097+if (!root) {
1098+throw new Error(`expected preflight checkout root in command: ${key}`);
1099+}
1100+await writePreflightPackageManagerFixture(root, packageManager);
1101+};
1102+const runCommand = async (argv: string[]) => {
1103+const key = argv.join(" ");
1104+calls.push(key);
1105+const responses = {
1106+ ...buildGitWorktreeProbeResponses(),
1107+[`git -C ${tempDir} fetch --all --prune --no-tags`]: { stdout: "" },
1108+[`git -C ${tempDir} rev-parse --abbrev-ref --symbolic-full-name @{upstream}`]: {
1109+stdout: "origin/main",
1110+},
1111+[`git -C ${tempDir} rev-parse @{upstream}`]: { stdout: upstreamSha },
1112+[`git -C ${tempDir} rev-list --max-count=10 ${upstreamSha}`]: {
1113+stdout: `${upstreamSha}\n${selectedSha}\n`,
1114+},
1115+[`git -C ${tempDir} rebase ${selectedSha}`]: { stdout: "" },
1116+[doctorCommand]: { stdout: "" },
1117+} satisfies Record<string, CommandResponse>;
1118+const response = responses[key];
1119+if (response) {
1120+return toCommandResult(response);
1121+}
1122+if (
1123+key.startsWith(`git -C ${tempDir} worktree add --detach /tmp/`) &&
1124+key.endsWith(` ${upstreamSha}`) &&
1125+preflightPrefixPattern.test(key)
1126+) {
1127+await writePreflightPackageManagerFixtureFromWorktreeAdd(key, "pnpm@8.0.0");
1128+return { stdout: `HEAD is now at ${upstreamSha}`, stderr: "", code: 0 };
1129+}
1130+if (
1131+key.startsWith("git -C /tmp/") &&
1132+preflightPrefixPattern.test(key) &&
1133+key.includes(" checkout --detach ") &&
1134+(key.endsWith(upstreamSha) || key.endsWith(selectedSha))
1135+) {
1136+await writeCandidatePackageManager(key, "npm@10.0.0");
1137+return { stdout: "", stderr: "", code: 0 };
1138+}
1139+if (key === "npm --version" || key === "pnpm --version" || key === "bun --version") {
1140+managerVersionProbeCount += 1;
1141+if (managerVersionProbeCount <= 3) {
1142+return { stdout: "", stderr: "not found", code: 1 };
1143+}
1144+}
1145+if (key === "npm --version") {
1146+return { stdout: "10.0.0", stderr: "", code: 0 };
1147+}
1148+if (key === "npm install" || key === "npm run build" || key === "npm run ui:build") {
1149+return { stdout: "", stderr: "", code: 0 };
1150+}
1151+if (
1152+key.startsWith(`git -C ${tempDir} worktree remove --force /tmp/`) &&
1153+preflightPrefixPattern.test(key)
1154+) {
1155+return { stdout: "", stderr: "", code: 0 };
1156+}
1157+if (key === `git -C ${tempDir} worktree prune`) {
1158+return { stdout: "", stderr: "", code: 0 };
1159+}
1160+return { stdout: "", stderr: "", code: 0 };
1161+};
1162+1163+const result = await runWithCommand(runCommand, { channel: "dev" });
1164+1165+expect(result.status).toBe("ok");
1166+const firstManagerProbeIndex = calls.indexOf("npm --version");
1167+const selectedCheckoutIndex = calls.findIndex(
1168+(call) =>
1169+call.startsWith("git -C ") &&
1170+preflightPrefixPattern.test(call) &&
1171+call.endsWith(` checkout --detach ${selectedSha}`),
1172+);
1173+expect(firstManagerProbeIndex).toBeGreaterThanOrEqual(0);
1174+expect(selectedCheckoutIndex).toBeGreaterThan(firstManagerProbeIndex);
1175+expect(calls).toContain(`git -C ${tempDir} rebase ${selectedSha}`);
1176+expect(calls).not.toContain(`git -C ${tempDir} rebase ${upstreamSha}`);
1177+});
1178+1179+it("does not let an earlier package manager failure mask a later candidate failure", async () => {
1180+await setupGitCheckout({ packageManager: "npm@10.0.0" });
1181+await setupUiIndex();
1182+const upstreamSha = "bad123";
1183+const olderSha = "older123";
1184+const calls: string[] = [];
1185+let managerVersionProbeCount = 0;
1186+1187+const writeCandidatePackageManager = async (key: string, packageManager: string) => {
1188+const match = /^git -C (?<root>\S+) checkout --detach /u.exec(key);
1189+const root = match?.groups?.root;
1190+if (!root) {
1191+throw new Error(`expected preflight checkout root in command: ${key}`);
1192+}
1193+await writePreflightPackageManagerFixture(root, packageManager);
1194+};
1195+const runCommand = async (argv: string[]) => {
1196+const key = argv.join(" ");
1197+calls.push(key);
1198+const responses = {
1199+ ...buildGitWorktreeProbeResponses(),
1200+[`git -C ${tempDir} fetch --all --prune --no-tags`]: { stdout: "" },
1201+[`git -C ${tempDir} rev-parse --abbrev-ref --symbolic-full-name @{upstream}`]: {
1202+stdout: "origin/main",
1203+},
1204+[`git -C ${tempDir} rev-parse @{upstream}`]: { stdout: upstreamSha },
1205+[`git -C ${tempDir} rev-list --max-count=10 ${upstreamSha}`]: {
1206+stdout: `${upstreamSha}\n${olderSha}\n`,
1207+},
1208+} satisfies Record<string, CommandResponse>;
1209+const response = responses[key];
1210+if (response) {
1211+return toCommandResult(response);
1212+}
1213+if (
1214+key.startsWith(`git -C ${tempDir} worktree add --detach /tmp/`) &&
1215+key.endsWith(` ${upstreamSha}`) &&
1216+preflightPrefixPattern.test(key)
1217+) {
1218+await writePreflightPackageManagerFixtureFromWorktreeAdd(key, "pnpm@8.0.0");
1219+return { stdout: `HEAD is now at ${upstreamSha}`, stderr: "", code: 0 };
1220+}
1221+if (
1222+key.startsWith("git -C /tmp/") &&
1223+preflightPrefixPattern.test(key) &&
1224+key.includes(" checkout --detach ") &&
1225+(key.endsWith(upstreamSha) || key.endsWith(olderSha))
1226+) {
1227+await writeCandidatePackageManager(key, "npm@10.0.0");
1228+return { stdout: "", stderr: "", code: 0 };
1229+}
1230+if (key === "npm --version" || key === "pnpm --version" || key === "bun --version") {
1231+managerVersionProbeCount += 1;
1232+if (managerVersionProbeCount <= 3) {
1233+return { stdout: "", stderr: "not found", code: 1 };
1234+}
1235+}
1236+if (key === "npm --version") {
1237+return { stdout: "10.0.0", stderr: "", code: 0 };
1238+}
1239+if (key === "npm install") {
1240+return { stdout: "", stderr: "", code: 0 };
1241+}
1242+if (key === "npm run build") {
1243+return { stdout: "", stderr: "build failed", code: 1 };
1244+}
1245+if (
1246+key.startsWith(`git -C ${tempDir} worktree remove --force /tmp/`) &&
1247+preflightPrefixPattern.test(key)
1248+) {
1249+return { stdout: "", stderr: "", code: 0 };
1250+}
1251+if (key === `git -C ${tempDir} worktree prune`) {
1252+return { stdout: "", stderr: "", code: 0 };
1253+}
1254+return { stdout: "", stderr: "", code: 0 };
1255+};
1256+1257+const result = await runWithCommand(runCommand, { channel: "dev" });
1258+1259+expect(result.status).toBe("error");
1260+expect(result.reason).toBe("preflight-no-good-commit");
1261+expect(result.steps.some((step) => step.name === "preflight package manager (bad123)")).toBe(
1262+true,
1263+);
1264+expect(result.steps.some((step) => step.name === "preflight build (older123)")).toBe(true);
1265+expect(calls).not.toContain(`git -C ${tempDir} rebase ${upstreamSha}`);
1266+expect(calls).not.toContain(`git -C ${tempDir} rebase ${olderSha}`);
1267+});
1268+10841269it("returns error and stops early when build fails", async () => {
10851270await setupGitCheckout({ packageManager: "pnpm@8.0.0" });
10861271const stableTag = "v1.0.1-1";
@@ -2171,6 +2356,9 @@ describe("runGatewayUpdate", () => {
2171235621722357expect(result.status).toBe("error");
21732358expect(result.reason).toBe("pnpm-npm-bootstrap-failed");
2359+expect(result.steps.some((step) => step.name === "preflight package manager (upstream)")).toBe(
2360+true,
2361+);
21742362expect(calls).not.toContain("npm run build");
21752363expect(calls).not.toContain("npm run lint");
21762364expect(calls).not.toContain("npm install");
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。