Repository: taiki-e/cargo-hack (language: rust)

Issue:
Use rust syntax for version ranges
> Perform commands on a specified (inclusive) range of Rust versions.
> 
> ```console
> $ cargo hack check --version-range 1.46..1.47
> ```

Being used to rust, the use of an inclusive range for `..` seems odd rather than `..=`. 

Granted, this would be a breaking change.


Discussion / hints:
Indeed.

> Granted, this would be a breaking change.

I have no plans to support (half) exclusive range, so I think we can simply deprecate the current one and warn on it.

Fix patch:
diff --git a/README.md b/README.md
index 394dbb0d..97aa46c0 100644
--- a/README.md
+++ b/README.md
@@ -163,11 +163,14 @@ OPTIONS:
 
             This flag can only be used together with either --features or --include-features.
 
-        --version-range <START>..[END]
+        --version-range [START]..[=END]
             Perform commands on a specified (inclusive) range of Rust versions.
 
-            If the given range is unclosed, the latest stable compiler is treated as the upper
-            bound.
+            If the upper bound of the range is omitted, the latest stable compiler is used as the
+            upper bound.
+
+            If the lower bound of the range is omitted, the value of the `rust-version` field in
+            `Cargo.toml` is used as the lower bound.
 
             Note that ranges are always inclusive ranges.
 
@@ -307,7 +310,7 @@ To specify multiple groups, use this option multiple times:
 Perform commands on a specified (inclusive) range of Rust versions.
 
 ```console
-$ cargo hack check --version-range 1.46..1.47
+$ cargo hack check --version-range 1.46..=1.47
 info: running `cargo +1.46 check` on cargo-hack (1/2)
 ...
 info: running `cargo +1.47 check` on cargo-hack (2/2)
diff --git a/src/cli.rs b/src/cli.rs
index df8c8126..c334ee5c 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -731,11 +731,13 @@ const HELP: &[HelpText<'_>] = &[
     (
         "",
         "--version-range",
-        "<START>..[END]",
+        "[START]..[=END]",
         "Perform commands on a specified (inclusive) range of Rust versions",
         &[
-            "If the given range is unclosed, the latest stable compiler is treated as the upper \
-             bound.",
+            "If the upper bound of the range is omitted, the latest stable compiler is used as the \
+             upper bound.",
+            "If the lower bound of the range is omitted, the value of the `rust-version` field in \
+             `Cargo.toml` is used as the lower bound.",
             "Note that ranges are always inclusive ranges.",
         ],
     ),
diff --git a/src/rustup.rs b/src/rustup.rs
index b61d2577..284e4342 100644
--- a/src/rustup.rs
+++ b/src/rustup.rs
@@ -66,6 +66,16 @@ pub(crate) fn version_range(
             cargo::minor_version(cmd!("cargo", "+stable"))?
         }
         Some(end) => {
+            let end = match end.strip_prefix('=') {
+                Some(end) => end,
+                None => {
+                    warn!(
+                        "using `..` for inclusive range is deprecated; consider using `{}`",
+                        range.replace("..", "..=")
+                    );
+                    end
+                }
+            };
             let end = end.parse()?;
             check(&end)?;
             end.minor


Test patch:
diff --git a/tests/auxiliary/mod.rs b/tests/auxiliary/mod.rs
index db303adb..14ef8373 100644
--- a/tests/auxiliary/mod.rs
+++ b/tests/auxiliary/mod.rs
@@ -62,7 +62,7 @@ pub fn cargo_hack<O: AsRef<OsStr>>(args: impl AsRef<[O]>) -> Command {
     cmd.arg("hack");
     if let Some(toolchain) = test_version() {
         if !args.iter().any(|a| a.as_ref().to_str().unwrap().starts_with("--version-range")) {
-            cmd.arg(format!("--version-range=1.{toolchain}..1.{toolchain}"));
+            cmd.arg(format!("--version-range=1.{toolchain}..=1.{toolchain}"));
         }
     }
     cmd.args(args);
diff --git a/tests/long-help.txt b/tests/long-help.txt
index a1a0015f..1367690b 100644
--- a/tests/long-help.txt
+++ b/tests/long-help.txt
@@ -134,11 +134,14 @@ OPTIONS:
 
             This flag can only be used together with either --features or --include-features.
 
-        --version-range <START>..[END]
+        --version-range [START]..[=END]
             Perform commands on a specified (inclusive) range of Rust versions.
 
-            If the given range is unclosed, the latest stable compiler is treated as the upper
-            bound.
+            If the upper bound of the range is omitted, the latest stable compiler is used as the
+            upper bound.
+
+            If the lower bound of the range is omitted, the value of the `rust-version` field in
+            `Cargo.toml` is used as the lower bound.
 
             Note that ranges are always inclusive ranges.
 
diff --git a/tests/short-help.txt b/tests/short-help.txt
index 2c5ba961..d8279321 100644
--- a/tests/short-help.txt
+++ b/tests/short-help.txt
@@ -34,7 +34,7 @@ OPTIONS:
         --ignore-private                 Skip to perform on `publish = false` packages
         --ignore-unknown-features        Skip passing --features flag to `cargo` if that feature
                                          does not exist in the package
-        --version-range <START>..[END]   Perform commands on a specified (inclusive) range of Rust
+        --version-range [START]..[=END]  Perform commands on a specified (inclusive) range of Rust
                                          versions
         --version-step <NUM>             Specify the version interval of --version-range (default
                                          to `1`)
diff --git a/tests/test.rs b/tests/test.rs
index 74bf4cd3..acbe3e4b 100644
--- a/tests/test.rs
+++ b/tests/test.rs
@@ -1318,14 +1318,24 @@ fn default_feature_behavior() {
 #[cfg_attr(windows, ignore)] // rustup bug: https://github.com/rust-lang/rustup/issues/3036
 #[test]
 fn version_range() {
-    cargo_hack(["check", "--version-range", "1.63..1.64"]).assert_success("real").stderr_contains(
+    cargo_hack(["check", "--version-range", "1.63..=1.64"]).assert_success("real").stderr_contains(
         "
         running `cargo +1.63 check` on real (1/2)
         running `cargo +1.64 check` on real (2/2)
         ",
     );
 
-    cargo_hack(["check", "--version-range", "1.63..1.64", "--target", TARGET])
+    cargo_hack(["check", "--version-range", "1.63..1.64"])
+        .assert_failure("real") // warn
+        .stderr_contains(
+            "
+            warning: using `..` for inclusive range is deprecated; consider using `1.63..=1.64`
+            running `cargo +1.63 check` on real (1/2)
+            running `cargo +1.64 check` on real (2/2)
+            ",
+        );
+
+    cargo_hack(["check", "--version-range", "1.63..=1.64", "--target", TARGET])
         .assert_success("real")
         .stderr_contains(format!(
             "
@@ -1349,7 +1359,7 @@ fn multi_target() {
     cargo_hack([
         "check",
         "--version-range",
-        "1.63..1.64",
+        "1.63..=1.64",
         "--target",
         &format!("aarch64{target_suffix}"),
     ])
@@ -1364,7 +1374,7 @@ fn multi_target() {
     cargo_hack([
         "check",
         "--version-range",
-        "1.63..1.64",
+        "1.63..=1.64",
         "--target",
         &format!("x86_64{target_suffix}"),
         "--target",
@@ -1382,7 +1392,7 @@ fn multi_target() {
     cargo_hack([
         "check",
         "--version-range",
-        "1.63..1.64",
+        "1.63..=1.64",
         "--target",
         &format!("x86_64{target_suffix}"),
         "--target",
@@ -1409,6 +1419,9 @@ fn version_range_failure() {
     cargo_hack(["check", "--version-range", "1.45..1.44"])
         .assert_failure("real")
         .stderr_contains("specified version range `1.45..1.44` is empty");
+    cargo_hack(["check", "--version-range", "1.45..=1.44"])
+        .assert_failure("real")
+        .stderr_contains("specified version range `1.45..=1.44` is empty");
 
     // v0
     cargo_hack(["check", "--version-range", "0.45.."])