mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-24 19:35:28 -06:00
fix(test): bound shared git inventory lookup (#111171)
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
This commit is contained in:
@@ -57,9 +57,11 @@ function expectNonEmptyStringList(values: readonly string[], label: string) {
|
||||
}
|
||||
|
||||
function listTrackedSourceFiles(): string[] {
|
||||
return (listGitTrackedFiles({ pathspecs: sourceRootsForDeprecatedCallGuard }) ?? []).filter(
|
||||
(file) => /\.(?:ts|tsx|mts|cts)$/u.test(file),
|
||||
);
|
||||
const files = listGitTrackedFiles({ pathspecs: sourceRootsForDeprecatedCallGuard });
|
||||
if (!files) {
|
||||
throw new Error("unable to list tracked source files for the deprecated-call guard");
|
||||
}
|
||||
return files.filter((file) => /\.(?:ts|tsx|mts|cts)$/u.test(file));
|
||||
}
|
||||
|
||||
describe("plugin compatibility registry", () => {
|
||||
|
||||
@@ -257,7 +257,10 @@ describe("config footprint guardrails", () => {
|
||||
]);
|
||||
const facadeImportPattern =
|
||||
/\bfrom\s*["'][^"']*(?:channel-config-primitives|bundled-channel-config-schema)(?:\.js)?["']/u;
|
||||
const files = listGitTrackedFiles({ repoRoot: REPO_ROOT, pathspecs: "src" }) ?? [];
|
||||
const files = listGitTrackedFiles({ repoRoot: REPO_ROOT, pathspecs: "src" });
|
||||
if (!files) {
|
||||
throw new Error("unable to list tracked source files for the config facade guard");
|
||||
}
|
||||
|
||||
const offenders = files.filter((file) => {
|
||||
if (!(file.endsWith(".ts") || file.endsWith(".tsx")) || allowedShellImporters.has(file)) {
|
||||
|
||||
@@ -34,12 +34,14 @@ const LEGACY_MODEL_CATALOG_BRIDGES = new Map([
|
||||
]);
|
||||
|
||||
function listSourceFiles(): string[] {
|
||||
return (
|
||||
listGitTrackedFiles({
|
||||
repoRoot: REPO_ROOT,
|
||||
pathspecs: ["src", "extensions", "packages", "test"],
|
||||
}) ?? []
|
||||
)
|
||||
const files = listGitTrackedFiles({
|
||||
repoRoot: REPO_ROOT,
|
||||
pathspecs: ["src", "extensions", "packages", "test"],
|
||||
});
|
||||
if (!files) {
|
||||
throw new Error("unable to list tracked source files for the model-catalog import guard");
|
||||
}
|
||||
return files
|
||||
.filter((file) => /\.(?:[cm]?ts|tsx|mts|cts)$/u.test(file))
|
||||
.filter((file) => fs.existsSync(path.join(REPO_ROOT, file)));
|
||||
}
|
||||
|
||||
@@ -465,11 +465,13 @@ function collectNewDeprecatedMemoryEmbeddingProviderApiFiles(): string[] {
|
||||
|
||||
function collectNewDeprecatedMemoryEmbeddingProviderManifestFiles(): string[] {
|
||||
const files: string[] = [];
|
||||
const manifestFiles =
|
||||
listGitTrackedFiles({
|
||||
repoRoot: REPO_ROOT,
|
||||
pathspecs: "extensions/**/openclaw.plugin.json",
|
||||
}) ?? [];
|
||||
const manifestFiles = listGitTrackedFiles({
|
||||
repoRoot: REPO_ROOT,
|
||||
pathspecs: "extensions/**/openclaw.plugin.json",
|
||||
});
|
||||
if (!manifestFiles) {
|
||||
throw new Error("unable to list plugin manifests for the deprecated manifest guard");
|
||||
}
|
||||
for (const repoRelativePath of manifestFiles) {
|
||||
const source = fs.readFileSync(resolve(REPO_ROOT, repoRelativePath), "utf8");
|
||||
if (
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { withTempDir } from "./temp-dir.js";
|
||||
|
||||
const spawnSyncMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock("node:child_process", () => ({
|
||||
spawnSync: spawnSyncMock,
|
||||
}));
|
||||
|
||||
import { listGitTrackedFiles } from "./repo-files.js";
|
||||
|
||||
describe("listGitTrackedFiles", () => {
|
||||
beforeEach(() => {
|
||||
spawnSyncMock.mockReset();
|
||||
});
|
||||
|
||||
it("bounds Git inventory lookup and returns sorted existing files", async () => {
|
||||
await withTempDir("openclaw-repo-files-", async (repoRoot) => {
|
||||
await fs.writeFile(path.join(repoRoot, "z.ts"), "");
|
||||
await fs.writeFile(path.join(repoRoot, "a.ts"), "");
|
||||
spawnSyncMock.mockReturnValue({
|
||||
status: 0,
|
||||
stdout: "z.ts\nmissing.ts\na.ts\n",
|
||||
});
|
||||
|
||||
expect(listGitTrackedFiles({ repoRoot, pathspecs: "src" })).toEqual(["a.ts", "z.ts"]);
|
||||
expect(spawnSyncMock).toHaveBeenCalledWith(
|
||||
"git",
|
||||
["ls-files", "--", "src"],
|
||||
expect.objectContaining({
|
||||
cwd: repoRoot,
|
||||
killSignal: "SIGKILL",
|
||||
timeout: 5_000,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("caches a timed-out inventory lookup as unavailable", async () => {
|
||||
await withTempDir("openclaw-repo-files-timeout-", async (repoRoot) => {
|
||||
spawnSyncMock.mockReturnValue({
|
||||
error: Object.assign(new Error("spawnSync git ETIMEDOUT"), { code: "ETIMEDOUT" }),
|
||||
signal: "SIGKILL",
|
||||
status: null,
|
||||
stdout: "",
|
||||
});
|
||||
const params = { repoRoot, pathspecs: ["src", "extensions"] };
|
||||
|
||||
expect(listGitTrackedFiles(params)).toBeNull();
|
||||
expect(listGitTrackedFiles(params)).toBeNull();
|
||||
expect(spawnSyncMock).toHaveBeenCalledOnce();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -3,6 +3,7 @@ import { spawnSync } from "node:child_process";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
const GIT_LS_FILES_TIMEOUT_MS = 5_000;
|
||||
const gitTrackedFilesCache = new Map<string, string[] | null>();
|
||||
|
||||
function filterExistingRepoFiles(repoRoot: string, files: readonly string[]): string[] {
|
||||
@@ -36,8 +37,11 @@ export function listGitTrackedFiles(params: {
|
||||
const result = spawnSync("git", ["ls-files", "--", ...pathspecs], {
|
||||
cwd: repoRoot,
|
||||
encoding: "utf8",
|
||||
// Bound repository scans; SIGKILL avoids waiting on a hung Git process after timeout.
|
||||
killSignal: "SIGKILL",
|
||||
maxBuffer: 16 * 1024 * 1024,
|
||||
stdio: ["ignore", "pipe", "ignore"],
|
||||
timeout: GIT_LS_FILES_TIMEOUT_MS,
|
||||
});
|
||||
if (result.status !== 0) {
|
||||
gitTrackedFilesCache.set(cacheKey, null);
|
||||
|
||||
Reference in New Issue
Block a user