diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-05-03 22:14:28 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-05-03 22:14:28 +0900 |
| commit | 9a467625ff8d135c650c7fefacfa0358002ce4d2 (patch) | |
| tree | f1451272418aae11d0134d73ad4c9f514892842b /crates/mozart/src/commands/update.rs | |
| parent | 6d036ca5b0e6cb21e5b12a02d544a27e33a97a14 (diff) | |
| download | php-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.rs | 52 |
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(), |
