mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-09 15:59:30 +00:00
fix(test): rebuild startup memory artifacts
This commit is contained in:
parent
653e8d1ea5
commit
4ce3c3e36c
5 changed files with 270 additions and 3 deletions
|
|
@ -7,11 +7,13 @@ import { fileURLToPath, pathToFileURL } from "node:url";
|
|||
|
||||
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const entryCandidates = ["dist/entry.js", "dist/entry.mjs"];
|
||||
const startupMetadataPath = "dist/cli-startup-metadata.json";
|
||||
|
||||
export function hasCliStartupBuild(params = {}) {
|
||||
const rootDir = params.rootDir ?? repoRoot;
|
||||
const exists = params.existsSync ?? existsSync;
|
||||
return entryCandidates.some((relativePath) => exists(path.join(rootDir, relativePath)));
|
||||
const hasEntry = entryCandidates.some((relativePath) => exists(path.join(rootDir, relativePath)));
|
||||
return hasEntry && exists(path.join(rootDir, startupMetadataPath));
|
||||
}
|
||||
|
||||
export function ensureCliStartupBuild(params = {}) {
|
||||
|
|
@ -24,7 +26,9 @@ export function ensureCliStartupBuild(params = {}) {
|
|||
const spawn = params.spawnSync ?? spawnSync;
|
||||
const buildScript = path.join(rootDir, "scripts", "build-all.mjs");
|
||||
|
||||
console.error("[cli-startup-build] dist/entry missing; running cliStartup build profile");
|
||||
console.error(
|
||||
"[cli-startup-build] dist startup entry or metadata missing; running cliStartup build profile",
|
||||
);
|
||||
const result = spawn(nodeExecPath, [buildScript, "cliStartup"], {
|
||||
cwd: rootDir,
|
||||
env: params.env ?? process.env,
|
||||
|
|
|
|||
102
scripts/ensure-extension-memory-build.mjs
Normal file
102
scripts/ensure-extension-memory-build.mjs
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { existsSync, readdirSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath, pathToFileURL } from "node:url";
|
||||
import {
|
||||
collectBundledPluginBuildEntries,
|
||||
NON_PACKAGED_BUNDLED_PLUGIN_DIRS,
|
||||
} from "./lib/bundled-plugin-build-entries.mjs";
|
||||
|
||||
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
||||
|
||||
function collectExpectedExtensionMemoryEntryIds(rootDir, env) {
|
||||
try {
|
||||
const entries = collectBundledPluginBuildEntries({ cwd: rootDir, env });
|
||||
return entries
|
||||
.filter(
|
||||
(entry) =>
|
||||
entry.hasManifest &&
|
||||
!NON_PACKAGED_BUNDLED_PLUGIN_DIRS.has(entry.id) &&
|
||||
entry.sourceEntries.length > 0,
|
||||
)
|
||||
.map((entry) => entry.id)
|
||||
.toSorted((left, right) => left.localeCompare(right));
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function hasBuiltExtensionMemoryEntries(params = {}) {
|
||||
const rootDir = params.rootDir ?? repoRoot;
|
||||
const exists = params.existsSync ?? existsSync;
|
||||
const readDir = params.readdirSync ?? readdirSync;
|
||||
const extensionsDir = path.join(rootDir, "dist", "extensions");
|
||||
if (!exists(extensionsDir)) {
|
||||
return false;
|
||||
}
|
||||
let extensionIds;
|
||||
try {
|
||||
extensionIds = readDir(extensionsDir);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
const requiredExtensionIds =
|
||||
params.requiredExtensionIds?.length > 0
|
||||
? params.requiredExtensionIds
|
||||
: collectExpectedExtensionMemoryEntryIds(rootDir, params.env ?? process.env);
|
||||
if (!requiredExtensionIds || requiredExtensionIds.length === 0) {
|
||||
return extensionIds.some((extensionId) =>
|
||||
exists(path.join(extensionsDir, extensionId, "index.js")),
|
||||
);
|
||||
}
|
||||
return requiredExtensionIds.every((extensionId) =>
|
||||
exists(path.join(extensionsDir, extensionId, "index.js")),
|
||||
);
|
||||
}
|
||||
|
||||
export function ensureExtensionMemoryBuild(params = {}) {
|
||||
const rootDir = params.rootDir ?? repoRoot;
|
||||
if (
|
||||
hasBuiltExtensionMemoryEntries({
|
||||
rootDir,
|
||||
existsSync: params.existsSync,
|
||||
readdirSync: params.readdirSync,
|
||||
requiredExtensionIds: params.requiredExtensionIds,
|
||||
env: params.env,
|
||||
})
|
||||
) {
|
||||
return { built: false };
|
||||
}
|
||||
|
||||
const nodeExecPath = params.nodeExecPath ?? process.execPath;
|
||||
const spawn = params.spawnSync ?? spawnSync;
|
||||
const buildScript = path.join(rootDir, "scripts", "build-all.mjs");
|
||||
|
||||
console.error(
|
||||
"[extension-memory-build] dist/extensions missing; running cliStartup build profile",
|
||||
);
|
||||
const result = spawn(nodeExecPath, [buildScript, "cliStartup"], {
|
||||
cwd: rootDir,
|
||||
env: params.env ?? process.env,
|
||||
stdio: params.stdio ?? "inherit",
|
||||
});
|
||||
if (result.error) {
|
||||
throw result.error;
|
||||
}
|
||||
const status = result.status ?? (result.signal ? 1 : 0);
|
||||
if (status !== 0) {
|
||||
throw new Error(`cliStartup build profile failed with exit code ${status}`);
|
||||
}
|
||||
return { built: true };
|
||||
}
|
||||
|
||||
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
||||
try {
|
||||
ensureExtensionMemoryBuild();
|
||||
} catch (error) {
|
||||
console.error(error instanceof Error ? error.message : String(error));
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import { spawn } from "node:child_process";
|
|||
import { existsSync, mkdtempSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { ensureExtensionMemoryBuild } from "./ensure-extension-memory-build.mjs";
|
||||
import { formatErrorMessage } from "./lib/error-format.mjs";
|
||||
|
||||
const DEFAULT_CONCURRENCY = 6;
|
||||
|
|
@ -241,6 +242,10 @@ function findExtensionEntries(repoRoot) {
|
|||
async function main() {
|
||||
const options = parseArgs(process.argv.slice(2));
|
||||
const repoRoot = process.cwd();
|
||||
ensureExtensionMemoryBuild({
|
||||
rootDir: repoRoot,
|
||||
requiredExtensionIds: options.extensions,
|
||||
});
|
||||
const allEntries = findExtensionEntries(repoRoot);
|
||||
const selectedEntries =
|
||||
options.extensions.length === 0
|
||||
|
|
|
|||
|
|
@ -28,14 +28,24 @@ describe("ensure-cli-startup-build", () => {
|
|||
const root = makeTempRoot();
|
||||
mkdirSync(path.join(root, "dist"), { recursive: true });
|
||||
writeFileSync(path.join(root, "dist", "entry.js"), "export {};\n", "utf8");
|
||||
writeFileSync(
|
||||
path.join(root, "dist", "cli-startup-metadata.json"),
|
||||
'{"rootHelpText":"help\\n"}\n',
|
||||
"utf8",
|
||||
);
|
||||
|
||||
expect(hasCliStartupBuild({ rootDir: root })).toBe(true);
|
||||
});
|
||||
|
||||
it("skips the build profile when dist entry output already exists", () => {
|
||||
it("skips the build profile when dist entry output and startup metadata already exist", () => {
|
||||
const root = makeTempRoot();
|
||||
mkdirSync(path.join(root, "dist"), { recursive: true });
|
||||
writeFileSync(path.join(root, "dist", "entry.mjs"), "export {};\n", "utf8");
|
||||
writeFileSync(
|
||||
path.join(root, "dist", "cli-startup-metadata.json"),
|
||||
'{"rootHelpText":"help\\n"}\n',
|
||||
"utf8",
|
||||
);
|
||||
|
||||
const result = ensureCliStartupBuild({
|
||||
rootDir: root,
|
||||
|
|
@ -47,6 +57,35 @@ describe("ensure-cli-startup-build", () => {
|
|||
expect(result).toEqual({ built: false });
|
||||
});
|
||||
|
||||
it("runs the cliStartup build profile when startup metadata is missing", () => {
|
||||
const root = makeTempRoot();
|
||||
mkdirSync(path.join(root, "dist"), { recursive: true });
|
||||
writeFileSync(path.join(root, "dist", "entry.js"), "export {};\n", "utf8");
|
||||
const calls: unknown[] = [];
|
||||
|
||||
const result = ensureCliStartupBuild({
|
||||
rootDir: root,
|
||||
nodeExecPath: "/node",
|
||||
spawnSync: (command, args, options) => {
|
||||
calls.push({ command, args, options });
|
||||
return { status: 0 };
|
||||
},
|
||||
stdio: "pipe",
|
||||
});
|
||||
|
||||
expect(result).toEqual({ built: true });
|
||||
expect(calls).toEqual([
|
||||
{
|
||||
command: "/node",
|
||||
args: [path.join(root, "scripts", "build-all.mjs"), "cliStartup"],
|
||||
options: expect.objectContaining({
|
||||
cwd: root,
|
||||
stdio: "pipe",
|
||||
}),
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("runs the cliStartup build profile when dist entry output is missing", () => {
|
||||
const root = makeTempRoot();
|
||||
const calls: unknown[] = [];
|
||||
|
|
|
|||
117
test/scripts/ensure-extension-memory-build.test.ts
Normal file
117
test/scripts/ensure-extension-memory-build.test.ts
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import {
|
||||
ensureExtensionMemoryBuild,
|
||||
hasBuiltExtensionMemoryEntries,
|
||||
} from "../../scripts/ensure-extension-memory-build.mjs";
|
||||
|
||||
const tempRoots: string[] = [];
|
||||
|
||||
function makeTempRoot(): string {
|
||||
const root = mkdtempSync(path.join(tmpdir(), "openclaw-extension-memory-build-"));
|
||||
tempRoots.push(root);
|
||||
mkdirSync(path.join(root, "scripts"), { recursive: true });
|
||||
writeFileSync(path.join(root, "scripts", "build-all.mjs"), "", "utf8");
|
||||
return root;
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
for (const root of tempRoots.splice(0)) {
|
||||
rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
describe("ensure-extension-memory-build", () => {
|
||||
it("detects existing built extension entrypoints", () => {
|
||||
const root = makeTempRoot();
|
||||
mkdirSync(path.join(root, "dist", "extensions", "telegram"), { recursive: true });
|
||||
writeFileSync(
|
||||
path.join(root, "dist", "extensions", "telegram", "index.js"),
|
||||
"export {};\n",
|
||||
"utf8",
|
||||
);
|
||||
|
||||
expect(
|
||||
hasBuiltExtensionMemoryEntries({ rootDir: root, requiredExtensionIds: ["telegram"] }),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("rejects partial built extension entrypoint sets", () => {
|
||||
const root = makeTempRoot();
|
||||
mkdirSync(path.join(root, "dist", "extensions", "discord"), { recursive: true });
|
||||
writeFileSync(
|
||||
path.join(root, "dist", "extensions", "discord", "index.js"),
|
||||
"export {};\n",
|
||||
"utf8",
|
||||
);
|
||||
|
||||
expect(
|
||||
hasBuiltExtensionMemoryEntries({
|
||||
rootDir: root,
|
||||
requiredExtensionIds: ["discord", "telegram"],
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("skips the build profile when extension entrypoints already exist", () => {
|
||||
const root = makeTempRoot();
|
||||
mkdirSync(path.join(root, "dist", "extensions", "discord"), { recursive: true });
|
||||
writeFileSync(
|
||||
path.join(root, "dist", "extensions", "discord", "index.js"),
|
||||
"export {};\n",
|
||||
"utf8",
|
||||
);
|
||||
|
||||
const result = ensureExtensionMemoryBuild({
|
||||
rootDir: root,
|
||||
requiredExtensionIds: ["discord"],
|
||||
spawnSync: () => {
|
||||
throw new Error("unexpected build");
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toEqual({ built: false });
|
||||
});
|
||||
|
||||
it("runs the cliStartup build profile when extension entrypoints are missing", () => {
|
||||
const root = makeTempRoot();
|
||||
const calls: unknown[] = [];
|
||||
|
||||
const result = ensureExtensionMemoryBuild({
|
||||
rootDir: root,
|
||||
requiredExtensionIds: ["discord"],
|
||||
nodeExecPath: "/node",
|
||||
spawnSync: (command, args, options) => {
|
||||
calls.push({ command, args, options });
|
||||
return { status: 0 };
|
||||
},
|
||||
stdio: "pipe",
|
||||
});
|
||||
|
||||
expect(result).toEqual({ built: true });
|
||||
expect(calls).toEqual([
|
||||
{
|
||||
command: "/node",
|
||||
args: [path.join(root, "scripts", "build-all.mjs"), "cliStartup"],
|
||||
options: expect.objectContaining({
|
||||
cwd: root,
|
||||
stdio: "pipe",
|
||||
}),
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("fails when the cliStartup build profile fails", () => {
|
||||
const root = makeTempRoot();
|
||||
|
||||
expect(() =>
|
||||
ensureExtensionMemoryBuild({
|
||||
rootDir: root,
|
||||
spawnSync: () => ({ status: 1 }),
|
||||
stdio: "pipe",
|
||||
}),
|
||||
).toThrow("cliStartup build profile failed with exit code 1");
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue