mirror of
https://github.com/openclaw/openclaw.git
synced 2026-10-29 03:01:18 +00:00
* test(infra): deslop z0586 tests * test(ui): deslop z0589 tests * test(ui): deslop z0589 tests * test(ui): deslop z0591 tests * test(ui): deslop z0591 tests * test(matrix): deslop z0592 tests * test(matrix): deslop z0592 tests * test(usage): deslop z0594 tests * test(usage): deslop z0594 tests * test(anthropic): deslop z0593 tests * test(anthropic): deslop z0593 tests * test(protocol): deslop z0595 tests * test(protocol): deslop z0595 tests * test(plugins): deslop z0600 tests * test(agents): deslop z0597 tests * test(agents): deslop z0597 tests * test(daemon): deslop z0596 tests * test(daemon): deslop z0596 tests * test(daemon): deslop z0596 tests * test(models): deslop z0598 tests * test(models): deslop z0598 tests * test(integration): deslop z0599 tests * test(integration): deslop z0599 tests * test(integration): deslop z0599 tests * test(agents): deslop z0590 tests * test(agents): deslop z0590 tests * test(plugin-sdk): deslop z0604 tests * test(process): deslop z0601 tests * test(process): deslop z0601 tests * test(process): preserve input fixture cleanup on setup failure * test(infra): drop unused backup fixture expansion after replay * test: preserve hook lifecycles and independent regression fixtures * test(models): keep refresh cleanup callback void * test: document isolated mocks and retain explicit export sorting * test: prune superseded mock export baseline entries
138 lines
4.3 KiB
TypeScript
138 lines
4.3 KiB
TypeScript
import { execFileSync } from "node:child_process";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { makeTempDir as makeTempRepoRoot } from "./helpers/temp-dir.js";
|
|
|
|
const baseGitEnv = {
|
|
GIT_CONFIG_NOSYSTEM: "1",
|
|
GIT_CONFIG_GLOBAL: "/dev/null",
|
|
GIT_TERMINAL_PROMPT: "0",
|
|
GIT_CONFIG_COUNT: "4",
|
|
GIT_CONFIG_KEY_0: "user.name",
|
|
GIT_CONFIG_VALUE_0: "Hook Test",
|
|
GIT_CONFIG_KEY_1: "user.email",
|
|
GIT_CONFIG_VALUE_1: "hook@example.invalid",
|
|
GIT_CONFIG_KEY_2: "commit.gpgSign",
|
|
GIT_CONFIG_VALUE_2: "false",
|
|
GIT_CONFIG_KEY_3: "init.templateDir",
|
|
GIT_CONFIG_VALUE_3: "",
|
|
};
|
|
export const rulePath = ".git/private rules.txt";
|
|
export const ruleSetting = "hooks.blockedLiteralsFile";
|
|
export const literals = ["GUARD_SYNTHETIC_ALPHA", "GUARD_SYNTHETIC_BETA_[x].*42"] as const;
|
|
|
|
export const run = (cwd: string, cmd: string, args: string[] = [], env?: NodeJS.ProcessEnv) =>
|
|
execFileSync(cmd, args, {
|
|
cwd,
|
|
encoding: "utf8",
|
|
stdio: "pipe",
|
|
timeout: 20_000,
|
|
maxBuffer: 24 * 1024 * 1024,
|
|
env: {
|
|
PATH: process.env.PATH,
|
|
HOME: cwd,
|
|
TMPDIR: cwd,
|
|
LC_ALL: "C",
|
|
TZ: "UTC",
|
|
...baseGitEnv,
|
|
...env,
|
|
},
|
|
}).trim();
|
|
|
|
export const runFailure = (...args: Parameters<typeof run>) => {
|
|
try {
|
|
run(...args);
|
|
} catch (error) {
|
|
if (!(error instanceof Error) || !("status" in error)) {
|
|
throw error;
|
|
}
|
|
const failure = error as Error & {
|
|
status?: number;
|
|
stderr?: string;
|
|
stdout?: string;
|
|
};
|
|
return {
|
|
status: failure.status ?? 1,
|
|
stderr: failure.stderr ?? "",
|
|
stdout: failure.stdout ?? "",
|
|
};
|
|
}
|
|
|
|
throw new Error("expected command to fail");
|
|
};
|
|
|
|
export function writeExecutable(dir: string, name: string, contents: string): void {
|
|
fs.writeFileSync(path.join(dir, name), contents, { mode: 0o755 });
|
|
}
|
|
|
|
export function installPreCommitFixture(dir: string): string {
|
|
const at = (...names: string[]) => path.join(dir, ...names);
|
|
for (const name of ["git-hooks", "scripts/pre-commit", "node_modules/.bin", "bin"]) {
|
|
fs.mkdirSync(at(name), { recursive: true });
|
|
}
|
|
fs.symlinkSync(
|
|
path.join(process.cwd(), "git-hooks", "pre-commit"),
|
|
at("git-hooks", "pre-commit"),
|
|
);
|
|
for (const name of [
|
|
"run-node-tool.sh",
|
|
"filter-staged-files.mjs",
|
|
"guard-staged-content.mjs",
|
|
"format-staged.sh",
|
|
]) {
|
|
fs.copyFileSync(
|
|
path.join(process.cwd(), "scripts/pre-commit", name),
|
|
at("scripts/pre-commit", name),
|
|
);
|
|
}
|
|
// Freshness checks import repository planners; hook behavior tests isolate formatting and guards.
|
|
fs.writeFileSync(at("scripts/pre-commit/check-staged-freshness.mts"), "");
|
|
const privateRules = path.resolve(
|
|
dir,
|
|
run(dir, "git", ["rev-parse", "--git-path", "private rules.txt"]),
|
|
);
|
|
fs.writeFileSync(privateRules, `${literals.join("\n")}\n`, { mode: 0o600 });
|
|
run(dir, "git", ["config", "--local", ruleSetting, privateRules]);
|
|
// Stdin mode must echo the blob or the hook treats the empty output as formatter failure.
|
|
writeExecutable(
|
|
at("node_modules/.bin"),
|
|
"oxfmt",
|
|
'#!/bin/sh\ncase "$*" in *--stdin-filepath=*) cat ;; esac\nexit 0\n',
|
|
);
|
|
|
|
return at("bin");
|
|
}
|
|
|
|
export function createContentGuardFixture(tempDirs: string[]): string {
|
|
const dir = makeTempRepoRoot(tempDirs, "openclaw-content-guard-");
|
|
run(dir, "git", ["init", "-q", "--initial-branch=main"]);
|
|
installPreCommitFixture(dir);
|
|
return dir;
|
|
}
|
|
|
|
export function stageContent(dir: string, name: string, content: string | Buffer): void {
|
|
fs.mkdirSync(path.dirname(path.join(dir, name)), { recursive: true });
|
|
fs.writeFileSync(path.join(dir, name), content);
|
|
run(dir, "git", ["--literal-pathspecs", "add", "-f", "--", name]);
|
|
}
|
|
|
|
export const commitArgs = ["-c", "core.hooksPath=git-hooks", "commit", "-qm", "guard proof"];
|
|
|
|
export function installFormattingRecorder(dir: string, body = ""): string {
|
|
const logPath = path.join(dir, "hook-tool.log");
|
|
writeExecutable(
|
|
path.join(dir, "node_modules/.bin"),
|
|
"oxfmt",
|
|
`#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
printf 'oxfmt %s\n' "$*" >> hook-tool.log
|
|
case "$*" in *--stdin-filepath=*) cat ;; esac
|
|
${body}
|
|
`,
|
|
);
|
|
return logPath;
|
|
}
|
|
|
|
export function readFormatterLog(logPath: string): string[] {
|
|
return fs.existsSync(logPath) ? fs.readFileSync(logPath, "utf8").split("\n").filter(Boolean) : [];
|
|
}
|