aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-05-02 22:46:44 +0900
committernsfisis <nsfisis@gmail.com>2026-05-02 22:46:44 +0900
commit3c61a7e1e557e3b90128d2ec29227f166b17c05b (patch)
treee68f5a03ac3ca5ba3a1ab29de755b18e0f3228e5 /crates
parent8da98493daf5013585e07ec98ca6960a42924edf (diff)
downloadphp-mozart-3c61a7e1e557e3b90128d2ec29227f166b17c05b.tar.gz
php-mozart-3c61a7e1e557e3b90128d2ec29227f166b17c05b.tar.zst
php-mozart-3c61a7e1e557e3b90128d2ec29227f166b17c05b.zip
feat(resolver): support inline #ref pin and default-branch alias
Adds the missing pieces for installer fixtures that pin a dev package via `dev-foo#hex` or rely on Composer's `default-branch: true` synthetic `9999999-dev` alias. Mirrors Composer at four layers: 1. `mozart_semver::parse_single` strips `dev-...#hex` / `....x-dev#hex` suffixes from constraints (Composer's `parseConstraint` regex). 2. `PackagistVersion` carries `default_branch`. When set on a `dev-` package with no numeric prefix, `packagist_to_pool_inputs` emits the synthetic `9999999-dev` alias — but skips it when an explicit `extra.branch-alias` already covers the version (matches `ArrayLoader::getBranchAlias`). 3. `RuleSetGenerator::generate` picks up `addRulesForRootAliases`: any pool alias whose target was added gets its own alias↔target rules so the SAT solver pulls them in together. 4. `lockfile::generate_lock_file` extracts root `#hex` overrides from `require`/`require-dev` and rewrites source/dist references (and github/gitlab/bitbucket archive URLs) on the matched package, the `setSourceDistReferences` ladder Composer runs in `PoolBuilder`. Resolver also infers `Stability::Dev` from a `dev-foo` style single-atom constraint when no explicit `@flag` is given, mirroring the second loop of `RootPackageLoader::extractStabilityFlags` so the package isn't filtered out under default `stable` minimum-stability. Newly green: install_branch_alias_composer_repo, install_reference, conflict_with_alias_prevents_update_if_not_required, unbounded_conflict_matches_default_branch. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates')
-rw-r--r--crates/mozart-registry/src/lockfile.rs128
-rw-r--r--crates/mozart-registry/src/packagist.rs8
-rw-r--r--crates/mozart-registry/src/resolver.rs120
-rw-r--r--crates/mozart-registry/src/vcs_bridge.rs1
-rw-r--r--crates/mozart-registry/src/version.rs1
-rw-r--r--crates/mozart-sat-resolver/src/rule_set_generator.rs18
-rw-r--r--crates/mozart-semver/src/lib.rs38
-rw-r--r--crates/mozart/tests/installer.rs6
8 files changed, 315 insertions, 5 deletions
diff --git a/crates/mozart-registry/src/lockfile.rs b/crates/mozart-registry/src/lockfile.rs
index e422a9a..045b189 100644
--- a/crates/mozart-registry/src/lockfile.rs
+++ b/crates/mozart-registry/src/lockfile.rs
@@ -407,6 +407,114 @@ fn packagist_dist_to_locked(pd: &PackagistDist) -> LockedDist {
}
}
+/// Mirror Composer's `RootPackageLoader::extractReferences`: scan
+/// `require`/`require-dev` for `dev-foo#hex` style constraints, returning a
+/// lowercase package name → reference map. Constraints whose stability isn't
+/// `dev` after stripping the reference are left out (matching the
+/// `'dev' === VersionParser::parseStability(...)` guard in PHP).
+fn extract_root_references(
+ require: &BTreeMap<String, String>,
+ require_dev: &BTreeMap<String, String>,
+) -> BTreeMap<String, String> {
+ let mut out = BTreeMap::new();
+ for (name, raw_constraint) in require.iter().chain(require_dev.iter()) {
+ if let Some(reference) = parse_inline_reference(raw_constraint) {
+ out.insert(name.to_lowercase(), reference);
+ }
+ }
+ out
+}
+
+/// Pull the `#hex` suffix out of a single-atom dev constraint. Returns
+/// `None` for non-`dev-*` / non-`*-dev` constraints, matching Composer's
+/// `'{^[^,\s@]+?#([a-f0-9]+)$}'` + `parseStability == 'dev'` guard.
+fn parse_inline_reference(constraint: &str) -> Option<String> {
+ // Strip `... as alias` first, mirroring extractReferences's
+ // `'{^([^,\s@]+) as .+$}'` replacement.
+ let core = match constraint.split(" as ").next() {
+ Some(c) => c.trim(),
+ None => constraint.trim(),
+ };
+ let (head, hash) = core.rsplit_once('#')?;
+ if hash.is_empty() || !hash.chars().all(|c| c.is_ascii_hexdigit()) {
+ return None;
+ }
+ if head.contains([' ', '\t', ',', '@']) {
+ return None;
+ }
+ let lower = head.to_lowercase();
+ if !(lower.starts_with("dev-") || lower.ends_with("-dev")) {
+ return None;
+ }
+ Some(hash.to_string())
+}
+
+/// Mirror `Composer\Package\Package::setSourceDistReferences`: rewrite both
+/// source and dist references to the supplied value, and rewrite the
+/// reference inside any auto-generated GitHub/GitLab/Bitbucket dist URL when
+/// present. The dist reference is only written if there was already one
+/// (Composer leaves `dist.reference == null` packages alone).
+fn apply_reference_override(pkg: &mut LockedPackage, reference: &str) {
+ if let Some(source) = pkg.source.as_mut() {
+ source.reference = Some(reference.to_string());
+ }
+ if let Some(dist) = pkg.dist.as_mut() {
+ let url_carries_known_host = matches_dist_url_with_known_host(Some(&dist.url));
+ if dist.reference.is_some() || url_carries_known_host {
+ dist.reference = Some(reference.to_string());
+ }
+ if url_carries_known_host {
+ dist.url = rewrite_known_dist_url_reference(&dist.url, reference);
+ }
+ }
+}
+
+/// Match the bitbucket / github / gitlab dist-URL prefixes Composer
+/// rewrites. Mirrors the regex
+/// `{^https?://(?:(?:www\.)?bitbucket\.org|(api\.)?github\.com|(?:www\.)?gitlab\.com)/}i`.
+fn matches_dist_url_with_known_host(url: Option<&str>) -> bool {
+ let Some(url) = url else { return false };
+ let lower = url.to_lowercase();
+ let stripped = lower
+ .strip_prefix("http://")
+ .or_else(|| lower.strip_prefix("https://"))
+ .unwrap_or(&lower);
+ let stripped = stripped.strip_prefix("www.").unwrap_or(stripped);
+ let stripped = stripped.strip_prefix("api.").unwrap_or(stripped);
+ stripped.starts_with("bitbucket.org/")
+ || stripped.starts_with("github.com/")
+ || stripped.starts_with("gitlab.com/")
+}
+
+/// Substitute any 40-char hex segment surrounded by `/` or `sha=` (the
+/// archive shape produced by GitHub/GitLab/Bitbucket) with the new
+/// reference. Matches Composer's
+/// `'{(?<=/|sha=)[a-f0-9]{40}(?=/|$)}i'` rewrite.
+fn rewrite_known_dist_url_reference(url: &str, reference: &str) -> String {
+ let bytes = url.as_bytes();
+ let mut out = String::with_capacity(url.len());
+ let mut i = 0;
+ while i < bytes.len() {
+ let start = i;
+ let preceded_by_slash = i > 0 && bytes[i - 1] == b'/';
+ let preceded_by_sha = i >= 4 && &bytes[i - 4..i] == b"sha=";
+ if (preceded_by_slash || preceded_by_sha) && i + 40 <= bytes.len() {
+ let candidate = &url[i..i + 40];
+ if candidate.chars().all(|c| c.is_ascii_hexdigit()) {
+ let after = bytes.get(i + 40).copied();
+ if after == Some(b'/') || after.is_none() {
+ out.push_str(reference);
+ i += 40;
+ continue;
+ }
+ }
+ }
+ out.push(url[start..].chars().next().unwrap());
+ i += url[start..].chars().next().unwrap().len_utf8();
+ }
+ out
+}
+
/// Convert a `PackagistVersion` to a `LockedPackage`.
fn packagist_version_to_locked_package(name: &str, pv: &PackagistVersion) -> LockedPackage {
let mut extra_fields: BTreeMap<String, serde_json::Value> = BTreeMap::new();
@@ -600,12 +708,26 @@ pub async fn generate_lock_file(request: &LockFileGenerationRequest) -> anyhow::
&package_metadata,
);
- // 3. Build LockedPackage lists
+ // 3. Build LockedPackage lists.
+ //
+ // Apply root-level `#hex` reference overrides extracted from
+ // `require`/`require-dev`. Mirrors Composer's
+ // `RootPackageLoader::extractReferences` + `PoolBuilder::loadPackage`'s
+ // `setSourceDistReferences` call: when the user pinned a dev package via
+ // `dev-main#abcd123`, the resolved package's source/dist must show that
+ // reference in the lock + trace, not whatever the inline metadata said.
+ let root_references = extract_root_references(
+ &request.composer_json.require,
+ &request.composer_json.require_dev,
+ );
let mut packages: Vec<LockedPackage> = Vec::new();
let mut packages_dev: Vec<LockedPackage> = Vec::new();
for pkg in &real_resolved {
let pv = &package_metadata[&pkg.name];
- let locked = packagist_version_to_locked_package(&pkg.name, pv);
+ let mut locked = packagist_version_to_locked_package(&pkg.name, pv);
+ if let Some(reference) = root_references.get(&pkg.name.to_lowercase()) {
+ apply_reference_override(&mut locked, reference);
+ }
if dev_only.contains(&pkg.name) {
packages_dev.push(locked);
} else {
@@ -869,6 +991,7 @@ mod tests {
time: Some("2024-01-15T10:00:00+00:00".to_string()),
extra: Some(serde_json::json!({"branch-alias": {"dev-main": "1.0.x-dev"}})),
notification_url: Some("https://packagist.org/downloads/".to_string()),
+ default_branch: false,
}
}
@@ -943,6 +1066,7 @@ mod tests {
time: None,
extra: None,
notification_url: None,
+ default_branch: false,
};
let locked = packagist_version_to_locked_package("vendor/pkg", &pv);
diff --git a/crates/mozart-registry/src/packagist.rs b/crates/mozart-registry/src/packagist.rs
index 64ff11a..1d9356d 100644
--- a/crates/mozart-registry/src/packagist.rs
+++ b/crates/mozart-registry/src/packagist.rs
@@ -127,6 +127,14 @@ pub struct PackagistVersion {
deserialize_with = "deserialize_unset_as_none"
)]
pub notification_url: Option<String>,
+
+ /// `default-branch: true` marks the repository's default branch (e.g. the
+ /// branch returned by `git symbolic-ref HEAD`). For packages without a
+ /// numeric version prefix this triggers the synthetic `9999999-dev` alias
+ /// generation in `ArrayLoader::getBranchAlias` — see the alias loop in
+ /// `crate::resolver::packagist_to_pool_inputs`.
+ #[serde(rename = "default-branch", default)]
+ pub default_branch: bool,
}
impl PackagistVersion {
diff --git a/crates/mozart-registry/src/resolver.rs b/crates/mozart-registry/src/resolver.rs
index 4b8266d..a83304f 100644
--- a/crates/mozart-registry/src/resolver.rs
+++ b/crates/mozart-registry/src/resolver.rs
@@ -52,6 +52,61 @@ pub(crate) fn extract_stability_suffix(constraint: &str) -> (String, Option<Stab
(trimmed.to_string(), None)
}
+/// Mirror Composer's `VersionParser::parseStability` for a single-atom
+/// constraint string (no `@flag` suffix). Returns `Some(stability)` for
+/// recognised non-stable constraints (`dev-foo`, `1.0.x-dev`, `1.0.0-beta1`,
+/// …), `None` for stable or unrecognised forms (in which case
+/// `minimum_stability` already applies).
+///
+/// Composer first strips a trailing `#hash` (handled here), then checks
+/// `dev-` prefix / `-dev` suffix / a `(stab)?\d*` modifier. We follow the
+/// same shape — the regex variant is overkill for inferring a flag.
+pub(crate) fn infer_constraint_stability(constraint: &str) -> Option<Stability> {
+ let s = constraint.trim();
+ // Strip `#ref` (matches Composer's `parseStability` line 54).
+ let s = match s.find('#') {
+ Some(p) => &s[..p],
+ None => s,
+ };
+ // Reject multi-atom constraints — extractStabilityFlags inspects each
+ // sub-constraint individually but the most common single-atom case is
+ // all we need for `dev-foo` / `1.0.x-dev` style root requires.
+ if s.contains([' ', ',']) || s.contains("||") {
+ return None;
+ }
+ // Strip a leading comparison operator (`>=1.0-beta` → `1.0-beta`).
+ let s = s
+ .strip_prefix(">=")
+ .or_else(|| s.strip_prefix("<="))
+ .or_else(|| s.strip_prefix("!="))
+ .or_else(|| s.strip_prefix("=="))
+ .or_else(|| s.strip_prefix('>'))
+ .or_else(|| s.strip_prefix('<'))
+ .or_else(|| s.strip_prefix('='))
+ .or_else(|| s.strip_prefix('^'))
+ .or_else(|| s.strip_prefix('~'))
+ .unwrap_or(s);
+ let lower = s.to_lowercase();
+ if lower.starts_with("dev-") || lower.ends_with("-dev") {
+ return Some(Stability::Dev);
+ }
+ // Match `<modifier><digits?>` at the end after the last `-`/`@`.
+ // Composer uses `{(stable|RC|beta|alpha|dev)([.-]?\d+)?(?:\+.*)?$}`.
+ let tail = lower
+ .rsplit_once('-')
+ .or_else(|| lower.rsplit_once('@'))
+ .map(|(_, t)| t)
+ .unwrap_or(&lower);
+ let tail_word: String = tail.chars().take_while(|c| c.is_alphabetic()).collect();
+ match tail_word.as_str() {
+ "alpha" | "a" => Some(Stability::Alpha),
+ "beta" | "b" => Some(Stability::Beta),
+ "rc" => Some(Stability::RC),
+ "patch" | "pl" | "p" | "stable" => Some(Stability::Stable),
+ _ => None,
+ }
+}
+
/// Determine the `Stability` of a `Version` from its pre_release string.
pub(crate) fn version_stability(v: &Version) -> Stability {
match &v.pre_release {
@@ -119,6 +174,25 @@ fn parse_branch_alias_target(alias_target: &str) -> Option<Version> {
})
}
+/// Mirror Composer's `VersionParser::parseNumericAliasPrefix`: returns true
+/// when the input is a numeric branch like `1.2-dev` / `1.2.3-dev` /
+/// `1.2.x-dev` (i.e. the prefix is suitable for version comparison).
+/// Non-numeric branches like `dev-main` / `dev-feature/x` return false.
+fn has_numeric_alias_prefix(branch: &str) -> bool {
+ let lower = branch.trim().to_lowercase();
+ let lower = lower.strip_prefix('v').unwrap_or(&lower);
+ let Some(base) = lower.strip_suffix("-dev") else {
+ return false;
+ };
+ let base = base.strip_suffix(".x").unwrap_or(base);
+ if base.is_empty() {
+ return false;
+ }
+ // Allow only digit segments separated by `.`.
+ base.split('.')
+ .all(|seg| !seg.is_empty() && seg.chars().all(|c| c.is_ascii_digit()))
+}
+
/// Mirror Composer's `VersionParser::normalizeBranch` for branch-alias
/// targets: turn a string like `"3.2.x-dev"` into the canonical numeric form
/// `"3.2.9999999.9999999-dev"`. Returns `None` if the input is not a numeric
@@ -398,6 +472,7 @@ fn packagist_to_pool_inputs(
results.push(make_input(&pv.version, &pv.version_normalized, None));
let aliases = pv.branch_aliases();
+ let mut emitted_explicit_alias = false;
for (branch, alias_target) in &aliases {
if branch.to_lowercase() != pv.version.to_lowercase() {
continue;
@@ -413,6 +488,37 @@ fn packagist_to_pool_inputs(
&alias_normalized,
Some(pv.version_normalized.clone()),
));
+ emitted_explicit_alias = true;
+ }
+
+ // Mirror Composer's `ArrayLoader::getBranchAlias`: when a
+ // `dev-` package carries `default-branch: true` and the version
+ // has no numeric prefix (i.e. it isn't already a `1.0.x-dev` form
+ // that would be its own alias), synthesize the `9999999-dev`
+ // alias so root constraints like `dev-main` pick up a default
+ // branch surfaced as `9999999-dev` in the lock + trace output.
+ //
+ // `getBranchAlias` returns the *first* matching branch-alias when
+ // one exists — i.e. an explicit `branch-alias` entry takes
+ // precedence over the `default-branch` synthetic one. Skip the
+ // synthetic alias when an explicit one has already been emitted
+ // for this version.
+ if pv.default_branch
+ && !emitted_explicit_alias
+ && !has_numeric_alias_prefix(&pv.version)
+ {
+ let default_alias = "9999999-dev";
+ let default_normalized = "9999999.9999999.9999999.9999999-dev";
+ let already_present = results
+ .iter()
+ .any(|r| r.version == default_normalized && r.name == package_name);
+ if !already_present {
+ results.push(make_input(
+ default_alias,
+ default_normalized,
+ Some(pv.version_normalized.clone()),
+ ));
+ }
}
}
}
@@ -499,6 +605,7 @@ pub async fn resolve(request: &ResolveRequest) -> Result<Vec<ResolvedPackage>, R
// request's caller-supplied flags (which today are usually empty).
let mut stability_flags: HashMap<String, Stability> = request.stability_flags.clone();
+ let minimum_stability = request.minimum_stability;
let mut insert_root_require = |name: &str, constraint: &str| {
let (clean, stability) = extract_stability_suffix(constraint);
let lower = name.to_lowercase();
@@ -507,6 +614,19 @@ pub async fn resolve(request: &ResolveRequest) -> Result<Vec<ResolvedPackage>, R
if (*entry as u8) > (s as u8) {
*entry = s;
}
+ } else if let Some(inferred) = infer_constraint_stability(&clean) {
+ // Mirrors `RootPackageLoader::extractStabilityFlags` second loop:
+ // when a single-atom constraint like `dev-main` or `1.0.x-dev`
+ // implies a non-stable stability and no explicit `@flag` was
+ // given, raise that package's stability ceiling so the pool
+ // accepts it. Only applied when the inferred level is *more*
+ // permissive than `minimum_stability` and any existing flag.
+ if (inferred as u8) > (minimum_stability as u8) {
+ let entry = stability_flags.entry(lower.clone()).or_insert(inferred);
+ if (*entry as u8) < (inferred as u8) {
+ *entry = inferred;
+ }
+ }
}
root_requires.insert(lower, Some(clean));
};
diff --git a/crates/mozart-registry/src/vcs_bridge.rs b/crates/mozart-registry/src/vcs_bridge.rs
index cb8aad5..7714630 100644
--- a/crates/mozart-registry/src/vcs_bridge.rs
+++ b/crates/mozart-registry/src/vcs_bridge.rs
@@ -182,6 +182,7 @@ pub fn vcs_to_packagist_version(vpkg: &VcsPackageVersion) -> PackagistVersion {
time: vpkg.time.clone(),
extra: vpkg.composer_json.get("extra").cloned(),
notification_url: None,
+ default_branch: vpkg.is_default_branch,
}
}
diff --git a/crates/mozart-registry/src/version.rs b/crates/mozart-registry/src/version.rs
index 8a26e92..ba120fa 100644
--- a/crates/mozart-registry/src/version.rs
+++ b/crates/mozart-registry/src/version.rs
@@ -198,6 +198,7 @@ mod tests {
time: None,
extra: None,
notification_url: None,
+ default_branch: false,
}
}
diff --git a/crates/mozart-sat-resolver/src/rule_set_generator.rs b/crates/mozart-sat-resolver/src/rule_set_generator.rs
index b5dfcdb..92b9f77 100644
--- a/crates/mozart-sat-resolver/src/rule_set_generator.rs
+++ b/crates/mozart-sat-resolver/src/rule_set_generator.rs
@@ -105,6 +105,24 @@ impl<'a> RuleSetGenerator<'a> {
}
}
+ // Mirror Composer's `RuleSetGenerator::addRulesForRootAliases`:
+ // ensure every alias whose target was already added gets its own
+ // alias↔target rules, even when the alias itself didn't appear in
+ // any root require's `whatProvides` (e.g. the synthetic
+ // `9999999-dev` alias from a `default-branch: true` package, which
+ // only matches a literal `9999999-dev` constraint).
+ let alias_pairs: Vec<(PackageId, PackageId)> = self
+ .pool
+ .packages()
+ .iter()
+ .filter_map(|p| p.is_alias_of.map(|t| (p.id, t)))
+ .collect();
+ for (alias_id, target_id) in alias_pairs {
+ if self.added_map.contains(&target_id) && !self.added_map.contains(&alias_id) {
+ self.add_rules_for_package(alias_id);
+ }
+ }
+
// Add conflict rules
self.add_conflict_rules();
diff --git a/crates/mozart-semver/src/lib.rs b/crates/mozart-semver/src/lib.rs
index dfb0db2..a15db13 100644
--- a/crates/mozart-semver/src/lib.rs
+++ b/crates/mozart-semver/src/lib.rs
@@ -669,12 +669,50 @@ fn split_and(s: &str) -> Vec<String> {
parts
}
+/// Strip `#ref` suffix from `dev-...#hex` / `....x-dev#hex` constraint
+/// strings. Mirrors Composer's
+/// `'{^(dev-[^,\s@]+?|[^,\s@]+?\.x-dev)#.+$}i'` regex strip in
+/// `VersionParser::parseConstraint`. Returns a `Cow` so callers that pass
+/// constraints without `#` see no allocation.
+fn strip_constraint_ref(s: &str) -> std::borrow::Cow<'_, str> {
+ let lower = s.to_lowercase();
+ let Some(hash_pos) = s.find('#') else {
+ return std::borrow::Cow::Borrowed(s);
+ };
+ let head = &lower[..hash_pos];
+ let rest = &s[hash_pos + 1..];
+ if rest.is_empty() {
+ return std::borrow::Cow::Borrowed(s);
+ }
+ // Accept `dev-foo` or `1.2.x-dev` style prefixes only, mirroring the
+ // Composer regex. Anything else (e.g. URLs, comments) is left alone.
+ let head_no_space = !head
+ .chars()
+ .any(|c: char| c.is_whitespace() || c == ',' || c == '@');
+ if !head_no_space {
+ return std::borrow::Cow::Borrowed(s);
+ }
+ let matches = head.starts_with("dev-") || head.ends_with(".x-dev");
+ if matches {
+ std::borrow::Cow::Owned(s[..hash_pos].to_string())
+ } else {
+ std::borrow::Cow::Borrowed(s)
+ }
+}
+
/// Parse a single constraint part.
fn parse_single(s: &str) -> Result<VersionConstraint, String> {
if s == "*" || s.is_empty() {
return Ok(VersionConstraint::Single(Constraint::Any));
}
+ // Strip `#ref` suffixes from `dev-...#hex` / `....x-dev#hex` constraints —
+ // they pin a source reference at the root level (handled by the
+ // installer) and are not part of the version match. Mirrors Composer's
+ // `VersionParser::parseConstraint` `'{^(dev-[^,\s@]+?|[^,\s@]+?\.x-dev)#.+$}i'` strip.
+ let s = strip_constraint_ref(s);
+ let s = s.as_ref();
+
// Caret: ^1.2.3
if let Some(rest) = s.strip_prefix('^') {
return parse_caret(rest);
diff --git a/crates/mozart/tests/installer.rs b/crates/mozart/tests/installer.rs
index d674485..fcb29c1 100644
--- a/crates/mozart/tests/installer.rs
+++ b/crates/mozart/tests/installer.rs
@@ -244,7 +244,7 @@ installer_fixture!(
);
installer_fixture!(conflict_with_alias_in_lock_does_prevents_install, ignore);
installer_fixture!(conflict_with_alias_prevents_update, ignore);
-installer_fixture!(conflict_with_alias_prevents_update_if_not_required, ignore);
+installer_fixture!(conflict_with_alias_prevents_update_if_not_required);
installer_fixture!(conflict_with_all_dependencies_option_dont_recommend_to_use_it);
installer_fixture!(deduplicate_solver_problems);
installer_fixture!(disjunctive_multi_constraints);
@@ -276,7 +276,7 @@ installer_fixture!(install_missing_alias_from_lock, ignore);
installer_fixture!(install_overridden_platform_packages, ignore);
installer_fixture!(install_package_and_its_provider_skips_original);
installer_fixture!(install_prefers_repos_over_package_versions, ignore);
-installer_fixture!(install_reference, ignore);
+installer_fixture!(install_reference);
installer_fixture!(install_security_advisory_matching_dependency);
installer_fixture!(install_self_from_root);
installer_fixture!(install_simple);
@@ -361,7 +361,7 @@ installer_fixture!(suggest_replaced);
installer_fixture!(suggest_uninstalled);
installer_fixture!(unbounded_conflict_does_not_match_default_branch_with_branch_alias);
installer_fixture!(unbounded_conflict_does_not_match_default_branch_with_numeric_branch);
-installer_fixture!(unbounded_conflict_matches_default_branch, ignore);
+installer_fixture!(unbounded_conflict_matches_default_branch);
installer_fixture!(
update_abandoned_package_required_but_blocked_via_audit_config,
ignore