Skip to content

Conversation

ShlomoCode
Copy link
Contributor

What does this PR do?

Closes #23507

How did you verify your code works?

I tried with the example monorepo provided in the issue (https://github.com/therealsamyak/bun-monorepo)

Copy link
Contributor

coderabbitai bot commented Oct 12, 2025

Walkthrough

Workspace discovery, filtering, and package.json path construction were extracted to a new WorkspaceHelpers module. CLI commands (outdated, update_interactive) now alias and delegate to those helpers. The update workflow gained workspace-aware logic to batch-update workspace package.json files and coordinate installs.

Changes

Cohort / File(s) Summary
CLI: delegate to WorkspaceHelpers
src/cli/outdated_command.zig, src/cli/update_interactive_command.zig
Removed in-file workspace functions and added const WorkspaceHelpers = @import("../install/PackageManager/WorkspaceHelpers.zig"); plus aliases: getAllWorkspaces, findMatchingWorkspaces, and (in update interactive) buildWorkspacePackageJsonPath. Call sites updated to use the helpers and .path_z where applicable.
New helpers module
src/install/PackageManager/WorkspaceHelpers.zig
Added pub fn getAllWorkspaces(...), pub fn findMatchingWorkspaces(...), and pub fn buildWorkspacePackageJsonPath(...) for lockfile-based workspace collection, filter normalization/matching, ordering, and package.json path construction.
Update workflow changes
src/install/PackageManager/updatePackageJSONAndInstall.zig
Added updatePackageJSONForWorkspaces(...). updatePackageJSONAndInstallWithManager now uses WorkspaceHelpers (getAllWorkspaces, findMatchingWorkspaces, buildWorkspacePackageJsonPath) to resolve workspaces, perform per-workspace package.json updates, and coordinate installs for recursive/filtered updates.

Suggested reviewers

  • lydiahallie

Pre-merge checks

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The pull request description includes the required section headings but does not summarize the actual code changes under “What does this PR do?”, only referencing the issue closure without describing the implementation of the recursive update behavior. Please expand the “What does this PR do?” section with a concise summary of the changes, for example noting the addition of workspace helper functions and the new recursive update logic in the updatePackageJSONAndInstall path.
✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The title accurately and concisely describes the primary feature implemented—support for the --recursive flag in the bun update command and matches the changes introduced in the pull request.
Linked Issues Check ✅ Passed The pull request implements the recursive update functionality by introducing workspace discovery helpers and updating the non-interactive update path to apply updates across all workspace packages as specified in issue #23507.
Out of Scope Changes Check ✅ Passed All modifications relate to implementing and refactoring workspace discovery and recursive update logic across CLI commands and the package manager module, with no unrelated or out-of-scope changes detected.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between e38d4e6 and 6e4790c.

📒 Files selected for processing (4)
  • src/cli/outdated_command.zig (1 hunks)
  • src/cli/update_interactive_command.zig (5 hunks)
  • src/install/PackageManager/WorkspaceHelpers.zig (1 hunks)
  • src/install/PackageManager/updatePackageJSONAndInstall.zig (3 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.zig

📄 CodeRabbit inference engine (.cursor/rules/javascriptcore-class.mdc)

**/*.zig: Declare the extern C symbol in Zig and export a Zig-friendly alias for use
Wrap the Bun____toJS extern in a Zig method that takes a JSGlobalObject and returns JSC.JSValue

Files:

  • src/install/PackageManager/WorkspaceHelpers.zig
  • src/install/PackageManager/updatePackageJSONAndInstall.zig
  • src/cli/update_interactive_command.zig
  • src/cli/outdated_command.zig
src/**/*.zig

📄 CodeRabbit inference engine (CLAUDE.md)

In Zig code, manage memory carefully and use defer for cleanup of allocations/resources

src/**/*.zig: Use the # prefix to declare private fields in Zig structs (e.g., struct { #foo: u32 })
Prefer decl literals when initializing values in Zig (e.g., const decl: Decl = .{ .binding = 0, .value = 0 })
Place @import directives at the bottom of Zig files
Use @import("bun") instead of @import("root").bun

When adding debug logs in Zig, create a scoped logger and log via Bun APIs: const log = bun.Output.scoped(.${SCOPE}, .hidden); then log("...", .{})

Files:

  • src/install/PackageManager/WorkspaceHelpers.zig
  • src/install/PackageManager/updatePackageJSONAndInstall.zig
  • src/cli/update_interactive_command.zig
  • src/cli/outdated_command.zig
🧠 Learnings (1)
📚 Learning: 2025-10-07T03:19:53.031Z
Learnt from: CR
PR: oven-sh/bun#0
File: src/CLAUDE.md:0-0
Timestamp: 2025-10-07T03:19:53.031Z
Learning: Applies to src/**/*.zig : Place import directives at the bottom of Zig files

Applied to files:

  • src/install/PackageManager/WorkspaceHelpers.zig

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f00e181 and fd32a2c.

📒 Files selected for processing (4)
  • src/cli/outdated_command.zig (1 hunks)
  • src/cli/update_interactive_command.zig (1 hunks)
  • src/install/PackageManager/WorkspaceHelpers.zig (1 hunks)
  • src/install/PackageManager/updatePackageJSONAndInstall.zig (3 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.zig

📄 CodeRabbit inference engine (.cursor/rules/javascriptcore-class.mdc)

**/*.zig: Declare the extern C symbol in Zig and export a Zig-friendly alias for use
Wrap the Bun____toJS extern in a Zig method that takes a JSGlobalObject and returns JSC.JSValue

Files:

  • src/cli/update_interactive_command.zig
  • src/install/PackageManager/WorkspaceHelpers.zig
  • src/install/PackageManager/updatePackageJSONAndInstall.zig
  • src/cli/outdated_command.zig
src/**/*.zig

📄 CodeRabbit inference engine (CLAUDE.md)

In Zig code, manage memory carefully and use defer for cleanup of allocations/resources

src/**/*.zig: Use the # prefix to declare private fields in Zig structs (e.g., struct { #foo: u32 })
Prefer decl literals when initializing values in Zig (e.g., const decl: Decl = .{ .binding = 0, .value = 0 })
Place @import directives at the bottom of Zig files
Use @import("bun") instead of @import("root").bun

When adding debug logs in Zig, create a scoped logger and log via Bun APIs: const log = bun.Output.scoped(.${SCOPE}, .hidden); then log("...", .{})

Files:

  • src/cli/update_interactive_command.zig
  • src/install/PackageManager/WorkspaceHelpers.zig
  • src/install/PackageManager/updatePackageJSONAndInstall.zig
  • src/cli/outdated_command.zig
🔇 Additional comments (4)
src/cli/outdated_command.zig (1)

616-619: Aliasing helpers here is good; check filter semantics parity

Delegating to WorkspaceHelpers reduces duplication. Please verify that findMatchingWorkspaces preserves prior matching semantics (any-of vs all-of across multiple filters), and that glob/path matching behaves on Windows as before.

src/cli/update_interactive_command.zig (1)

534-536: LGTM: centralizing workspace helpers

Aliases keep interactive flow consistent with the new shared logic.

src/install/PackageManager/WorkspaceHelpers.zig (2)

14-35: getAllWorkspaces: OK

Collecting root + workspace PackageIDs and returning an owned slice looks correct.


37-122: Remove outdated ownership suggestion; confirm filter semantics

  • Ownership: .toOwnedSlice(allocator) is already used—no change needed.
  • Semantics: filters are currently ANDed; confirm if they should be ORed instead.

@ShlomoCode ShlomoCode force-pushed the feat/update-recursive branch from fd32a2c to 195e23c Compare October 12, 2025 21:42
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
src/install/PackageManager/updatePackageJSONAndInstall.zig (1)

272-283: Single matched workspace still skipped

The regression called out earlier remains: when filters match exactly one workspace (and --recursive is not set) we still fall through to the root-only path, so that workspace never gets updated. Please execute the previously suggested fix to always delegate to the workspace-aware path whenever any match exists.

-        if (workspace_pkg_ids.len > 1 or (workspace_pkg_ids.len == 1 and manager.options.do.recursive)) {
-            defer bun.default_allocator.free(workspace_pkg_ids);
-            return try updatePackageJSONForWorkspaces(
-                manager,
-                ctx,
-                original_cwd,
-                workspace_pkg_ids,
-            );
-        } else if (workspace_pkg_ids.len > 0) {
-            bun.default_allocator.free(workspace_pkg_ids);
-        }
+        if (workspace_pkg_ids.len > 0) {
+            defer bun.default_allocator.free(workspace_pkg_ids);
+            return try updatePackageJSONForWorkspaces(
+                manager,
+                ctx,
+                original_cwd,
+                workspace_pkg_ids,
+            );
+        }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between fd32a2c and 195e23c.

📒 Files selected for processing (4)
  • src/cli/outdated_command.zig (1 hunks)
  • src/cli/update_interactive_command.zig (1 hunks)
  • src/install/PackageManager/WorkspaceHelpers.zig (1 hunks)
  • src/install/PackageManager/updatePackageJSONAndInstall.zig (3 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.zig

📄 CodeRabbit inference engine (.cursor/rules/javascriptcore-class.mdc)

**/*.zig: Declare the extern C symbol in Zig and export a Zig-friendly alias for use
Wrap the Bun____toJS extern in a Zig method that takes a JSGlobalObject and returns JSC.JSValue

Files:

  • src/install/PackageManager/updatePackageJSONAndInstall.zig
  • src/cli/outdated_command.zig
  • src/cli/update_interactive_command.zig
  • src/install/PackageManager/WorkspaceHelpers.zig
src/**/*.zig

📄 CodeRabbit inference engine (CLAUDE.md)

In Zig code, manage memory carefully and use defer for cleanup of allocations/resources

src/**/*.zig: Use the # prefix to declare private fields in Zig structs (e.g., struct { #foo: u32 })
Prefer decl literals when initializing values in Zig (e.g., const decl: Decl = .{ .binding = 0, .value = 0 })
Place @import directives at the bottom of Zig files
Use @import("bun") instead of @import("root").bun

When adding debug logs in Zig, create a scoped logger and log via Bun APIs: const log = bun.Output.scoped(.${SCOPE}, .hidden); then log("...", .{})

Files:

  • src/install/PackageManager/updatePackageJSONAndInstall.zig
  • src/cli/outdated_command.zig
  • src/cli/update_interactive_command.zig
  • src/install/PackageManager/WorkspaceHelpers.zig
🧠 Learnings (1)
📚 Learning: 2025-10-07T03:19:53.031Z
Learnt from: CR
PR: oven-sh/bun#0
File: src/CLAUDE.md:0-0
Timestamp: 2025-10-07T03:19:53.031Z
Learning: Applies to src/**/*.zig : Place import directives at the bottom of Zig files

Applied to files:

  • src/install/PackageManager/WorkspaceHelpers.zig

@ShlomoCode ShlomoCode force-pushed the feat/update-recursive branch from 195e23c to 05aac39 Compare October 12, 2025 22:30
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (3)
src/install/PackageManager/updatePackageJSONAndInstall.zig (1)

238-249: Bug: single matched workspace with filters is not updated.

If exactly one workspace matches filters (and --recursive is not set), the condition on line 238 evaluates to false:

if (workspace_pkg_ids.len > 1 or (workspace_pkg_ids.len == 1 and manager.options.do.recursive))

This causes the code to free the IDs and fall through to the non-workspace path, skipping the intended workspace update.

Apply this diff to fix the issue:

-        if (workspace_pkg_ids.len > 1 or (workspace_pkg_ids.len == 1 and manager.options.do.recursive)) {
-            defer bun.default_allocator.free(workspace_pkg_ids);
-            return try updatePackageJSONForWorkspaces(
-                manager,
-                ctx,
-                original_cwd,
-                workspace_pkg_ids,
-            );
-        } else if (workspace_pkg_ids.len > 0) {
-            bun.default_allocator.free(workspace_pkg_ids);
-        }
+        if (workspace_pkg_ids.len > 0) {
+            defer bun.default_allocator.free(workspace_pkg_ids);
+            return try updatePackageJSONForWorkspaces(
+                manager,
+                ctx,
+                original_cwd,
+                workspace_pkg_ids,
+            );
+        }
src/install/PackageManager/WorkspaceHelpers.zig (2)

7-10: Critical: Return allocator-owned empty slices to prevent invalid free.

getAllWorkspaces returns a static zero-length slice when no packages exist. Callers (e.g., in updatePackageJSONAndInstall.zig at line 233) immediately free the result with bun.default_allocator.free(workspace_pkg_ids), which will trigger an invalid-free panic because the pointer was never allocated by the allocator.

Apply this diff to fix the issue:

     if (lockfile.packages.len == 0) {
-        const empty: []const PackageID = &[_]PackageID{};
-        return empty;
+        return allocator.alloc(PackageID, 0);
     }

63-109: Critical: Transfer ownership properly before returning.

findMatchingWorkspaces returns workspace_pkg_ids.items at line 108, leaving the backing buffer owned by the local ArrayListUnmanaged. When callers free the slice using its post-filter length (which may differ from the allocated capacity), this yields undefined behavior and potential leaks when no matches remain.

Apply this diff to transfer ownership properly:

     while (i < workspace_pkg_ids.items.len) {
         ...
     }
 
-    return workspace_pkg_ids.items;
+    const result = try workspace_pkg_ids.toOwnedSlice(allocator);
+    if (result.len == 0) {
+        return allocator.alloc(PackageID, 0);
+    }
+    return result;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 195e23c and 05aac39.

📒 Files selected for processing (4)
  • src/cli/outdated_command.zig (1 hunks)
  • src/cli/update_interactive_command.zig (5 hunks)
  • src/install/PackageManager/WorkspaceHelpers.zig (1 hunks)
  • src/install/PackageManager/updatePackageJSONAndInstall.zig (3 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.zig

📄 CodeRabbit inference engine (.cursor/rules/javascriptcore-class.mdc)

**/*.zig: Declare the extern C symbol in Zig and export a Zig-friendly alias for use
Wrap the Bun____toJS extern in a Zig method that takes a JSGlobalObject and returns JSC.JSValue

Files:

  • src/install/PackageManager/updatePackageJSONAndInstall.zig
  • src/cli/update_interactive_command.zig
  • src/cli/outdated_command.zig
  • src/install/PackageManager/WorkspaceHelpers.zig
src/**/*.zig

📄 CodeRabbit inference engine (CLAUDE.md)

In Zig code, manage memory carefully and use defer for cleanup of allocations/resources

src/**/*.zig: Use the # prefix to declare private fields in Zig structs (e.g., struct { #foo: u32 })
Prefer decl literals when initializing values in Zig (e.g., const decl: Decl = .{ .binding = 0, .value = 0 })
Place @import directives at the bottom of Zig files
Use @import("bun") instead of @import("root").bun

When adding debug logs in Zig, create a scoped logger and log via Bun APIs: const log = bun.Output.scoped(.${SCOPE}, .hidden); then log("...", .{})

Files:

  • src/install/PackageManager/updatePackageJSONAndInstall.zig
  • src/cli/update_interactive_command.zig
  • src/cli/outdated_command.zig
  • src/install/PackageManager/WorkspaceHelpers.zig
🧠 Learnings (1)
📚 Learning: 2025-10-07T03:19:53.031Z
Learnt from: CR
PR: oven-sh/bun#0
File: src/CLAUDE.md:0-0
Timestamp: 2025-10-07T03:19:53.031Z
Learning: Applies to src/**/*.zig : Place import directives at the bottom of Zig files

Applied to files:

  • src/install/PackageManager/WorkspaceHelpers.zig
🔇 Additional comments (7)
src/cli/outdated_command.zig (1)

616-619: LGTM! Clean delegation to WorkspaceHelpers.

The aliases properly delegate workspace discovery to the centralized WorkspaceHelpers module, and imports are correctly placed at the bottom per Zig coding guidelines.

src/cli/update_interactive_command.zig (2)

158-288: LGTM! Consistent use of centralized path helper.

The migration to buildWorkspacePackageJsonPath is implemented consistently across all call sites, properly accessing the .path and .path_z fields from the returned struct.


1904-1908: LGTM! Clean WorkspaceHelpers integration.

The imports and aliases follow Zig coding guidelines with imports at the bottom, and the aliasing pattern is consistent with other command files.

src/install/PackageManager/updatePackageJSONAndInstall.zig (2)

1-161: Verify correctness of two-pass workspace update logic.

The function processes workspace package.jsons twice with different exact_versions settings:

  1. First pass (lines 13-90): exact_versions = true, before_install = true
  2. Install step (line 104)
  3. Second pass (lines 106-160): exact_versions = manager.options.enable.exact_versions

Please confirm this two-pass approach is intentional and that the second pass is necessary after the install completes. If the second pass is only meant to revert the exact_versions behavior when the flag is off, consider documenting this workflow with inline comments explaining the rationale.


983-989: LGTM! Proper WorkspaceHelpers integration.

The imports and aliases are correctly structured, enabling workspace-aware update logic.

src/install/PackageManager/WorkspaceHelpers.zig (2)

111-138: LGTM! Path helper function is correct.

The buildWorkspacePackageJsonPath function properly constructs absolute paths and returns both regular and zero-terminated slices, facilitating clean integration with filesystem APIs.


140-151: LGTM! Imports correctly placed at the bottom.

The imports follow the Zig coding guideline of placing @import directives at the bottom of the file.

As per coding guidelines

@ShlomoCode ShlomoCode force-pushed the feat/update-recursive branch 2 times, most recently from 43dd937 to e38d4e6 Compare October 12, 2025 22:50
@ShlomoCode ShlomoCode force-pushed the feat/update-recursive branch from e38d4e6 to 6e4790c Compare October 12, 2025 22:59
@ShlomoCode ShlomoCode changed the title feat: implement update --recursive feat: implement bun update --recursive Oct 12, 2025
@markovejnovic markovejnovic requested a review from RiskyMH October 13, 2025 22:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Recursive flag not working for bun update

1 participant