diff --git a/src/cargo/ops/cargo_add/crate_spec.rs b/src/cargo/ops/cargo_add/crate_spec.rs index d7aeddd0615..00d106f1f18 100644 --- a/src/cargo/ops/cargo_add/crate_spec.rs +++ b/src/cargo/ops/cargo_add/crate_spec.rs @@ -7,6 +7,24 @@ use crate::CargoResult; use crate::util::toml_mut::dependency::RegistrySource; use cargo_util_schemas::manifest::PackageName; +/// A user-provided version selector from `@`. +#[derive(Debug)] +pub(super) enum VersionSpec { + /// A semver requirement that can be written to the manifest. + Requirement(String), + /// The special `@latest` selector, used for diagnostics only. + Latest, +} + +impl std::fmt::Display for VersionSpec { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Requirement(req) => req.fmt(f), + Self::Latest => "latest".fmt(f), + } + } +} + /// User-specified crate /// /// This can be a @@ -16,8 +34,8 @@ use cargo_util_schemas::manifest::PackageName; pub struct CrateSpec { /// Crate name name: String, - /// Optional version requirement - version_req: Option, + /// Optional version selector + version: Option, } impl CrateSpec { @@ -46,22 +64,34 @@ impl CrateSpec { package_name?; - if let Some(version) = version { - semver::VersionReq::parse(version).with_context(|| { - if let Some(stripped) = version.strip_prefix("v") { - return format!( - "the version provided, `{version}` is not a \ - valid SemVer requirement\n\n\ - help: changing the package to `{name}@{stripped}`", - ); - } - format!("invalid version requirement `{version}`") - })?; - } + let version = if let Some(version) = version { + // `latest` is the only supported special version selector. It is + // not a SemVer requirement. + // + // We intentionally keep it case-sensitive to match other package + // managers we may be helping users transition from. + if version == "latest" { + Some(VersionSpec::Latest) + } else { + semver::VersionReq::parse(version).with_context(|| { + if let Some(stripped) = version.strip_prefix("v") { + return format!( + "the version provided, `{version}` is not a \ + valid SemVer requirement\n\n\ + help: changing the package to `{name}@{stripped}`", + ); + } + format!("invalid version requirement `{version}`") + })?; + Some(VersionSpec::Requirement(version.to_owned())) + } + } else { + None + }; let id = Self { name: name.to_owned(), - version_req: version.map(|s| s.to_owned()), + version, }; Ok(id) @@ -70,8 +100,14 @@ impl CrateSpec { /// Generate a dependency entry for this crate specifier pub fn to_dependency(&self) -> CargoResult { let mut dep = Dependency::new(self.name()); - if let Some(version_req) = self.version_req() { - dep = dep.set_source(RegistrySource::new(version_req)); + match self.version.as_ref() { + Some(VersionSpec::Latest) => { + anyhow::bail!("`latest` is not a valid dependency requirement") + } + Some(VersionSpec::Requirement(req)) => { + dep = dep.set_source(RegistrySource::new(req)); + } + None => {} } Ok(dep) } @@ -80,7 +116,7 @@ impl CrateSpec { &self.name } - pub fn version_req(&self) -> Option<&str> { - self.version_req.as_deref() + pub(crate) fn version(&self) -> Option<&VersionSpec> { + self.version.as_ref() } } diff --git a/src/cargo/ops/cargo_add/mod.rs b/src/cargo/ops/cargo_add/mod.rs index 929d704c677..a3f5b7989c2 100644 --- a/src/cargo/ops/cargo_add/mod.rs +++ b/src/cargo/ops/cargo_add/mod.rs @@ -47,6 +47,7 @@ use crate::util::toml_mut::dependency::WorkspaceSource; use crate::util::toml_mut::manifest::DepTable; use crate::util::toml_mut::manifest::LocalManifest; use crate_spec::CrateSpec; +use crate_spec::VersionSpec; const MAX_FEATURE_PRINTS: usize = 30; @@ -349,6 +350,10 @@ fn resolve_dependency( .as_deref() .map(CrateSpec::resolve) .transpose()?; + let request_latest = crate_spec + .as_ref() + .is_some_and(|crate_spec| matches!(crate_spec.version(), Some(VersionSpec::Latest))); + let mut selected_dep = if let Some(url) = &arg.git { let mut src = GitSource::new(url); if let Some(branch) = &arg.branch { @@ -362,9 +367,9 @@ fn resolve_dependency( } let selected = if let Some(crate_spec) = &crate_spec { - if let Some(v) = crate_spec.version_req() { + if let Some(version) = crate_spec.version() { // crate specifier includes a version (e.g. `docopt@0.8`) - anyhow::bail!("cannot specify a git URL (`{url}`) with a version (`{v}`)."); + anyhow::bail!("cannot specify a git URL (`{url}`) with a version (`{version}`)."); } let dependency = crate_spec.to_dependency()?.set_source(src); let selected = select_package(&dependency, gctx, registry)?; @@ -399,9 +404,9 @@ fn resolve_dependency( } let selected = if let Some(crate_spec) = &crate_spec { - if let Some(v) = crate_spec.version_req() { + if let Some(version) = crate_spec.version() { // crate specifier includes a version (e.g. `docopt@0.8`) - anyhow::bail!("cannot specify a path (`{raw_path}`) with a version (`{v}`)."); + anyhow::bail!("cannot specify a path (`{raw_path}`) with a version (`{version}`)."); } let dependency = crate_spec.to_dependency()?.set_source(src); let selected = select_package(&dependency, gctx, registry)?; @@ -423,7 +428,14 @@ fn resolve_dependency( }; selected } else if let Some(crate_spec) = &crate_spec { - crate_spec.to_dependency()? + if request_latest { + // `latest` is not a dependency requirement we can write to the manifest. + // Build an unconstrained dependency and let the dedicated diagnostics below + // explain what the user should do instead. + Dependency::new(crate_spec.name()) + } else { + crate_spec.to_dependency()? + } } else { anyhow::bail!("dependency name is required"); }; @@ -513,6 +525,49 @@ fn resolve_dependency( dependency = dependency.clear_version(); } + // Check if user tried to use @latest and provide helpful error. + if request_latest { + // The diagnostics below compare against the resolved and latest published registry + // versions, so they only apply to registry dependencies. + if !matches!(dependency.source(), Some(Source::Registry(_))) { + anyhow::bail!("invalid version requirement `latest`"); + } + + // Get the exact version that `cargo add ` would resolve to, + // respecting MSRV and existing version constraints. + let resolved = + get_latest_dependency(spec, &dependency, honor_rust_version, gctx, registry)?; + let resolved_version = resolved + .version() + .expect("resolved dependency should have version"); + // Get the actual latest non-prerelease, non-yanked version from the registry, + // ignoring MSRV and existing version constraints. + // Only name + registry matter; `Dependency::query` ignores other fields. + let mut unconstrained_dep = Dependency::new(&dependency.name); + if let Some(registry_name) = dependency.registry() { + unconstrained_dep = unconstrained_dep.set_registry(registry_name); + } + let latest = get_latest_dependency(spec, &unconstrained_dep, Some(false), gctx, registry)?; + let latest_version = latest + .version() + .expect("latest dependency should have version"); + if resolved_version == latest_version { + anyhow::bail!( + "invalid version requirement `latest`\n\n\ + help: to add the latest version `{latest_version}`, run `cargo add {}`", + dependency.name, + ); + } else { + anyhow::bail!( + "invalid version requirement `latest`\n\n\ + help: to use `{resolved_version}`, run `cargo add {}`\n\ + help: to use the latest version, run `cargo add {}@{latest_version}`", + dependency.name, + dependency.name, + ); + } + } + let query = query_dependency(ws, gctx, &mut dependency)?; let dependency = populate_available_features(dependency, &query, registry)?; diff --git a/tests/testsuite/cargo_add/add_latest/in/Cargo.toml b/tests/testsuite/cargo_add/add_latest/in/Cargo.toml new file mode 100644 index 00000000000..db55ed24962 --- /dev/null +++ b/tests/testsuite/cargo_add/add_latest/in/Cargo.toml @@ -0,0 +1,9 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +edition = "2015" + +[dependencies] +my-package = "0.4" diff --git a/tests/testsuite/cargo_add/add_latest/in/src/lib.rs b/tests/testsuite/cargo_add/add_latest/in/src/lib.rs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/testsuite/cargo_add/add_latest/mod.rs b/tests/testsuite/cargo_add/add_latest/mod.rs new file mode 100644 index 00000000000..a789fce72a1 --- /dev/null +++ b/tests/testsuite/cargo_add/add_latest/mod.rs @@ -0,0 +1,38 @@ +use crate::prelude::*; +use cargo_test_support::Project; +use cargo_test_support::compare::assert_ui; +use cargo_test_support::current_dir; +use cargo_test_support::file; +use cargo_test_support::str; + +#[cargo_test] +fn case() { + cargo_test_support::registry::init(); + for ver in [ + "0.1.1+my-package", + "0.2.0+my-package", + "0.2.3+my-package", + "0.4.1+my-package", + "0.4.2+my-package", + "20.0.0+my-package", + "99999.0.0+my-package", + "99999.0.0-alpha.1+my-package", + ] { + cargo_test_support::registry::Package::new("my-package", ver).publish(); + } + + let project = Project::from_template(current_dir!().join("in")); + let project_root = project.root(); + let cwd = &project_root; + + snapbox::cmd::Command::cargo_ui() + .arg("add") + .arg_line("my-package@latest") + .current_dir(cwd) + .assert() + .failure() + .stdout_eq(str![""]) + .stderr_eq(file!["stderr.term.svg"]); + + assert_ui().subset_matches(current_dir!().join("out"), &project_root); +} diff --git a/tests/testsuite/cargo_add/add_latest/out/Cargo.toml b/tests/testsuite/cargo_add/add_latest/out/Cargo.toml new file mode 100644 index 00000000000..db55ed24962 --- /dev/null +++ b/tests/testsuite/cargo_add/add_latest/out/Cargo.toml @@ -0,0 +1,9 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +edition = "2015" + +[dependencies] +my-package = "0.4" diff --git a/tests/testsuite/cargo_add/add_latest/stderr.term.svg b/tests/testsuite/cargo_add/add_latest/stderr.term.svg new file mode 100644 index 00000000000..c5d8b666d80 --- /dev/null +++ b/tests/testsuite/cargo_add/add_latest/stderr.term.svg @@ -0,0 +1,36 @@ + + + + + + + Updating `dummy-registry` index + + error: invalid version requirement `latest` + + + + help: to use `0.4.2`, run `cargo add my-package` + + help: to use the latest version, run `cargo add my-package@99999.0.0` + + + + + + diff --git a/tests/testsuite/cargo_add/add_latest_alt_registry/in/Cargo.toml b/tests/testsuite/cargo_add/add_latest_alt_registry/in/Cargo.toml new file mode 100644 index 00000000000..946b7c86bf0 --- /dev/null +++ b/tests/testsuite/cargo_add/add_latest_alt_registry/in/Cargo.toml @@ -0,0 +1,6 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +edition = "2015" diff --git a/tests/testsuite/cargo_add/add_latest_alt_registry/in/src/lib.rs b/tests/testsuite/cargo_add/add_latest_alt_registry/in/src/lib.rs new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/tests/testsuite/cargo_add/add_latest_alt_registry/in/src/lib.rs @@ -0,0 +1 @@ + diff --git a/tests/testsuite/cargo_add/add_latest_alt_registry/mod.rs b/tests/testsuite/cargo_add/add_latest_alt_registry/mod.rs new file mode 100644 index 00000000000..b360d5f73ab --- /dev/null +++ b/tests/testsuite/cargo_add/add_latest_alt_registry/mod.rs @@ -0,0 +1,40 @@ +use crate::prelude::*; +use cargo_test_support::Project; +use cargo_test_support::compare::assert_ui; +use cargo_test_support::current_dir; +use cargo_test_support::file; +use cargo_test_support::str; + +#[cargo_test] +fn case() { + cargo_test_support::registry::alt_init(); + for ver in [ + "0.1.1+my-package", + "0.2.0+my-package", + "0.2.3+my-package", + "0.4.1+my-package", + "0.4.2+my-package", + "20.0.0+my-package", + "99999.0.0+my-package", + "99999.0.0-alpha.1+my-package", + ] { + cargo_test_support::registry::Package::new("my-package", ver) + .alternative(true) + .publish(); + } + + let project = Project::from_template(current_dir!().join("in")); + let project_root = project.root(); + let cwd = &project_root; + + snapbox::cmd::Command::cargo_ui() + .arg("add") + .arg_line("my-package@latest --registry alternative") + .current_dir(cwd) + .assert() + .failure() + .stdout_eq(str![""]) + .stderr_eq(file!["stderr.term.svg"]); + + assert_ui().subset_matches(current_dir!().join("out"), &project_root); +} diff --git a/tests/testsuite/cargo_add/add_latest_alt_registry/out/Cargo.toml b/tests/testsuite/cargo_add/add_latest_alt_registry/out/Cargo.toml new file mode 100644 index 00000000000..946b7c86bf0 --- /dev/null +++ b/tests/testsuite/cargo_add/add_latest_alt_registry/out/Cargo.toml @@ -0,0 +1,6 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +edition = "2015" diff --git a/tests/testsuite/cargo_add/add_latest_alt_registry/stderr.term.svg b/tests/testsuite/cargo_add/add_latest_alt_registry/stderr.term.svg new file mode 100644 index 00000000000..9512e12cca6 --- /dev/null +++ b/tests/testsuite/cargo_add/add_latest_alt_registry/stderr.term.svg @@ -0,0 +1,34 @@ + + + + + + + Updating `alternative` index + + error: invalid version requirement `latest` + + + + help: to add the latest version `99999.0.0`, run `cargo add my-package` + + + + + + diff --git a/tests/testsuite/cargo_add/add_latest_no_existing/in/Cargo.toml b/tests/testsuite/cargo_add/add_latest_no_existing/in/Cargo.toml new file mode 100644 index 00000000000..946b7c86bf0 --- /dev/null +++ b/tests/testsuite/cargo_add/add_latest_no_existing/in/Cargo.toml @@ -0,0 +1,6 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +edition = "2015" diff --git a/tests/testsuite/cargo_add/add_latest_no_existing/in/src/lib.rs b/tests/testsuite/cargo_add/add_latest_no_existing/in/src/lib.rs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/testsuite/cargo_add/add_latest_no_existing/mod.rs b/tests/testsuite/cargo_add/add_latest_no_existing/mod.rs new file mode 100644 index 00000000000..a789fce72a1 --- /dev/null +++ b/tests/testsuite/cargo_add/add_latest_no_existing/mod.rs @@ -0,0 +1,38 @@ +use crate::prelude::*; +use cargo_test_support::Project; +use cargo_test_support::compare::assert_ui; +use cargo_test_support::current_dir; +use cargo_test_support::file; +use cargo_test_support::str; + +#[cargo_test] +fn case() { + cargo_test_support::registry::init(); + for ver in [ + "0.1.1+my-package", + "0.2.0+my-package", + "0.2.3+my-package", + "0.4.1+my-package", + "0.4.2+my-package", + "20.0.0+my-package", + "99999.0.0+my-package", + "99999.0.0-alpha.1+my-package", + ] { + cargo_test_support::registry::Package::new("my-package", ver).publish(); + } + + let project = Project::from_template(current_dir!().join("in")); + let project_root = project.root(); + let cwd = &project_root; + + snapbox::cmd::Command::cargo_ui() + .arg("add") + .arg_line("my-package@latest") + .current_dir(cwd) + .assert() + .failure() + .stdout_eq(str![""]) + .stderr_eq(file!["stderr.term.svg"]); + + assert_ui().subset_matches(current_dir!().join("out"), &project_root); +} diff --git a/tests/testsuite/cargo_add/add_latest_no_existing/out/Cargo.toml b/tests/testsuite/cargo_add/add_latest_no_existing/out/Cargo.toml new file mode 100644 index 00000000000..946b7c86bf0 --- /dev/null +++ b/tests/testsuite/cargo_add/add_latest_no_existing/out/Cargo.toml @@ -0,0 +1,6 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +edition = "2015" diff --git a/tests/testsuite/cargo_add/add_latest_no_existing/stderr.term.svg b/tests/testsuite/cargo_add/add_latest_no_existing/stderr.term.svg new file mode 100644 index 00000000000..25c84b79848 --- /dev/null +++ b/tests/testsuite/cargo_add/add_latest_no_existing/stderr.term.svg @@ -0,0 +1,34 @@ + + + + + + + Updating `dummy-registry` index + + error: invalid version requirement `latest` + + + + help: to add the latest version `99999.0.0`, run `cargo add my-package` + + + + + + diff --git a/tests/testsuite/cargo_add/add_latest_rust_version/in/Cargo.toml b/tests/testsuite/cargo_add/add_latest_rust_version/in/Cargo.toml new file mode 100644 index 00000000000..644f41d9f6c --- /dev/null +++ b/tests/testsuite/cargo_add/add_latest_rust_version/in/Cargo.toml @@ -0,0 +1,7 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +edition = "2015" +rust-version = "1.70" diff --git a/tests/testsuite/cargo_add/add_latest_rust_version/in/src/lib.rs b/tests/testsuite/cargo_add/add_latest_rust_version/in/src/lib.rs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/testsuite/cargo_add/add_latest_rust_version/mod.rs b/tests/testsuite/cargo_add/add_latest_rust_version/mod.rs new file mode 100644 index 00000000000..99d2f7e8d6d --- /dev/null +++ b/tests/testsuite/cargo_add/add_latest_rust_version/mod.rs @@ -0,0 +1,32 @@ +use crate::prelude::*; +use cargo_test_support::Project; +use cargo_test_support::compare::assert_ui; +use cargo_test_support::current_dir; +use cargo_test_support::file; +use cargo_test_support::str; + +#[cargo_test] +fn case() { + cargo_test_support::registry::init(); + cargo_test_support::registry::Package::new("rust-version-user", "0.1.0") + .rust_version("1.66") + .publish(); + cargo_test_support::registry::Package::new("rust-version-user", "0.2.1") + .rust_version("1.72") + .publish(); + + let project = Project::from_template(current_dir!().join("in")); + let project_root = project.root(); + let cwd = &project_root; + + snapbox::cmd::Command::cargo_ui() + .arg("add") + .arg_line("rust-version-user@latest") + .current_dir(cwd) + .assert() + .failure() + .stdout_eq(str![""]) + .stderr_eq(file!["stderr.term.svg"]); + + assert_ui().subset_matches(current_dir!().join("out"), &project_root); +} diff --git a/tests/testsuite/cargo_add/add_latest_rust_version/out/Cargo.toml b/tests/testsuite/cargo_add/add_latest_rust_version/out/Cargo.toml new file mode 100644 index 00000000000..644f41d9f6c --- /dev/null +++ b/tests/testsuite/cargo_add/add_latest_rust_version/out/Cargo.toml @@ -0,0 +1,7 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +edition = "2015" +rust-version = "1.70" diff --git a/tests/testsuite/cargo_add/add_latest_rust_version/stderr.term.svg b/tests/testsuite/cargo_add/add_latest_rust_version/stderr.term.svg new file mode 100644 index 00000000000..1dbe2e25ca7 --- /dev/null +++ b/tests/testsuite/cargo_add/add_latest_rust_version/stderr.term.svg @@ -0,0 +1,39 @@ + + + + + + + Updating `dummy-registry` index + + warning: ignoring rust-version-user@0.2.1 (which requires rustc 1.72) to maintain cargo-list-test-fixture's rust-version of 1.70 + + error: invalid version requirement `latest` + + + + help: to use `0.1.0`, run `cargo add rust-version-user` + + help: to use the latest version, run `cargo add rust-version-user@0.2.1` + + + + + + diff --git a/tests/testsuite/cargo_add/add_latest_workspace/in/Cargo.toml b/tests/testsuite/cargo_add/add_latest_workspace/in/Cargo.toml new file mode 100644 index 00000000000..b3beb88fba7 --- /dev/null +++ b/tests/testsuite/cargo_add/add_latest_workspace/in/Cargo.toml @@ -0,0 +1,5 @@ +[workspace] +members = ["bar"] + +[workspace.dependencies] +my-package = "0.4" diff --git a/tests/testsuite/cargo_add/add_latest_workspace/in/bar/Cargo.toml b/tests/testsuite/cargo_add/add_latest_workspace/in/bar/Cargo.toml new file mode 100644 index 00000000000..fb520246281 --- /dev/null +++ b/tests/testsuite/cargo_add/add_latest_workspace/in/bar/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "bar" +version = "0.0.0" +edition = "2015" diff --git a/tests/testsuite/cargo_add/add_latest_workspace/in/bar/src/lib.rs b/tests/testsuite/cargo_add/add_latest_workspace/in/bar/src/lib.rs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/testsuite/cargo_add/add_latest_workspace/mod.rs b/tests/testsuite/cargo_add/add_latest_workspace/mod.rs new file mode 100644 index 00000000000..bc88128519d --- /dev/null +++ b/tests/testsuite/cargo_add/add_latest_workspace/mod.rs @@ -0,0 +1,38 @@ +use crate::prelude::*; +use cargo_test_support::Project; +use cargo_test_support::compare::assert_ui; +use cargo_test_support::current_dir; +use cargo_test_support::file; +use cargo_test_support::str; + +#[cargo_test] +fn case() { + cargo_test_support::registry::init(); + for ver in [ + "0.1.1+my-package", + "0.2.0+my-package", + "0.2.3+my-package", + "0.4.1+my-package", + "0.4.2+my-package", + "20.0.0+my-package", + "99999.0.0+my-package", + "99999.0.0-alpha.1+my-package", + ] { + cargo_test_support::registry::Package::new("my-package", ver).publish(); + } + + let project = Project::from_template(current_dir!().join("in")); + let project_root = project.root(); + let cwd = &project_root; + + snapbox::cmd::Command::cargo_ui() + .arg("add") + .arg_line("my-package@latest -p bar") + .current_dir(cwd) + .assert() + .failure() + .stdout_eq(str![""]) + .stderr_eq(file!["stderr.term.svg"]); + + assert_ui().subset_matches(current_dir!().join("out"), &project_root); +} diff --git a/tests/testsuite/cargo_add/add_latest_workspace/out/Cargo.toml b/tests/testsuite/cargo_add/add_latest_workspace/out/Cargo.toml new file mode 100644 index 00000000000..b3beb88fba7 --- /dev/null +++ b/tests/testsuite/cargo_add/add_latest_workspace/out/Cargo.toml @@ -0,0 +1,5 @@ +[workspace] +members = ["bar"] + +[workspace.dependencies] +my-package = "0.4" diff --git a/tests/testsuite/cargo_add/add_latest_workspace/out/bar/Cargo.toml b/tests/testsuite/cargo_add/add_latest_workspace/out/bar/Cargo.toml new file mode 100644 index 00000000000..fb520246281 --- /dev/null +++ b/tests/testsuite/cargo_add/add_latest_workspace/out/bar/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "bar" +version = "0.0.0" +edition = "2015" diff --git a/tests/testsuite/cargo_add/add_latest_workspace/out/bar/src/lib.rs b/tests/testsuite/cargo_add/add_latest_workspace/out/bar/src/lib.rs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/testsuite/cargo_add/add_latest_workspace/stderr.term.svg b/tests/testsuite/cargo_add/add_latest_workspace/stderr.term.svg new file mode 100644 index 00000000000..e8883cd1ce7 --- /dev/null +++ b/tests/testsuite/cargo_add/add_latest_workspace/stderr.term.svg @@ -0,0 +1,27 @@ + + + + + + + error: invalid version requirement `latest` + + + + + + diff --git a/tests/testsuite/cargo_add/git_conflicts_namever/mod.rs b/tests/testsuite/cargo_add/git_conflicts_namever/mod.rs index bf1cd694983..64e0d84ac3e 100644 --- a/tests/testsuite/cargo_add/git_conflicts_namever/mod.rs +++ b/tests/testsuite/cargo_add/git_conflicts_namever/mod.rs @@ -39,3 +39,25 @@ fn case() { assert_ui().subset_matches(current_dir!().join("out"), &project_root); } + +#[cargo_test] +fn latest() { + let project = Project::from_template(current_dir!().join("in")); + let project_root = project.root(); + let cwd = &project_root; + + snapbox::cmd::Command::cargo_ui() + .arg("add") + .args([ + "my-package@latest", + "--git", + "https://github.com/dcjanus/invalid", + ]) + .current_dir(cwd) + .assert() + .code(101) + .stdout_eq(str![""]) + .stderr_eq(file!["stderr_latest.term.svg"]); + + assert_ui().subset_matches(current_dir!().join("out"), &project_root); +} diff --git a/tests/testsuite/cargo_add/git_conflicts_namever/stderr_latest.term.svg b/tests/testsuite/cargo_add/git_conflicts_namever/stderr_latest.term.svg new file mode 100644 index 00000000000..897f646be86 --- /dev/null +++ b/tests/testsuite/cargo_add/git_conflicts_namever/stderr_latest.term.svg @@ -0,0 +1,27 @@ + + + + + + + error: cannot specify a git URL (`https://github.com/dcjanus/invalid`) with a version (`latest`). + + + + + + diff --git a/tests/testsuite/cargo_add/mod.rs b/tests/testsuite/cargo_add/mod.rs index bd9024466ac..bab857cd40b 100644 --- a/tests/testsuite/cargo_add/mod.rs +++ b/tests/testsuite/cargo_add/mod.rs @@ -1,4 +1,9 @@ mod add_basic; +mod add_latest; +mod add_latest_alt_registry; +mod add_latest_no_existing; +mod add_latest_rust_version; +mod add_latest_workspace; mod add_multiple; mod add_no_vendored_package_with_alter_registry; mod add_no_vendored_package_with_vendor;