






















1+// Release preflight tests keep generated-artifact checks fail-closed for operators.
2+import { chmodSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3+import { delimiter, join } from "node:path";
4+import { spawnSync } from "node:child_process";
5+import { afterEach, describe, expect, it } from "vitest";
6+import { cleanupTempDirs, makeTempDir } from "../helpers/temp-dir.js";
7+8+const SCRIPT = "scripts/release-preflight.mjs";
9+const CHECK_COMMANDS = [
10+"deps:root-ownership:check",
11+"deps:shrinkwrap:check",
12+"plugins:sync:check",
13+"plugins:inventory:check",
14+"config:schema:check",
15+"config:channels:check",
16+"config:docs:check",
17+"plugin-sdk:check-exports",
18+"plugin-sdk:api:check",
19+"plugin-sdk:surface:check",
20+];
21+const FIX_COMMANDS = [
22+"plugins:sync",
23+"deps:shrinkwrap:changed:generate",
24+"plugins:inventory:gen",
25+"config:schema:gen",
26+"config:channels:gen",
27+"config:docs:gen",
28+"plugin-sdk:sync-exports",
29+"plugin-sdk:api:gen",
30+];
31+32+const tempDirs = new Set<string>();
33+34+afterEach(() => {
35+cleanupTempDirs(tempDirs);
36+});
37+38+function makeFakePnpm(): { binDir: string; logPath: string } {
39+const root = makeTempDir(tempDirs, "openclaw-release-preflight-");
40+const binDir = join(root, "bin");
41+const logPath = join(root, "pnpm.log");
42+mkdirSync(binDir);
43+const pnpmPath = join(binDir, "pnpm");
44+writeFileSync(
45+pnpmPath,
46+`#!/usr/bin/env node
47+import { appendFileSync } from "node:fs";
48+49+const command = process.argv.slice(2).join(" ");
50+appendFileSync(process.env.OPENCLAW_RELEASE_PREFLIGHT_PNPM_LOG, command + "\\n");
51+const failures = new Set((process.env.OPENCLAW_RELEASE_PREFLIGHT_FAIL_COMMANDS ?? "").split(";").filter(Boolean));
52+process.exit(failures.has(command) ? 7 : 0);
53+`,
54+{ mode: 0o755 },
55+);
56+chmodSync(pnpmPath, 0o755);
57+return { binDir, logPath };
58+}
59+60+function runPreflight(
61+args: string[],
62+fakePnpm?: ReturnType<typeof makeFakePnpm>,
63+extraEnv: NodeJS.ProcessEnv = {},
64+) {
65+return spawnSync(process.execPath, [SCRIPT, ...args], {
66+cwd: process.cwd(),
67+encoding: "utf8",
68+env: {
69+ ...process.env,
70+ ...extraEnv,
71+ ...(fakePnpm
72+ ? {
73+OPENCLAW_RELEASE_PREFLIGHT_PNPM_LOG: fakePnpm.logPath,
74+PATH: `${fakePnpm.binDir}${delimiter}${process.env.PATH ?? ""}`,
75+}
76+ : {}),
77+},
78+});
79+}
80+81+function readPnpmLog(logPath: string): string[] {
82+return readFileSync(logPath, "utf8").trimEnd().split("\n").filter(Boolean);
83+}
84+85+describe("scripts/release-preflight.mjs", () => {
86+it("rejects unknown arguments before running release checks", () => {
87+const result = runPreflight(["--fiix"]);
88+89+expect(result.status).toBe(1);
90+expect(result.stderr).toContain("Unknown release preflight argument: --fiix");
91+expect(result.stderr).toContain("Usage: node scripts/release-preflight.mjs [--check|--fix]");
92+expect(result.stdout).toBe("");
93+});
94+95+it("runs every check command and reports all failed release artifact checks", () => {
96+const fakePnpm = makeFakePnpm();
97+const result = runPreflight(["--check"], fakePnpm, {
98+OPENCLAW_RELEASE_PREFLIGHT_FAIL_COMMANDS: "plugins:sync:check;config:docs:check",
99+});
100+101+expect(result.status).toBe(1);
102+expect(readPnpmLog(fakePnpm.logPath)).toEqual(CHECK_COMMANDS);
103+expect(result.stderr).toContain("- plugin versions: exit 7 (pnpm plugins:sync:check)");
104+expect(result.stderr).toContain("- config docs baseline: exit 7 (pnpm config:docs:check)");
105+});
106+107+it("stops refresh mode at the first failed generator before running checks", () => {
108+const fakePnpm = makeFakePnpm();
109+const result = spawnSync(process.execPath, [SCRIPT, "--fix"], {
110+cwd: process.cwd(),
111+encoding: "utf8",
112+env: {
113+ ...process.env,
114+OPENCLAW_RELEASE_PREFLIGHT_FAIL_COMMANDS: "deps:shrinkwrap:changed:generate",
115+OPENCLAW_RELEASE_PREFLIGHT_PNPM_LOG: fakePnpm.logPath,
116+PATH: `${fakePnpm.binDir}${delimiter}${process.env.PATH ?? ""}`,
117+},
118+});
119+120+expect(result.status).toBe(1);
121+expect(readPnpmLog(fakePnpm.logPath)).toEqual(FIX_COMMANDS.slice(0, 2));
122+expect(result.stderr).toContain(
123+"- npm shrinkwraps: exit 7 (pnpm deps:shrinkwrap:changed:generate)",
124+);
125+});
126+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。