aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/mozart/src/commands/update.rs
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-05-03 22:14:28 +0900
committernsfisis <nsfisis@gmail.com>2026-05-03 22:14:28 +0900
commit9a467625ff8d135c650c7fefacfa0358002ce4d2 (patch)
treef1451272418aae11d0134d73ad4c9f514892842b /crates/mozart/src/commands/update.rs
parent6d036ca5b0e6cb21e5b12a02d544a27e33a97a14 (diff)
downloadphp-mozart-9a467625ff8d135c650c7fefacfa0358002ce4d2.tar.gz
php-mozart-9a467625ff8d135c650c7fefacfa0358002ce4d2.tar.zst
php-mozart-9a467625ff8d135c650c7fefacfa0358002ce4d2.zip
fix(update): apply --minimal-changes preferred versions on partial update
The previous --minimal-changes wiring only populated the policy's preferred-version map when no packages were named on the CLI, so a partial update like `update foo --with-all-dependencies --minimal-changes` saw an empty map and the resolver picked the highest matching version for transitive deps that should have stayed at their lock version. Mirror Composer's `Installer::createPolicy(minimalUpdate=true)` directly: build the map from the lock and skip only the packages explicitly named by the user (the `updateAllowList`), so deps unlocked transitively by `--with-(all-)dependencies` still prefer their lock version when the constraint allows it.
Diffstat (limited to 'crates/mozart/src/commands/update.rs')
-rw-r--r--crates/mozart/src/commands/update.rs52
1 files changed, 32 insertions, 20 deletions
diff --git a/crates/mozart/src/commands/update.rs b/crates/mozart/src/commands/update.rs
index 185d3be..01c2129 100644
--- a/crates/mozart/src/commands/update.rs
+++ b/crates/mozart/src/commands/update.rs
@@ -1167,29 +1167,41 @@ pub async fn run(
.and_then(|v| v.as_bool())
.unwrap_or(false);
- // For `--minimal-changes` without a per-package update list, feed the
- // lock's pinned versions into the resolver as preferred-version
- // overrides. Mirrors Composer's
- // `Installer::createPolicy(forUpdate=true, minimalUpdate=true)` branch.
- let preferred_versions: IndexMap<String, String> =
- if args.minimal_changes && raw_packages.is_empty() && lock_path.exists() {
- match lockfile::LockFile::read_from_file(&lock_path) {
- Ok(lock) => {
- let mut map = IndexMap::new();
- for pkg in lock
- .packages
- .iter()
- .chain(lock.packages_dev.iter().flatten())
- {
- map.insert(pkg.name.to_lowercase(), locked_version_normalized(pkg));
+ // For `--minimal-changes`, feed the lock's pinned versions into the
+ // resolver as preferred-version overrides. The packages the user
+ // explicitly named on the CLI are excluded — they're being asked to
+ // move, so the policy should pick the regular highest/lowest version
+ // for them. Mirrors Composer's
+ // `Installer::createPolicy(forUpdate=true, minimalUpdate=true)` branch,
+ // which loops over the locked repository and skips any
+ // `updateAllowList` entry. Transitive deps pulled in by
+ // `--with-(all-)dependencies` stay in the map so they only move when a
+ // constraint actually forces a different version.
+ let preferred_versions: IndexMap<String, String> = if args.minimal_changes && lock_path.exists()
+ {
+ match lockfile::LockFile::read_from_file(&lock_path) {
+ Ok(lock) => {
+ let allow_set: IndexSet<String> =
+ raw_packages.iter().map(|s| s.to_lowercase()).collect();
+ let mut map = IndexMap::new();
+ for pkg in lock
+ .packages
+ .iter()
+ .chain(lock.packages_dev.iter().flatten())
+ {
+ let name_lower = pkg.name.to_lowercase();
+ if allow_set.contains(&name_lower) {
+ continue;
}
- map
+ map.insert(name_lower, locked_version_normalized(pkg));
}
- Err(_) => IndexMap::new(),
+ map
}
- } else {
- IndexMap::new()
- };
+ Err(_) => IndexMap::new(),
+ }
+ } else {
+ IndexMap::new()
+ };
let request = ResolveRequest {
root_name: composer_json.name.clone(),