From c09d09f2cec4eec2077c6625fe0d9cb32cda72a8 Mon Sep 17 00:00:00 2001 From: LukeGus Date: Thu, 5 Nov 2026 12:52:04 -0600 Subject: [PATCH] fix: test --- scripts/bundled-plugins.test.ts | 23 ++++++++++++++++++++++- scripts/lib/bundled-plugins.cjs | 19 ++++++++++++------- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/scripts/bundled-plugins.test.ts b/scripts/bundled-plugins.test.ts index 3a9aa02a1..414697e4f 100644 --- a/scripts/bundled-plugins.test.ts +++ b/scripts/bundled-plugins.test.ts @@ -1,4 +1,4 @@ -import { afterEach, describe, expect, it } from "vitest"; +import { afterEach, describe, expect, it, vi } from "vitest"; import crypto from "node:crypto"; import fs from "node:fs"; import os from "node:os"; @@ -471,6 +471,27 @@ describe("rebuilding local plugins", () => { expect(isLocalBuildStale(root)).toBe(false); }); + it("survives a build replacing dist during the scan", () => { + const root = repo(tempDir(), "Plugin-A", "a"); + const gone = path.join(root, "dist", "migrations", "postgres"); + fs.mkdirSync(gone, { recursive: true }); + fs.writeFileSync(path.join(root, "manifest.json"), "{}"); + const realStat = fs.statSync; + const spy = vi.spyOn(fs, "statSync").mockImplementation((( + target: string, + ) => { + if (target === gone) { + throw Object.assign(new Error("gone"), { code: "ENOENT" }); + } + return realStat(target); + }) as typeof fs.statSync); + try { + expect(() => isLocalBuildStale(root)).not.toThrow(); + } finally { + spy.mockRestore(); + } + }); + it("builds with this checkout's SDK CLI, not the plugin's own", () => { const [command, args] = localSdkBuildCommand(); expect(command).toBe(process.execPath); diff --git a/scripts/lib/bundled-plugins.cjs b/scripts/lib/bundled-plugins.cjs index 16eaf7163..ec4bd1e14 100644 --- a/scripts/lib/bundled-plugins.cjs +++ b/scripts/lib/bundled-plugins.cjs @@ -370,15 +370,20 @@ const BUILD_INPUTS = [ "package.json", ]; +// A build can replace dist while this walks it, so a path can vanish mid scan. function newestMtime(target) { - if (!fs.existsSync(target)) return 0; - const stat = fs.statSync(target); - if (!stat.isDirectory()) return stat.mtimeMs; - let newest = 0; - for (const name of fs.readdirSync(target)) { - newest = Math.max(newest, newestMtime(path.join(target, name))); + try { + const stat = fs.statSync(target); + if (!stat.isDirectory()) return stat.mtimeMs; + let newest = 0; + for (const name of fs.readdirSync(target)) { + newest = Math.max(newest, newestMtime(path.join(target, name))); + } + return newest; + } catch (error) { + if (error.code === "ENOENT") return 0; + throw error; } - return newest; } /** True when a plugin repo has never been built or its sources changed since. */