From bc0def52af3258b098dc577815039a8bde8e2b81 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Thu, 14 May 2026 13:03:59 +0800 Subject: [PATCH] fix(ci): read sparse package manifests from index --- scripts/check-dependency-pins.mjs | 17 +++++++++++++++-- test/scripts/check-dependency-pins.test.ts | 17 ++++++++++++++++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/scripts/check-dependency-pins.mjs b/scripts/check-dependency-pins.mjs index 842426d3432..7b99909975e 100644 --- a/scripts/check-dependency-pins.mjs +++ b/scripts/check-dependency-pins.mjs @@ -27,6 +27,19 @@ function readJson(filePath) { return JSON.parse(fs.readFileSync(filePath, "utf8")); } +function readTrackedJson(cwd, relativePath) { + const filePath = path.join(cwd, relativePath); + if (fs.existsSync(filePath)) { + return readJson(filePath); + } + return JSON.parse( + execFileSync("git", ["show", `:${relativePath}`], { + cwd, + encoding: "utf8", + }), + ); +} + function isAllowedPinnedSpec(spec) { if (typeof spec !== "string") { return false; @@ -46,7 +59,7 @@ function isAllowedPinnedSpec(spec) { function collectPackageJsonViolations(cwd) { const violations = []; for (const relativePath of listTrackedPackageJsonFiles(cwd)) { - const packageJson = readJson(path.join(cwd, relativePath)); + const packageJson = readTrackedJson(cwd, relativePath); for (const section of PACKAGE_DEPENDENCY_SECTIONS) { for (const [name, spec] of Object.entries(packageJson[section] ?? {})) { if (!isAllowedPinnedSpec(spec)) { @@ -96,7 +109,7 @@ export function collectDependencyPinAudit(cwd = process.cwd()) { const packageJsonFiles = listTrackedPackageJsonFiles(cwd); let packageSpecCount = 0; for (const relativePath of packageJsonFiles) { - const packageJson = readJson(path.join(cwd, relativePath)); + const packageJson = readTrackedJson(cwd, relativePath); for (const section of PACKAGE_DEPENDENCY_SECTIONS) { packageSpecCount += Object.keys(packageJson[section] ?? {}).length; } diff --git a/test/scripts/check-dependency-pins.test.ts b/test/scripts/check-dependency-pins.test.ts index 245ef7a4f70..d1c3605cb56 100644 --- a/test/scripts/check-dependency-pins.test.ts +++ b/test/scripts/check-dependency-pins.test.ts @@ -1,5 +1,5 @@ import { execFileSync } from "node:child_process"; -import { mkdirSync, writeFileSync } from "node:fs"; +import { mkdirSync, rmSync, writeFileSync } from "node:fs"; import path from "node:path"; import { afterEach, describe, expect, it } from "vitest"; import { collectDependencyPinViolations } from "../../scripts/check-dependency-pins.mjs"; @@ -143,6 +143,21 @@ packageExtensions: ]); }); + it("reads tracked package manifests from the index when sparse checkout omits them", () => { + const dir = makeRepo(); + mkdirSync(path.join(dir, "qa", "convex-credential-broker"), { recursive: true }); + writeJson(path.join(dir, "package.json"), {}); + writeJson(path.join(dir, "qa", "convex-credential-broker", "package.json"), { + dependencies: { + exact: "1.2.3", + }, + }); + git(dir, ["add", "package.json", "qa/convex-credential-broker/package.json"]); + rmSync(path.join(dir, "qa"), { recursive: true, force: true }); + + expect(collectDependencyPinViolations(dir)).toEqual([]); + }); + it("rejects floating workspace overrides and package extension dependencies", () => { const dir = makeRepo(); writeJson(path.join(dir, "package.json"), {});