From f22d354924121fcd9a320120444b8aeaf7689224 Mon Sep 17 00:00:00 2001 From: Seow Alex Date: Thu, 28 Nov 2024 20:19:36 +0800 Subject: [PATCH] fix: ensure pinning strategy is not affected by non-semver packages (#2580) Fixes #2574. I added a test as well, but I'm not sure if it follows the project's standards. --- src/lock_file/satisfiability.rs | 2 +- src/project/mod.rs | 3 +- tests/integration_rust/add_tests.rs | 68 ++++++++++++++++++++++++++++- 3 files changed, 69 insertions(+), 4 deletions(-) diff --git a/src/lock_file/satisfiability.rs b/src/lock_file/satisfiability.rs index da81b22b4..8da5a37e1 100644 --- a/src/lock_file/satisfiability.rs +++ b/src/lock_file/satisfiability.rs @@ -1461,7 +1461,7 @@ mod tests { Ok(()) } - #[rstest::rstest] + #[rstest] #[tokio::test] async fn test_good_satisfiability( #[files("tests/data/satisfiability/*/pixi.toml")] manifest_path: PathBuf, diff --git a/src/project/mod.rs b/src/project/mod.rs index dabbbb970..4804a9514 100644 --- a/src/project/mod.rs +++ b/src/project/mod.rs @@ -883,9 +883,10 @@ impl Project { .flatten() .collect_vec(); - let mut pinning_strategy = self.config().pinning_strategy; let channel_config = self.channel_config(); for (name, (spec_type, spec)) in conda_specs_to_add_constraints_for { + let mut pinning_strategy = self.config().pinning_strategy; + // Edge case: some packages are a special case where we want to pin the minor // version by default. This is done to avoid early user confusion // when the minor version changes and environments magically start breaking. diff --git a/tests/integration_rust/add_tests.rs b/tests/integration_rust/add_tests.rs index ffca9726b..b4599b5c7 100644 --- a/tests/integration_rust/add_tests.rs +++ b/tests/integration_rust/add_tests.rs @@ -470,9 +470,8 @@ async fn add_sdist_functionality() { .unwrap(); } -#[rstest::rstest] #[tokio::test] -async fn add_unconstrainted_dependency() { +async fn add_unconstrained_dependency() { // Create a channel with a single package let mut package_database = PackageDatabase::default(); package_database.add_package(Package::build("foobar", "1").finish()); @@ -582,3 +581,68 @@ async fn pinning_dependency() { .to_string(); assert_eq!(python_spec, r#""==3.13""#); } + +#[tokio::test] +async fn add_dependency_pinning_strategy() { + // Create a channel with two packages + let mut package_database = PackageDatabase::default(); + package_database.add_package(Package::build("foo", "1").finish()); + package_database.add_package(Package::build("bar", "1").finish()); + package_database.add_package(Package::build("python", "3.13").finish()); + + let local_channel = package_database.into_channel().await.unwrap(); + + // Initialize a new pixi project using the above channel + let pixi = PixiControl::new().unwrap(); + pixi.init().with_channel(local_channel.url()).await.unwrap(); + + // Add the `packages` to the project + pixi.add_multiple(vec!["foo", "python", "bar"]) + .await + .unwrap(); + + let project = pixi.project().unwrap(); + + // Get the specs for the `foo` package + let foo_spec = project + .manifest() + .default_feature() + .dependencies(SpecType::Run, None) + .unwrap_or_default() + .get("foo") + .cloned() + .unwrap() + .to_toml_value() + .to_string(); + assert_eq!(foo_spec, r#"">=1,<2""#); + + // Get the specs for the `python` package + let python_spec = project + .manifest() + .default_feature() + .dependencies(SpecType::Run, None) + .unwrap_or_default() + .get("python") + .cloned() + .unwrap() + .to_toml_value() + .to_string(); + // Testing to see if edge cases are handled correctly + // Python shouldn't be automatically pinned to a major version. + assert_eq!(python_spec, r#"">=3.13,<3.14""#); + + // Get the specs for the `bar` package + let bar_spec = project + .manifest() + .default_feature() + .dependencies(SpecType::Run, None) + .unwrap_or_default() + .get("bar") + .cloned() + .unwrap() + .to_toml_value() + .to_string(); + // Testing to make sure bugfix did not regress + // Package should be automatically pinned to a major version + assert_eq!(bar_spec, r#"">=1,<2""#); +}