You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix(deps): keep env.jsonc component peers after lane merge, support +^/+~ versions - #10815
An env.jsonc peer can be a component that is also on the lane. On the lane, the component dependency is a peer with the lane snap. When the lane is released from a bare scope, the snap/tag recalculates the dependency-resolver data from the legacy fields. The legacy fields do not keep component peers. Thus, the peers are removed on main, and each new lane shows them as new dependencies. Also, the released package.json keeps the env.jsonc version, which can be older than the version that is released.
This PR:
Restores the component peers from the dependency-resolver data when a component is loaded from the model (toConsumerComponent). The bare-scope snap/tag now keeps them.
Adds +^ and +~ to the + placeholder in env.jsonc (version and supportedRange). The placeholder uses the resolved version of the dependency: the snap on a lane, and the new tag after the release (for example, +^ gives ^1.2.3). A prefix is not added to a snap.
Tests: unit tests for the new helper and the policy validation. An e2e test snaps on a lane, merges, releases from a bare scope, and makes sure that the peer stays and the package.json has ^<new-tag>.
Preserve component peers on lane release and resolve +^/+~ versions
🐞 Bug fix✨ Enhancement🧪 Tests🕐 40+ Minutes
AI Description
• Preserve component peers when merged lanes are tagged from bare scopes.
• Resolve env.jsonc +^ and +~ placeholders against current snaps or released tags.
• Cover policy validation, version resolution, and lane-to-release behavior with tests.
The following are alternative approaches to this PR:
1. Persist peers in legacy Version fields
➕ All consumers of legacy dependency fields could see component peers directly.
➖ Duplicates dependency-resolver data and requires handling existing versions that lack those fields.
2. Recompute env peers during bare-scope tagging
➕ Avoids restoring peers when loading every model component.
➖ Depends on env policy and dependency resolution being available during remote release; does not recover peers from stored resolver data.
Recommendation: Keep the PR’s model-loading restoration: it recovers peers from data already stored in historical versions and supports bare-scope tagging without requiring the env to be resolved again. Centralizing placeholder resolution is preferable to separate +^/+~ rules in each manifest path.
Files changed (19) +294 / -33
Enhancement (12) +89 / -27
component-overrides.tsTreat plus-prefixed overrides as placeholders+2/-1
Treat plus-prefixed overrides as placeholders
• Excludes +, +^, and +~ override values from concrete-version handling.
model-component.tsRestore component peers when loading model versions+23/-2
Restore component peers when loading model versions
• Reconstructs component peer dependencies from dependency-resolver extension data when creating a ConsumerComponent. This keeps them available when bare-scope tagging recalculates dependency data.
lane-env-jsonc-dep.e2e.tsTest component peers through lane merge and release+94/-0
Test component peers through lane merge and release
• Exercises snapping, merging, and bare-scope tagging of an env.jsonc component peer. Checks that the peer survives in resolver data and the capsule package.json uses the new tag with a caret range.
1. One environment loses its peer package 🐞 Bug≡ Correctness⭐ New
Description
mergeEnvPeersToRoot() skips +^ and +~ in a non-singleton version conflict without adding a
root entry or a per-component override for the environment that declared the placeholder. When
another environment requests a concrete version of the same package and the workspace has no
independent root dependency for it, only that other environment receives an injected dependency; the
placeholder environment has no peer installed.
The changed condition drops the newly supported placeholders during non-singleton conflicts. That
branch adds neither a resolved root entry nor an override for the skipped environment; the root
manifest only adds peers supplied through the resulting root policy.
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution
## Issue description
In a non-singleton conflict, skipping a `+^` or `+~` env peer can leave its components without that package when the workspace has no existing root dependency.
## Fix Focus Areas
- scopes/dependencies/dependency-resolver/manifest/workspace-manifest-factory.ts[222-257]
- scopes/dependencies/dependency-resolver/manifest/workspace-manifest-factory.ts[267-278]
## Recommended Fix
In the non-singleton branch, resolve placeholder peers against an existing workspace dependency when one exists; otherwise provide a valid fallback dependency for the affected environment rather than discarding its entry. Add a test with two envs requesting the same peer as `+^` and a concrete version, with no independent root dependency.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
2. Uninstalled peers lose their tag range✓ Resolved
Description
applyAutoDetectedPeersFromEnvOnEnvItSelf() now resolves +^ and +~ through
resolveEnvPeerDepVersion(), but that fallback checks the model's regular dependencies and not its
restored component peers. When the peer is available only from the model, with no installed package
or workspace policy entry, resolution returns '*' rather than a range based on the peer's tag.
The new resolution path calls the fallback for +^ and +~. Model loading now restores component
peers into a separate peer-dependency list, but the fallback searches only regular model
dependencies and package dependencies before returning '*'; resolvePlusVersion() leaves that
wildcard unchanged.
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution
## Issue description
An env peer using `+^` or `+~` resolves to `'*'` when its component version is available only in the model's restored peer dependencies.
## Fix Focus Areas
- scopes/dependencies/dependencies/dependencies-loader/apply-overrides.ts[780-805]
- scopes/scope/objects/models/model-component.ts[1250-1261]
## Recommended Fix
Have `resolveEnvPeerDepVersion()` also look up the matching component in `componentFromModel.peerDependencies` before falling back to `'*'`. Add a test for a peer absent from installed packages and workspace policy.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
Context sources
Review mode: Auto: 🧠 Deep: Many independent dependency-resolution paths and subtle lane-release behavior changed.
Tip of the day
💡 Did you know, you can hide the parts of a finding you never read, like the evidence or the agent prompt
1. Uninstalled peers lose their tag range 🐞 Bug≡ Correctness
Description
applyAutoDetectedPeersFromEnvOnEnvItSelf() now resolves +^ and +~ through
resolveEnvPeerDepVersion(), but that fallback checks the model's regular dependencies and not its
restored component peers. When the peer is available only from the model, with no installed package
or workspace policy entry, resolution returns '*' rather than a range based on the peer's tag.
The new resolution path calls the fallback for +^ and +~. Model loading now restores component
peers into a separate peer-dependency list, but the fallback searches only regular model
dependencies and package dependencies before returning '*'; resolvePlusVersion() leaves that
wildcard unchanged.
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution
## Issue description
An env peer using `+^` or `+~` resolves to `'*'` when its component version is available only in the model's restored peer dependencies.
## Fix Focus Areas
- scopes/dependencies/dependencies/dependencies-loader/apply-overrides.ts[780-805]
- scopes/scope/objects/models/model-component.ts[1250-1261]
## Recommended Fix
Have `resolveEnvPeerDepVersion()` also look up the matching component in `componentFromModel.peerDependencies` before falling back to `'*'`. Add a test for a peer absent from installed packages and workspace policy.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
An env.jsonc peer can be a component that is also on the lane. On the lane, the component dependency is a peer with the lane snap. When the lane is released from a bare scope, the snap/tag recalculates the dependency-resolver data from the legacy fields. The legacy fields do not keep component peers. Thus, the peers are removed on main, and each new lane shows them as new dependencies. Also, the released package.json keeps the env.jsonc version, which can be older than the version that is released.
This PR:
toConsumerComponent). The bare-scope snap/tag now keeps them.+^and+~to the+placeholder in env.jsonc (versionandsupportedRange). The placeholder uses the resolved version of the dependency: the snap on a lane, and the new tag after the release (for example,+^gives^1.2.3). A prefix is not added to a snap.Tests: unit tests for the new helper and the policy validation. An e2e test snaps on a lane, merges, releases from a bare scope, and makes sure that the peer stays and the package.json has
^<new-tag>.