fix(install): skip lockfile-level diff checks in recursive workspace comparisons#29052
fix(install): skip lockfile-level diff checks in recursive workspace comparisons#29052hassellof wants to merge 4 commits intooven-sh:mainfrom
Conversation
…comparisons `Package.Diff.generate` is called recursively to compare individual workspace packages, but it receives the *global* `from_lockfile` and `to_lockfile` — not per-workspace lockfiles. The temp lockfile used for the fresh package.json parse has no trusted_dependencies (and potentially different overrides/patched_dependencies), so the lockfile-level comparisons produced spurious diffs for every workspace package. This caused `--frozen-lockfile` and `--production` (which implies frozen lockfile) to always fail in workspace monorepos, even when the lockfile was just generated. Guard the overrides, trusted_dependencies, and patched_dependencies comparisons with `is_root` checks, matching the existing guard on catalogs. These lockfile-level concepts are already correctly compared in the root-level call. Fixes oven-sh#19088 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…onorepos Verifies that `--frozen-lockfile` and `--production` succeed immediately after `bun install` in a workspace monorepo where packages depend on each other via `workspace:*`. Regression test for oven-sh#19088. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughLockfile diff logic now skips several global-scope comparisons when invoked non-root to avoid spurious diffs during recursive comparisons. A regression test for workspace monorepo frozen-lockfile/production installs was added. Changes
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@test/cli/install/bun-workspaces.test.ts`:
- Around line 1990-2020: The tests call spawn(...) and immediately assert
expect(await exited).toBe(0) which hides stderr output on failures; update each
spawn call to also destructure and capture stderr (e.g., { exited, stderr } =
spawn(...)), await the stderr content before asserting the exit code, and add an
assertion or include stderr in the failure message (for the spawn invocations
around bunExe(), packageDir and env) so stderr is visible when the process
fails.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 3446d2d5-e751-4740-a873-72f4c8109337
📒 Files selected for processing (2)
src/install/lockfile/Package.zigtest/cli/install/bun-workspaces.test.ts
Follows the coding guideline to check stderr before exit code for more actionable failure messages when spawned processes fail. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@test/cli/install/bun-workspaces.test.ts`:
- Around line 1953-1957: The test case titled "frozen lockfile succeeds in
workspace monorepo with workspace: deps" is a regression test for issue `#19088`
and must be relocated to the canonical regression location; move the test
(including its surrounding describe/context and any fixtures it depends on) out
of test/cli/install/bun-workspaces.test.ts and into a new file named for the
issue (issue 19088), ensure the test file exports/defines the same test name and
preserves any helper imports or setup used by the original (update relative
imports if needed), and remove the original duplicate from
bun-workspaces.test.ts so the test now lives only in
test/regression/issue/19088.test.ts.
- Around line 1958-1985: The test fixture only covers workspace:* dependencies
and misses lockfile-level fields that triggered the regression; update the JSON
written by the write call for the workspace package (e.g., the call that writes
join(packageDir, "packages", "shared", "package.json")) to include a
lockfile-level field such as "trustedDependencies" with at least one entry
(e.g., map a package name to a version or boolean) so the test exercises
recursive diffing of lockfile-level fields like
trustedDependencies/overrides/patchedDependencies and locks the fix; ensure the
added field is valid JSON and placed alongside existing fields like
name/version/dependencies.
- Around line 1998-2000: The test currently asserts
expect(stderr).not.toContain("error") which is too broad and can cause false
failures; update the assertion in the test that reads proc.stderr.text()
(variable stderr) to either remove the broad check entirely and rely on
expect(await proc.exited).toBe(0), or change it to assert absence of the
specific regression message you care about (e.g., the exact error substring
previously observed) so only that exact string is checked rather than any
occurrence of "error".
- Around line 1990-2026: Wrap each Bun.spawn invocation with the resource-safe
pattern using "await using" so spawned processes are disposed correctly: replace
the three raw calls that assign to "proc" (the ones invoking spawn({ cmd:
[bunExe(), 'install' ...] }), spawn({ cmd: [bunExe(), 'install',
'--frozen-lockfile' ...] }), and spawn({ cmd: [bunExe(), 'install',
'--production' ...] })) with "await using proc = spawn(...)" (or equivalent) so
the proc.stderr.text() and proc.exited checks run inside the scope and the
process is cleaned up automatically; ensure you keep references to
"proc.stderr.text()" and "proc.exited" calls inside each using block.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 07099780-0667-4ea3-9f6c-77923779e00c
📒 Files selected for processing (1)
test/cli/install/bun-workspaces.test.ts
| // Regression test for https://github.com/oven-sh/bun/issues/19088 | ||
| // --frozen-lockfile was failing in workspace monorepos because lockfile-level | ||
| // properties (trusted dependencies, overrides, patched dependencies) were | ||
| // spuriously compared during recursive per-workspace diff calls. | ||
| test("frozen lockfile succeeds in workspace monorepo with workspace: deps", async () => { |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Place this issue-numbered regression test under test/regression/issue/19088.test.ts.
Since this test is explicitly tied to issue #19088, it should live in the regression issue folder with the real issue number.
As per coding guidelines: “Tests for specific numbered GitHub Issues should be placed in test/regression/issue/${issueNumber}.test.ts with a REAL issue number.”
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@test/cli/install/bun-workspaces.test.ts` around lines 1953 - 1957, The test
case titled "frozen lockfile succeeds in workspace monorepo with workspace:
deps" is a regression test for issue `#19088` and must be relocated to the
canonical regression location; move the test (including its surrounding
describe/context and any fixtures it depends on) out of
test/cli/install/bun-workspaces.test.ts and into a new file named for the issue
(issue 19088), ensure the test file exports/defines the same test name and
preserves any helper imports or setup used by the original (update relative
imports if needed), and remove the original duplicate from
bun-workspaces.test.ts so the test now lives only in
test/regression/issue/19088.test.ts.
- Add trustedDependencies to workspace fixture to exercise the actual root-cause path (lockfile-level field contamination across recursive workspace diff calls) - Use `await using` for spawn resource cleanup - Drop broad "error" stderr check; use specific "lockfile had changes" assertion on all three spawn calls - Use block-scoped const instead of var reassignment Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
What does this PR do?
Fixes
bun install --frozen-lockfile(and--production, which implies frozen lockfile) always failing in workspace monorepos, even when the lockfile was just generated bybun installon the same machine.Root cause:
Package.Diff.generateis called recursively — once at the root level to compare the root package, and then for each workspace package. The recursive calls receive the globalfrom_lockfileandto_lockfile, not per-workspace lockfiles. When any workspacepackage.jsonhastrustedDependencies, the temp lockfile accumulates state across workspace comparisons, producing spurious diffs that mark every subsequent workspace as "updated". This triggers unnecessary dependency re-resolution, which in large monorepos produces a different hoisted dependency tree, causing the frozen-lockfileeqlcheck to fail. The same class of bug affectsoverridesandpatched_dependencies.Fix: Guard the
overrides,trusted_dependencies, andpatched_dependenciescomparisons withis_rootchecks, matching the existing guard oncatalogs(which was already correctly wrapped inif (is_root)). These lockfile-level concepts are already correctly compared in the root-level call — the recursive workspace calls were redundant and harmful.Fixes #19088
Reproduction: hassellof/bun-frozen-lockfile-repro (minimal). Also consistently reproduced against a private Phystack monorepo with 4 apps, 6 shared workspace packages, and ~4600 total dependencies.
How did you verify your code works?
Tested against the real-world workspace monorepo described above:
All 63 existing workspace tests pass (0 failures), including the new regression test.
Also verified that the binary lockfile format (
bun.lockb) was unaffected — it uses a different comparison path (hasMetaHashChanged) that doesn't have this issue.Test plan
--frozen-lockfilepasses after clean install--production(which implies--frozen-lockfile) passestest/cli/install/bun-workspaces.test.ts)🤖 Generated with Claude Code