From 158b3bf562b09874d110e82a52e73f1fc92ad082 Mon Sep 17 00:00:00 2001 From: Matt Toohey Date: Fri, 30 Oct 2026 14:37:38 +1100 Subject: [PATCH] test(scripts): stop file-size fixtures leaking git repos and fsmonitor daemons (#8727) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary The file-size ratchet tests (`scripts/check-file-sizes-core.test.mjs`, run by `just file-size-check`) created fixture git repos under the OS tmpdir and never deleted them. When `core.fsmonitor=true` is set globally, every git call in a fixture also started a `git fsmonitor--daemon` that never exited. So every run left more temp repos and more daemons behind. - The test's `git()` helper now passes `-c core.fsmonitor=false`, next to the existing `core.hooksPath` override. - Fixture repos are now created through a new `createFixtureRepo()` helper, which records each path. An `after()` hook deletes them all with `rmSync(..., { recursive: true, force: true })`. The other scripts that create temp git repos (`scripts/ci-selection.test.mjs`, `scripts/flake-check.test.mjs`, `scripts/test-mobile-release-contract.sh`, `scripts/test-sprig-image.sh`) already clean up their temp directories and left no daemons running, so they are unchanged. ## Testing - `node --test scripts/check-file-sizes-core.test.mjs`: no `file-size-*` directories are left in the tmpdir afterwards, and no new `fsmonitor--daemon` processes are running. - The pre-push `file-size-check` lane passes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: Matt Toohey Co-authored-by: Claude Opus 5.5 --- scripts/check-file-sizes-core.test.mjs | 36 +++++++++++++++++++------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/scripts/check-file-sizes-core.test.mjs b/scripts/check-file-sizes-core.test.mjs index 986d1a3810..905a2cea2c 100644 --- a/scripts/check-file-sizes-core.test.mjs +++ b/scripts/check-file-sizes-core.test.mjs @@ -5,12 +5,13 @@ import { mkdirSync, mkdtempSync, realpathSync, + rmSync, symlinkSync, writeFileSync, } from "node:fs"; import { tmpdir } from "node:os"; import path from "node:path"; -import test from "node:test"; +import test, { after } from "node:test"; import { policy as desktopPolicy } from "../desktop/scripts/check-file-sizes.mjs"; import { policy as mobilePolicy } from "../mobile/scripts/check-file-sizes.mjs"; import { policy as webPolicy } from "../web/scripts/check-file-sizes.mjs"; @@ -24,18 +25,35 @@ import { const repoRoot = path.resolve(import.meta.dirname, ".."); +const fixtureRepos = []; +after(() => { + for (const repo of fixtureRepos) + rmSync(repo, { recursive: true, force: true }); +}); + +function createFixtureRepo(prefix) { + const repo = realpathSync(mkdtempSync(path.join(tmpdir(), prefix))); + fixtureRepos.push(repo); + return repo; +} + function git(repo, ...args) { // These fixture repositories inherit both hook configuration and Git's // repository-local environment when this test runs from pre-push. Isolate // them completely so fixture commits cannot recurse into the real checkout. + // A global core.fsmonitor would also leave a daemon running per fixture. const env = Object.fromEntries( Object.entries(process.env).filter(([key]) => !key.startsWith("GIT_")), ); - return execFileSync("git", ["-c", "core.hooksPath=/dev/null", ...args], { - cwd: repo, - encoding: "utf8", - env, - }).trim(); + return execFileSync( + "git", + ["-c", "core.hooksPath=/dev/null", "-c", "core.fsmonitor=false", ...args], + { + cwd: repo, + encoding: "utf8", + env, + }, + ).trim(); } function createEntrypointFixture({ @@ -44,9 +62,7 @@ function createEntrypointFixture({ lineDelta = 1, symlinkEntrypoint = false, }) { - const repo = realpathSync( - mkdtempSync(path.join(tmpdir(), `file-size-${surface}-`)), - ); + const repo = createFixtureRepo(`file-size-${surface}-`); const scriptsDir = path.join(repo, "scripts"); const surfaceScriptsDir = path.join(repo, surface, "scripts"); mkdirSync(scriptsDir, { recursive: true }); @@ -95,7 +111,7 @@ function createEntrypointFixture({ } test("local base resolution uses the branch merge-base and fails without origin/main", () => { - const repo = mkdtempSync(path.join(tmpdir(), "file-size-base-")); + const repo = createFixtureRepo("file-size-base-"); git(repo, "init", "-b", "main"); git(repo, "config", "user.name", "Test"); git(repo, "config", "user.email", "test@example.com");