feat: bit update should update dependencies in env.jsonc#10128
feat: bit update should update dependencies in env.jsonc#10128zkochan wants to merge 16 commits intoteambit:masterfrom
Conversation
fc8d0a2 to
c9dd8ce
Compare
There was a problem hiding this comment.
Pull request overview
This pull request adds support for updating dependencies in env.jsonc files when running the bit update command. Previously, bit update only updated dependencies in workspace.jsonc and component configurations, but did not handle dependencies defined in environment component's env.jsonc files.
Key changes:
- Introduces a new
jsonc-utilscomponent for parsing and modifying JSONC files while preserving formatting - Extends dependency resolution to include dependencies from env.jsonc files
- Implements logic to update env.jsonc files with new dependency versions, including special handling for peerDependencies' supportedRange
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| scopes/toolbox/json/jsonc-utils/jsonc-utils.ts | New utility functions for parsing, stringifying, and updating JSONC files while preserving formatting (indentation, newlines, comments) |
| scopes/toolbox/json/jsonc-utils/index.ts | Exports for the new jsonc-utils component |
| scopes/toolbox/json/jsonc-utils/jsonc-utils.docs.mdx | Comprehensive documentation for the jsonc-utils utility with examples and use cases |
| scopes/dependencies/dependency-resolver/get-all-policy-pkgs.ts | Adds 'env-jsonc' as a new CurrentPkgSource type to track where dependencies are defined |
| scopes/dependencies/dependency-resolver/dependency-resolver.main.runtime.ts | Implements getEnvJsoncPolicyPkgs() to extract dependencies from env.jsonc files and integrates them into the dependency resolution flow |
| scopes/workspace/install/install.main.runtime.ts | Implements updateEnvJsoncPolicies() to write updated dependency versions back to env.jsonc files and integrates it into the update workflow |
| scopes/workspace/install/pick-outdated-pkgs.ts | Updates unique name generation and adds context rendering for env-jsonc dependencies in the interactive selection UI |
| scopes/workspace/install/pick-outdated-pkgs.spec.ts | Updates test expectations to match new unique naming scheme with index suffixes |
| e2e/harmony/dependencies/env-jsonc-policies.e2e.ts | Adds end-to-end tests verifying that bit update correctly updates env.jsonc files and handles supportedRange for peerDependencies |
| .bitmap | Registers the new json/jsonc-utils component in the workspace |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
scopes/dependencies/dependency-resolver/dependency-resolver.main.runtime.ts
Outdated
Show resolved
Hide resolved
scopes/dependencies/dependency-resolver/dependency-resolver.main.runtime.ts
Outdated
Show resolved
Hide resolved
scopes/dependencies/dependency-resolver/dependency-resolver.main.runtime.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated 6 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
scopes/dependencies/dependency-resolver/dependency-resolver.main.runtime.ts
Outdated
Show resolved
Hide resolved
scopes/dependencies/dependency-resolver/dependency-resolver.main.runtime.ts
Outdated
Show resolved
Hide resolved
scopes/dependencies/dependency-resolver/dependency-resolver.main.runtime.ts
Outdated
Show resolved
Hide resolved
scopes/dependencies/dependency-resolver/dependency-resolver.main.runtime.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
scopes/dependencies/dependency-resolver/dependency-resolver.main.runtime.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 9 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
scopes/dependencies/dependency-resolver/dependency-resolver.main.runtime.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
scopes/dependencies/dependency-resolver/dependency-resolver.main.runtime.ts
Show resolved
Hide resolved
scopes/dependencies/dependency-resolver/dependency-resolver.main.runtime.ts
Show resolved
Hide resolved
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 14 out of 14 changed files in this pull request and generated 6 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| getEnvJsoncPolicyPkgs(components: Component[]): CurrentPkg[] { | ||
| const policies = [ | ||
| { field: 'peers', targetField: 'peerDependencies' as const }, | ||
| { field: 'dev', targetField: 'devDependencies' as const }, | ||
| { field: 'runtime', targetField: 'dependencies' as const }, | ||
| ]; | ||
| const pkgs: CurrentPkg[] = []; | ||
| for (const component of components) { | ||
| const isEnv = this.envs.isEnv(component); | ||
| if (!isEnv) continue; | ||
|
|
||
| const envJsoncFile = component.filesystem.files.find((file) => file.relative === 'env.jsonc'); | ||
| if (!envJsoncFile) continue; | ||
|
|
||
| let envJsonc: EnvJsonc; | ||
| try { | ||
| envJsonc = parse(envJsoncFile.contents.toString()) as EnvJsonc; | ||
| } catch (error: unknown) { | ||
| const errorMessage = error instanceof Error ? error.message : String(error); | ||
| this.logger.warn(`Failed to parse env.jsonc for component ${component.id.toString()}: ${errorMessage}`); | ||
| continue; | ||
| } | ||
| if (!envJsonc.policy) continue; | ||
|
|
||
| for (const { field, targetField } of policies) { | ||
| const deps: EnvJsoncPolicyEntry[] = envJsonc.policy?.[field] || []; | ||
| for (const dep of deps) { | ||
| pkgs.push({ | ||
| name: dep.name, | ||
| currentRange: dep.version, | ||
| source: 'env-jsonc', | ||
| componentId: component.id, | ||
| targetField, | ||
| }); | ||
| } |
There was a problem hiding this comment.
getEnvJsoncPolicyPkgs() returns currentRange: dep.version for env.jsonc policy entries. When an env.jsonc peer entry uses the special version "+" (supported elsewhere in the codebase/tests), bit update will treat it as an outdated range and then updateEnvJsoncPolicies() will overwrite the "+" with an explicit version/range, changing the meaning of the policy.
Consider either skipping env.jsonc entries whose version is "+"/"-" from outdated detection, or resolving them to an actual semver range (e.g. for peers: use supportedRange) and, on update, keep version: "+" while updating the appropriate range field.
| * Update env.jsonc policy files for environment components based on a list of outdated packages. | ||
| * @param outdatedPkgs - List of outdated packages. | ||
| */ | ||
| async updateEnvJsoncPolicies(outdatedPkgs: MergedOutdatedPkg[]): Promise<void> { |
There was a problem hiding this comment.
updateEnvJsoncPolicies is only called internally from updateDependencies, but it is currently declared as a public method. If it’s not intended to be part of the Install aspect public API, mark it private (or prefix with _ consistently) to avoid expanding the public surface area unintentionally.
| async updateEnvJsoncPolicies(outdatedPkgs: MergedOutdatedPkg[]): Promise<void> { | |
| private async updateEnvJsoncPolicies(outdatedPkgs: MergedOutdatedPkg[]): Promise<void> { |
| expect(newSupportedRange).to.include(' || '); | ||
| expect(newSupportedRange).to.include('^16.8.0'); | ||
| expect(newSupportedRange).to.include(newVersion); | ||
| }); |
There was a problem hiding this comment.
The new bit update e2e coverage validates updating explicit env.jsonc versions, but it doesn’t cover the existing env.jsonc special case where a peer entry has version: "+" (resolved via supportedRange). With the new update flow, this case is at risk of being rewritten to an explicit version/range.
Add an e2e assertion that running bit update does not overwrite version: "+" entries (and define the expected behavior for updating supportedRange, if applicable).
| }); | |
| }); | |
| it('should not overwrite peer version "+" and should update supportedRange to include the new version', () => { | |
| const envId3 = 'react-based-env-peers-plus'; | |
| helper.env.setCustomNewEnv(undefined, undefined, { | |
| policy: { | |
| peers: [ | |
| { | |
| name: 'react', | |
| version: '+', | |
| supportedRange: '^16.8.0', | |
| }, | |
| ], | |
| }, | |
| }, false, envId3); | |
| helper.command.install(); | |
| const envJsoncPath = path.join(helper.scopes.localPath, envId3, 'env.jsonc'); | |
| const originalEnvJsonc = fs.readJsonSync(envJsoncPath); | |
| expect(originalEnvJsonc.policy.peers[0].version).to.equal('+'); | |
| expect(originalEnvJsonc.policy.peers[0].supportedRange).to.equal('^16.8.0'); | |
| // Update react to latest while version is resolved via "+" and supportedRange | |
| helper.command.update('react --yes'); | |
| const updatedEnvJsonc = fs.readJsonSync(envJsoncPath); | |
| const updatedPeer = updatedEnvJsonc.policy.peers[0]; | |
| // The special-case "+" version must be preserved | |
| expect(updatedPeer.version).to.equal('+'); | |
| const updatedSupportedRange = updatedPeer.supportedRange; | |
| expect(updatedSupportedRange).to.not.equal('^16.8.0'); | |
| expect(updatedSupportedRange).to.include('^16.8.0'); | |
| // The updated supportedRange should include the newly installed react version | |
| const reactPkgJsonPath = resolveFrom(helper.scopes.localPath, 'react/package.json'); | |
| const reactPkgJson = fs.readJsonSync(reactPkgJsonPath); | |
| const installedVersion = reactPkgJson.version; | |
| expect(updatedSupportedRange).to.include(installedVersion); | |
| }); |
Proposed Changes