Reject Git CLI arguments with non-Git sources (#5377)

## Summary

Closes https://github.com/astral-sh/uv/issues/5335.
This commit is contained in:
Charlie Marsh 2024-07-23 17:48:50 -04:00 committed by GitHub
parent aced05d427
commit 76566b09be
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 80 additions and 2 deletions

View file

@ -2012,7 +2012,7 @@ pub struct AddArgs {
/// Add source requirements to the `project.dependencies` section of the `pyproject.toml`. /// Add source requirements to the `project.dependencies` section of the `pyproject.toml`.
/// ///
/// Without this flag uv will try to use `tool.uv.sources` for any sources. /// Without this flag, uv will try to use `tool.uv.sources` for any sources.
#[arg(long)] #[arg(long)]
pub raw_sources: bool, pub raw_sources: bool,

View file

@ -233,7 +233,7 @@ pub enum Source {
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum SourceError { pub enum SourceError {
#[error("Cannot resolve git reference `{0}`")] #[error("Failed to resolve Git reference: `{0}`")]
UnresolvedReference(String), UnresolvedReference(String),
#[error("Workspace dependency `{0}` must refer to local directory, not a Git repository")] #[error("Workspace dependency `{0}` must refer to local directory, not a Git repository")]
WorkspacePackageGit(String), WorkspacePackageGit(String),
@ -241,6 +241,12 @@ pub enum SourceError {
WorkspacePackageUrl(String), WorkspacePackageUrl(String),
#[error("Workspace dependency `{0}` must refer to local directory, not a file")] #[error("Workspace dependency `{0}` must refer to local directory, not a file")]
WorkspacePackageFile(String), WorkspacePackageFile(String),
#[error("`{0}` did not resolve to a Git repository, but a Git reference (`--rev {1}`) was provided.")]
UnusedRev(String, String),
#[error("`{0}` did not resolve to a Git repository, but a Git reference (`--tag {1}`) was provided.")]
UnusedTag(String, String),
#[error("`{0}` did not resolve to a Git repository, but a Git reference (`--branch {1}`) was provided.")]
UnusedBranch(String, String),
} }
impl Source { impl Source {
@ -253,6 +259,20 @@ impl Source {
tag: Option<String>, tag: Option<String>,
branch: Option<String>, branch: Option<String>,
) -> Result<Option<Source>, SourceError> { ) -> Result<Option<Source>, SourceError> {
// If we resolved to a non-Git source, and the user specified a Git reference, error.
if !matches!(source, RequirementSource::Git { .. }) {
if let Some(rev) = rev {
return Err(SourceError::UnusedRev(name.to_string(), rev));
}
if let Some(tag) = tag {
return Err(SourceError::UnusedTag(name.to_string(), tag));
}
if let Some(branch) = branch {
return Err(SourceError::UnusedBranch(name.to_string(), branch));
}
}
// If the source is a workspace package, error if the user tried to specify a source.
if workspace { if workspace {
return match source { return match source {
RequirementSource::Registry { .. } | RequirementSource::Directory { .. } => { RequirementSource::Registry { .. } | RequirementSource::Directory { .. } => {

View file

@ -285,6 +285,64 @@ fn add_git() -> Result<()> {
Ok(()) Ok(())
} }
#[test]
fn add_git_error() -> Result<()> {
let context = TestContext::new("3.12");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(indoc! {r#"
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
"#})?;
uv_snapshot!(context.filters(), context.lock(), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: `uv lock` is experimental and may change without warning
Resolved 1 package in [TIME]
"###);
uv_snapshot!(context.filters(), context.sync().arg("--frozen"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: `uv sync` is experimental and may change without warning
Prepared 1 package in [TIME]
Installed 1 package in [TIME]
+ project==0.1.0 (from file://[TEMP_DIR]/)
"###);
// Provide a tag without a Git source.
uv_snapshot!(context.filters(), context.add(&[]).arg("flask").arg("--tag").arg("0.0.1").arg("--preview"), @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: `flask` did not resolve to a Git repository, but a Git reference (`--tag 0.0.1`) was provided.
"###);
// Provide a tag with a non-Git source.
uv_snapshot!(context.filters(), context.add(&[]).arg("flask @ https://files.pythonhosted.org/packages/61/80/ffe1da13ad9300f87c93af113edd0638c75138c42a0994becfacac078c06/flask-3.0.3-py3-none-any.whl").arg("--branch").arg("0.0.1").arg("--preview"), @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: `flask` did not resolve to a Git repository, but a Git reference (`--branch 0.0.1`) was provided.
"###);
Ok(())
}
/// Add a Git requirement using the `--raw-sources` API. /// Add a Git requirement using the `--raw-sources` API.
#[test] #[test]
fn add_git_raw() -> Result<()> { fn add_git_raw() -> Result<()> {