





















1+// Plugin release pretag pack check tests cover its script-local target and command routing.
2+import { mkdirSync, writeFileSync } from "node:fs";
3+import { join } from "node:path";
4+import { afterEach, describe, expect, it, vi } from "vitest";
5+import { OPENCLAW_PLUGIN_NPM_REPOSITORY_URL } from "../../scripts/lib/plugin-npm-release.ts";
6+import {
7+collectPluginReleasePretagPackTargets,
8+runPluginReleasePretagPackCheck,
9+} from "../../scripts/plugin-release-pretag-pack-check.ts";
10+import { cleanupTempDirs, makeTempRepoRoot, writeJsonFile } from "../helpers/temp-repo.js";
11+12+const { execFileSyncMock } = vi.hoisted(() => ({
13+execFileSyncMock: vi.fn(),
14+}));
15+16+vi.mock("node:child_process", async () => {
17+const actual = await vi.importActual<typeof import("node:child_process")>("node:child_process");
18+return {
19+ ...actual,
20+execFileSync: execFileSyncMock,
21+};
22+});
23+24+const tempDirs: string[] = [];
25+26+type ExecOptions = {
27+cwd?: string;
28+env?: NodeJS.ProcessEnv;
29+stdio?: unknown;
30+};
31+32+afterEach(() => {
33+cleanupTempDirs(tempDirs);
34+execFileSyncMock.mockReset();
35+});
36+37+function createDualPublishPluginRepo() {
38+const repoDir = makeTempRepoRoot(tempDirs, "openclaw-plugin-pretag-pack-");
39+const packageDir = join(repoDir, "extensions", "demo-plugin");
40+mkdirSync(packageDir, { recursive: true });
41+writeJsonFile(join(repoDir, "package.json"), { name: "openclaw-test-root", type: "module" });
42+writeJsonFile(join(packageDir, "package.json"), {
43+name: "@openclaw/demo-plugin",
44+version: "2026.4.10",
45+type: "module",
46+repository: {
47+type: "git",
48+url: OPENCLAW_PLUGIN_NPM_REPOSITORY_URL,
49+},
50+openclaw: {
51+extensions: ["./index.ts"],
52+compat: {
53+pluginApi: ">=2026.4.10",
54+},
55+build: {
56+openclawVersion: "2026.4.10",
57+},
58+install: {
59+npmSpec: "@openclaw/demo-plugin",
60+},
61+release: {
62+publishToClawHub: true,
63+publishToNpm: true,
64+},
65+},
66+});
67+writeFileSync(join(packageDir, "README.md"), "# Demo plugin\n");
68+writeFileSync(join(packageDir, "index.ts"), "export const demo = 1;\n");
69+70+return repoDir;
71+}
72+73+function callOptions(index: number): ExecOptions {
74+return execFileSyncMock.mock.calls[index]?.[2] as ExecOptions;
75+}
76+77+describe("scripts/plugin-release-pretag-pack-check.ts", () => {
78+it("collects dual-published plugin targets for npm and ClawHub pack checks", () => {
79+const repoDir = createDualPublishPluginRepo();
80+81+expect(collectPluginReleasePretagPackTargets(repoDir)).toEqual([
82+{
83+packageDir: "extensions/demo-plugin",
84+packageName: "@openclaw/demo-plugin",
85+packClawHub: true,
86+packNpm: true,
87+},
88+]);
89+});
90+91+it("runs runtime build, npm pack, and ClawHub pack commands for selected targets", () => {
92+const repoDir = createDualPublishPluginRepo();
93+execFileSyncMock.mockImplementation(() => "");
94+95+runPluginReleasePretagPackCheck(repoDir);
96+97+expect(execFileSyncMock).toHaveBeenCalledTimes(3);
98+expect(execFileSyncMock.mock.calls[0]?.slice(0, 2)).toEqual([
99+process.execPath,
100+[
101+"scripts/check-plugin-npm-runtime-builds.mjs",
102+"--package",
103+"extensions/demo-plugin",
104+],
105+]);
106+expect(callOptions(0)).toMatchObject({ cwd: repoDir, stdio: "inherit" });
107+108+expect(execFileSyncMock.mock.calls[1]?.slice(0, 2)).toEqual([
109+"bash",
110+["scripts/plugin-npm-publish.sh", "--pack-dry-run", "extensions/demo-plugin"],
111+]);
112+expect(callOptions(1)).toMatchObject({
113+cwd: repoDir,
114+env: { OPENCLAW_PLUGIN_NPM_RUNTIME_BUILD: "0" },
115+stdio: ["inherit", "ignore", "inherit"],
116+});
117+118+expect(execFileSyncMock.mock.calls[2]?.slice(0, 2)).toEqual([
119+"bash",
120+["scripts/plugin-clawhub-publish.sh", "--pack", "extensions/demo-plugin"],
121+]);
122+expect(callOptions(2)).toMatchObject({
123+cwd: repoDir,
124+env: { OPENCLAW_PLUGIN_NPM_RUNTIME_BUILD: "0" },
125+stdio: ["inherit", "ignore", "inherit"],
126+});
127+expect(callOptions(2).env?.OPENCLAW_CLAWHUB_PACK_OUTPUT_DIR).toContain("clawhub-0");
128+});
129+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。