diff --git a/crates/uv/tests/it/branching_urls.rs b/crates/uv/tests/it/branching_urls.rs index 88da1f1c0..759fc67c7 100644 --- a/crates/uv/tests/it/branching_urls.rs +++ b/crates/uv/tests/it/branching_urls.rs @@ -621,6 +621,7 @@ fn branching_between_registry_and_direct_url() -> Result<()> { /// ] /// ``` #[test] +#[cfg(feature = "git")] fn branching_urls_of_different_sources_disjoint() -> Result<()> { let context = TestContext::new("3.12"); @@ -703,6 +704,7 @@ fn branching_urls_of_different_sources_disjoint() -> Result<()> { /// ] /// ``` #[test] +#[cfg(feature = "git")] fn branching_urls_of_different_sources_conflict() -> Result<()> { let context = TestContext::new("3.12"); diff --git a/crates/uv/tests/it/common/mod.rs b/crates/uv/tests/it/common/mod.rs index cef8a0746..e71c28182 100644 --- a/crates/uv/tests/it/common/mod.rs +++ b/crates/uv/tests/it/common/mod.rs @@ -89,6 +89,7 @@ pub struct TestContext { pub cache_dir: ChildPath, pub python_dir: ChildPath, pub home_dir: ChildPath, + pub bin_dir: ChildPath, pub venv: ChildPath, pub workspace_root: PathBuf, @@ -274,6 +275,14 @@ impl TestContext { let python_dir = ChildPath::new(root.path()).child("python"); fs_err::create_dir_all(&python_dir).expect("Failed to create test Python directory"); + let bin_dir = ChildPath::new(root.path()).child("bin"); + fs_err::create_dir_all(&bin_dir).expect("Failed to create test bin directory"); + + // When the `git` feature is disabled, enforce that the test suite does not use `git` + if cfg!(not(feature = "git")) { + Self::disallow_git_cli(&bin_dir).expect("Failed to setup disallowed `git` command"); + } + let home_dir = ChildPath::new(root.path()).child("home"); fs_err::create_dir_all(&home_dir).expect("Failed to create test home directory"); @@ -441,6 +450,7 @@ impl TestContext { cache_dir, python_dir, home_dir, + bin_dir, venv, workspace_root, python_version, @@ -457,6 +467,24 @@ impl TestContext { command } + fn disallow_git_cli(bin_dir: &Path) -> std::io::Result<()> { + let contents = r"#!/bin/sh + echo 'error: `git` operations are not allowed — are you missing a cfg for the `git` feature?' >&2 + exit 127"; + let git = bin_dir.join(format!("git{}", env::consts::EXE_SUFFIX)); + fs_err::write(&git, contents)?; + + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + let mut perms = fs_err::metadata(&git)?.permissions(); + perms.set_mode(0o755); + fs_err::set_permissions(&git, perms)?; + } + + Ok(()) + } + /// Shared behaviour for almost all test commands. /// /// * Use a temporary cache directory @@ -468,12 +496,18 @@ impl TestContext { /// `UV_TEST_PYTHON_PATH` and an active venv (if applicable) by removing `VIRTUAL_ENV`. /// * Increase the stack size to avoid stack overflows on windows due to large async functions. pub fn add_shared_args(&self, command: &mut Command, activate_venv: bool) { + // Push the test context bin to the front of the PATH + let mut path = OsString::from(self.bin_dir.as_ref()); + path.push(if cfg!(windows) { ";" } else { ":" }); + path.push(env::var(EnvVars::PATH).unwrap_or_default()); + command .arg("--cache-dir") .arg(self.cache_dir.path()) // When running the tests in a venv, ignore that venv, otherwise we'll capture warnings. .env_remove(EnvVars::VIRTUAL_ENV) .env(EnvVars::UV_NO_WRAP, "1") + .env(EnvVars::PATH, path) .env(EnvVars::HOME, self.home_dir.as_os_str()) .env(EnvVars::UV_PYTHON_INSTALL_DIR, "") .env(EnvVars::UV_TEST_PYTHON_PATH, self.python_path()) diff --git a/crates/uv/tests/it/edit.rs b/crates/uv/tests/it/edit.rs index 84f8cd2ce..2b0a83d5f 100644 --- a/crates/uv/tests/it/edit.rs +++ b/crates/uv/tests/it/edit.rs @@ -4545,6 +4545,7 @@ fn add_repeat() -> Result<()> { /// Add from requirement file. #[test] +#[cfg(feature = "git")] fn add_requirements_file() -> Result<()> { let context = TestContext::new("3.12").with_filtered_counts(); diff --git a/crates/uv/tests/it/lock.rs b/crates/uv/tests/it/lock.rs index da799f6cf..71dc84412 100644 --- a/crates/uv/tests/it/lock.rs +++ b/crates/uv/tests/it/lock.rs @@ -10768,6 +10768,7 @@ fn lock_mismatched_sources() -> Result<()> { /// /// See: #[test] +#[cfg(feature = "git")] fn lock_mismatched_versions() -> Result<()> { let context = TestContext::new("3.12"); diff --git a/crates/uv/tests/it/main.rs b/crates/uv/tests/it/main.rs index 44c7488cb..5ffe6349e 100644 --- a/crates/uv/tests/it/main.rs +++ b/crates/uv/tests/it/main.rs @@ -28,7 +28,7 @@ mod export; mod help; -#[cfg(all(feature = "python", feature = "pypi"))] +#[cfg(all(feature = "python", feature = "pypi", feature = "git"))] mod init; #[cfg(all(feature = "python", feature = "pypi"))] diff --git a/crates/uv/tests/it/pip_install.rs b/crates/uv/tests/it/pip_install.rs index 3a5632fbb..9cffa5115 100644 --- a/crates/uv/tests/it/pip_install.rs +++ b/crates/uv/tests/it/pip_install.rs @@ -6812,6 +6812,7 @@ fn verify_hashes_editable() -> Result<()> { } #[test] +#[cfg(feature = "git")] fn tool_uv_sources() -> Result<()> { let context = TestContext::new("3.12"); // Use a subdir to test path normalization. @@ -8262,6 +8263,7 @@ fn cyclic_build_dependency() { } #[test] +#[cfg(feature = "git")] fn direct_url_json_git_default() -> Result<()> { let context = TestContext::new("3.12"); let requirements_txt = context.temp_dir.child("requirements.txt"); @@ -8299,6 +8301,7 @@ fn direct_url_json_git_default() -> Result<()> { } #[test] +#[cfg(feature = "git")] fn direct_url_json_git_tag() -> Result<()> { let context = TestContext::new("3.12"); let requirements_txt = context.temp_dir.child("requirements.txt"); diff --git a/crates/uv/tests/it/run.rs b/crates/uv/tests/it/run.rs index d2dbc41ce..63e4ca7bc 100644 --- a/crates/uv/tests/it/run.rs +++ b/crates/uv/tests/it/run.rs @@ -581,6 +581,7 @@ fn run_pythonw_script() -> Result<()> { /// Run a PEP 723-compatible script with `tool.uv` metadata. #[test] +#[cfg(feature = "git")] fn run_pep723_script_metadata() -> Result<()> { let context = TestContext::new("3.12"); diff --git a/crates/uv/tests/it/sync.rs b/crates/uv/tests/it/sync.rs index 9ee7cb238..59f4d02fb 100644 --- a/crates/uv/tests/it/sync.rs +++ b/crates/uv/tests/it/sync.rs @@ -3183,6 +3183,7 @@ fn sync_custom_environment_path() -> Result<()> { } #[test] +#[cfg(feature = "git")] fn sync_workspace_custom_environment_path() -> Result<()> { let context = TestContext::new("3.12"); @@ -5276,7 +5277,7 @@ fn sync_derivation_chain_group() -> Result<()> { /// See: #[test] -#[cfg(feature = "slow-tests")] +#[cfg(all(feature = "slow-tests", feature = "git"))] fn sync_stale_egg_info() -> Result<()> { let context = TestContext::new("3.13");