From 1fdd7d2a9aed342397bfef20348a1c5fd50fa5ff Mon Sep 17 00:00:00 2001 From: Mason Huang Date: Wed, 1 Jul 2026 21:33:37 +0800 Subject: [PATCH] test: read staged temp helper source from index --- scripts/report-test-temp-creations.mjs | 36 +++++++-- .../report-test-temp-creations.test.ts | 76 +++++++++++++++++-- 2 files changed, 101 insertions(+), 11 deletions(-) diff --git a/scripts/report-test-temp-creations.mjs b/scripts/report-test-temp-creations.mjs index 9324e36ca1e0..4e7325235a72 100644 --- a/scripts/report-test-temp-creations.mjs +++ b/scripts/report-test-temp-creations.mjs @@ -143,6 +143,33 @@ function readDiff(args, cwd = process.cwd()) { }); } +function readWorktreeSource(filePath, cwd) { + try { + return fs.readFileSync(path.join(cwd, filePath), "utf8"); + } catch { + return ""; + } +} + +function readStagedSource(filePath, cwd) { + try { + return execFileSync("git", ["show", `:${filePath}`], { + cwd, + encoding: "utf8", + maxBuffer: 64 * 1024 * 1024, + stdio: ["ignore", "pipe", "pipe"], + }); + } catch { + return ""; + } +} + +function readSourceForDiff(filePath, args, cwd) { + // Staged checks must parse the index blob. Reading the worktree mixes in + // unstaged edits and can warn on code that will not be committed. + return args.staged ? readStagedSource(filePath, cwd) : readWorktreeSource(filePath, cwd); +} + function stripKnownExtension(filePath) { return filePath.replace(/\.(?:c|m)?[jt]sx?$/u, ""); } @@ -419,13 +446,10 @@ export async function main(argv, io) { return 0; } - const findings = collectTempCreationFindingsFromDiff(readDiff(args), { + const cwd = process.cwd(); + const findings = collectTempCreationFindingsFromDiff(readDiff(args, cwd), { readFile(filePath) { - try { - return fs.readFileSync(path.join(process.cwd(), filePath), "utf8"); - } catch { - return ""; - } + return readSourceForDiff(filePath, args, cwd); }, }); if (args.json) { diff --git a/test/scripts/report-test-temp-creations.test.ts b/test/scripts/report-test-temp-creations.test.ts index 560090db67f1..b018bc77e30e 100644 --- a/test/scripts/report-test-temp-creations.test.ts +++ b/test/scripts/report-test-temp-creations.test.ts @@ -116,11 +116,11 @@ describe("report-test-temp-creations", () => { it("reports repository-observed mkdtemp call forms", () => { const sources = [ - 'const root = await fs.promises.mkdtemp(path.join(os.tmpdir(), "case-"));', - 'const root = await fs.mkdtemp(path.join(os.tmpdir(), "case-"));', - 'const root = await fsPromises.mkdtemp("/tmp/openclaw-case-");', - 'const root = await mkdtemp(path.join(tmpdir(), "case-"));', - 'const root = mkdtempSync(join(tmpdir(), "case-"));', + ["const root = await fs.promises.", "mkdtemp", '(path.join(os.tmpdir(), "case-"));'].join(""), + ["const root = await fs.", "mkdtemp", '(path.join(os.tmpdir(), "case-"));'].join(""), + ["const root = await fsPromises.", "mkdtemp", '("/tmp/openclaw-case-");'].join(""), + ["const root = await ", "mkdtemp", '(path.join(tmpdir(), "case-"));'].join(""), + ["const root = ", "mkdtemp", 'Sync(join(tmpdir(), "case-"));'].join(""), ]; const diff = [ "diff --git a/test/scripts/temp-patterns.test.ts b/test/scripts/temp-patterns.test.ts", @@ -394,6 +394,72 @@ describe("report-test-temp-creations", () => { ); }); + it("reads staged source for manual helper scans", () => { + const root = tempDirs.make("openclaw-temp-report-staged-source-"); + const env = createNestedGitEnv(); + execFileSync("git", ["init", "-q", "--initial-branch=main"], { cwd: root, env }); + execFileSync( + "git", + [ + "-c", + "user.email=test@example.com", + "-c", + "user.name=Test User", + "commit", + "--allow-empty", + "-q", + "-m", + "initial", + ], + { cwd: root, env }, + ); + + fs.mkdirSync(path.join(root, "test", "scripts"), { recursive: true }); + const stagedManualFile = path.join(root, "test", "scripts", "staged-manual.test.ts"); + const stagedAutoFile = path.join(root, "test", "scripts", "staged-auto.test.ts"); + const manualSource = [ + 'import { makeTempDir } from "../helpers/temp-dir.js";', + "const tempDirs = new Set();", + 'const workspace = makeTempDir(tempDirs, "case-");', + ].join("\n"); + const autoSource = [ + 'import { useAutoCleanupTempDirTracker } from "../helpers/temp-dir.js";', + "const tempDirs = useAutoCleanupTempDirTracker();", + 'const workspace = tempDirs.make("case-");', + ].join("\n"); + fs.writeFileSync(stagedManualFile, `${manualSource}\n`, "utf8"); + fs.writeFileSync(stagedAutoFile, `${autoSource}\n`, "utf8"); + execFileSync("git", ["add", "test/scripts"], { cwd: root, env }); + fs.writeFileSync(stagedManualFile, `${autoSource}\n`, "utf8"); + fs.writeFileSync(stagedAutoFile, `${manualSource}\n`, "utf8"); + + const result = spawnSync( + process.execPath, + [path.join(repoRoot, "scripts", "report-test-temp-creations.mjs"), "--staged", "--json"], + { + cwd: root, + encoding: "utf8", + env, + }, + ); + + expect(result.status).toBe(0); + expect(JSON.parse(result.stdout)).toEqual([ + { + file: "test/scripts/staged-manual.test.ts", + line: 1, + reason: "new manual temp-dir helper import", + source: 'import { makeTempDir } from "../helpers/temp-dir.js";', + }, + { + file: "test/scripts/staged-manual.test.ts", + line: 3, + reason: "new manual temp-dir helper usage", + source: 'const workspace = makeTempDir(tempDirs, "case-");', + }, + ]); + }); + it("exits non-zero for staged findings when requested", () => { const root = tempDirs.make("openclaw-temp-report-"); const env = createNestedGitEnv();