commit 8e3e5829b00974dd113cc245d0c297ee6f108b5e
parent 7d3a9f3b8de69683b9cfc0a3dc86ce0d574bdf69
Author: Zack Newman <zack@philomathiclife.com>
Date: Mon, 19 May 2025 10:42:01 -0600
add ignore tests
Diffstat:
M | Cargo.toml | | | 47 | ++++++++++++++++++++++++++++++++++++++++++++++- |
M | README.md | | | 8 | +++++--- |
M | src/args.rs | | | 98 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------ |
M | src/main.rs | | | 47 | +++++------------------------------------------ |
4 files changed, 139 insertions(+), 61 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
@@ -10,7 +10,52 @@ name = "ci"
readme = "README.md"
repository = "https://git.philomathiclife.com/repos/ci/"
rust-version = "1.86.0"
-version = "0.2.3"
+version = "0.3.0"
+
+[lints.rust]
+unknown_lints = { level = "deny", priority = -1 }
+future_incompatible = { level = "deny", priority = -1 }
+let_underscore = { level = "deny", priority = -1 }
+missing_docs = { level = "deny", priority = -1 }
+nonstandard_style = { level = "deny", priority = -1 }
+refining_impl_trait = { level = "deny", priority = -1 }
+rust_2018_compatibility = { level = "deny", priority = -1 }
+rust_2018_idioms = { level = "deny", priority = -1 }
+rust_2021_compatibility = { level = "deny", priority = -1 }
+rust_2024_compatibility = { level = "deny", priority = -1 }
+unsafe_code = { level = "deny", priority = -1 }
+unused = { level = "deny", priority = -1 }
+warnings = { level = "deny", priority = -1 }
+
+[lints.clippy]
+all = { level = "deny", priority = -1 }
+cargo = { level = "deny", priority = -1 }
+complexity = { level = "deny", priority = -1 }
+correctness = { level = "deny", priority = -1 }
+nursery = { level = "deny", priority = -1 }
+pedantic = { level = "deny", priority = -1 }
+perf = { level = "deny", priority = -1 }
+restriction = { level = "deny", priority = -1 }
+style = { level = "deny", priority = -1 }
+suspicious = { level = "deny", priority = -1 }
+# Noisy, opinionated, and likely don't prevent bugs or improve APIs.
+arbitrary_source_item_ordering = "allow"
+blanket_clippy_restriction_lints = "allow"
+exhaustive_enums = "allow"
+exhaustive_structs = "allow"
+implicit_return = "allow"
+min_ident_chars = "allow"
+missing_trait_methods = "allow"
+multiple_crate_versions = "allow"
+pub_with_shorthand = "allow"
+pub_use = "allow"
+question_mark_used = "allow"
+ref_patterns = "allow"
+return_and_then = "allow"
+self_named_module_files = "allow"
+single_call_fn = "allow"
+single_char_lifetime_names = "allow"
+unseparated_literal_suffix = "allow"
[dependencies]
serde = { version = "1.0.219", default-features = false }
diff --git a/README.md b/README.md
@@ -23,18 +23,20 @@ invoking `cargo` with each possible combination of features, this handles it aut
* `clippy`: `cargo clippy -q` is invoked for each combination of features.
* `doc_tests`: `cargo t -q --doc` is invoked for each combination of features.
* `tests`: `cargo t -q --tests` is invoked for each combination of features.
+* `ignored`: `cargo t -q --tests -- --ignored` is invoked for each combination of features.
+* `include-ignored`: `cargo t -q --tests -- --include-ignored` is invoked for each combination of features.
* `--color`: `--color always` is passed to the above commands; otherwise without this option, `--color never` is
passed.
* `--dir <path to directory Cargo.toml is in>`: `ci` changes the working directory to the passed path (after
canonicalizing it) before executing. Without this, the working directory and all ancestor directories are searched
for `Cargo.toml` before changing the working directory to its location.
-When `clippy`, `doc_tests`, and `tests` are not passed; then all three are invoked.
+When `clippy`, `doc_tests`, `tests`, `ignored`, and `include-ignored` are not passed; then `clippy`, `doc_tests`,
+and `tests` are all invoked.
## Limitations
-Any use of `compile_error` _not_ related to incompatible features will be silently ignored. Any tests that
-are marked `ignored` will not be run.
+Any use of `compile_error` _not_ related to incompatible features will be silently ignored.
## Minimum Supported Rust Version (MSRV)
diff --git a/src/args.rs b/src/args.rs
@@ -30,7 +30,7 @@ impl Display for ArgsErr {
),
Self::InvalidOption(ref arg) => write!(
f,
- "{arg} is an invalid option. No arguments or exactly one of 'clippy', 'doc_tests', or 'tests' is allowed followed by nothing, '--color', or '--dir' and the path to the directory ci should run in"
+ "{arg} is an invalid option. No arguments or exactly one of 'clippy', 'doc_tests', 'tests', 'ignored', or 'include-ignored' is allowed followed by nothing, '--color', or '--dir' and the path to the directory ci should run in"
),
Self::DuplicateOption(ref arg) => write!(f, "{arg} was passed more than once"),
Self::MissingPath => {
@@ -60,6 +60,14 @@ pub enum Opts {
///
/// The contained `bool` is `true` iff `--color always` should be used; otherwise `--color never` is used.
Tests(bool),
+ /// Variant when `ignored` is passed.
+ ///
+ /// The contained `bool` is `true` iff `--color always` should be used; otherwise `--color never` is used.
+ IgnoredTests(bool),
+ /// Variant when `include-ignored` is passed.
+ ///
+ /// The contained `bool` is `true` iff `--color always` should be used; otherwise `--color never` is used.
+ IncludeIgnoredTests(bool),
}
/// Kind of successful completion of a command.
pub enum Success {
@@ -77,7 +85,9 @@ impl Opts {
Self::None(color, _)
| Self::Clippy(color)
| Self::DocTests(color)
- | Self::Tests(color) => color,
+ | Self::Tests(color)
+ | Self::IgnoredTests(color)
+ | Self::IncludeIgnoredTests(color) => color,
}
}
/// Changes `self` such that it should contain color.
@@ -86,7 +96,9 @@ impl Opts {
Self::None(ref mut color, _)
| Self::Clippy(ref mut color)
| Self::DocTests(ref mut color)
- | Self::Tests(ref mut color) => *color = true,
+ | Self::Tests(ref mut color)
+ | Self::IgnoredTests(ref mut color)
+ | Self::IncludeIgnoredTests(ref mut color) => *color = true,
}
}
/// Returns the arguments to pass to the command based on `self`.
@@ -108,21 +120,26 @@ impl Opts {
"--doc",
"--no-default-features",
],
- Self::Tests(color) => vec![
- "t",
- "-q",
- "--color",
- if color { "always" } else { "never" },
- "--tests",
- "--no-default-features",
- ],
+ Self::Tests(color) | Self::IgnoredTests(color) | Self::IncludeIgnoredTests(color) => {
+ vec![
+ "t",
+ "-q",
+ "--color",
+ if color { "always" } else { "never" },
+ "--tests",
+ "--no-default-features",
+ ]
+ }
}
}
/// Returns the appropriate [`Stdio`] to be used to capture `stdout` based on `self`.
fn stdout(self) -> Stdio {
match self {
Self::None(_, _) | Self::Clippy(_) => Stdio::null(),
- Self::DocTests(_) | Self::Tests(_) => Stdio::piped(),
+ Self::DocTests(_)
+ | Self::Tests(_)
+ | Self::IgnoredTests(_)
+ | Self::IncludeIgnoredTests(_) => Stdio::piped(),
}
}
/// Returns the entire command based on `self`.
@@ -148,6 +165,7 @@ impl Opts {
///
/// `self` is mutated iff `Self::None(_, false)` and `cargo t -q --doc` errors
/// due to a lack of library target; in which case, the second `bool` becomes `true`.
+ #[expect(clippy::else_if_without_else, reason = "don't want it")]
#[expect(clippy::too_many_lines, reason = "not too many")]
pub fn run_cmd(
&mut self,
@@ -175,17 +193,32 @@ impl Opts {
}
})
}
- Self::Clippy(color) | Self::DocTests(color) | Self::Tests(color) => {
+ Self::Clippy(color)
+ | Self::DocTests(color)
+ | Self::Tests(color)
+ | Self::IgnoredTests(color)
+ | Self::IncludeIgnoredTests(color) => {
let mut args = self.args();
if !features.is_empty() {
args.push("--features");
args.push(features);
}
- if matches!(*self, Self::DocTests(_) | Self::Tests(_)) {
+ if matches!(
+ *self,
+ Self::DocTests(_)
+ | Self::Tests(_)
+ | Self::IgnoredTests(_)
+ | Self::IncludeIgnoredTests(_)
+ ) {
args.push("--");
args.push("--color");
args.push(if color { "always" } else { "never" });
}
+ if matches!(*self, Self::IgnoredTests(_)) {
+ args.push("--ignored");
+ } else if matches!(*self, Self::IncludeIgnoredTests(_)) {
+ args.push("--include-ignored");
+ }
let output = Command::new("cargo")
.stderr(Stdio::piped())
.stdin(Stdio::null())
@@ -254,13 +287,24 @@ impl Opts {
msg.push_str(" --features ");
msg.push_str(features);
}
- if matches!(*self, Self::DocTests(_) | Self::Tests(_)) {
+ if matches!(
+ *self,
+ Self::DocTests(_)
+ | Self::Tests(_)
+ | Self::IgnoredTests(_)
+ | Self::IncludeIgnoredTests(_)
+ ) {
msg.push_str(if color {
" -- --color always"
} else {
" -- --color never"
});
}
+ if matches!(*self, Self::IgnoredTests(_)) {
+ msg.push_str(" --ignored");
+ } else if matches!(*self, Self::IncludeIgnoredTests(_)) {
+ msg.push_str(" --include-ignored");
+ }
Err(E::Cmd(msg))
},
)
@@ -313,6 +357,30 @@ impl Opts {
opt = Self::Tests(false);
}
}
+ "ignored" => {
+ if !matches!(opt, Self::None(_, _)) {
+ return Err(E::Args(ArgsErr::InvalidOption(String::from("ignored"))));
+ } else if opt.contains_color() {
+ return Err(E::Args(ArgsErr::InvalidOption(String::from("--color"))));
+ } else if path.is_some() {
+ return Err(E::Args(ArgsErr::InvalidOption(String::from("--dir"))));
+ } else {
+ opt = Self::IgnoredTests(false);
+ }
+ }
+ "include-ignored" => {
+ if !matches!(opt, Self::None(_, _)) {
+ return Err(E::Args(ArgsErr::InvalidOption(String::from(
+ "include-ignored",
+ ))));
+ } else if opt.contains_color() {
+ return Err(E::Args(ArgsErr::InvalidOption(String::from("--color"))));
+ } else if path.is_some() {
+ return Err(E::Args(ArgsErr::InvalidOption(String::from("--dir"))));
+ } else {
+ opt = Self::IncludeIgnoredTests(false);
+ }
+ }
"--color" => {
if opt.contains_color() {
return Err(E::Args(ArgsErr::DuplicateOption(arg)));
diff --git a/src/main.rs b/src/main.rs
@@ -26,56 +26,19 @@
//! * `clippy`: `cargo clippy -q` is invoked for each combination of features.
//! * `doc_tests`: `cargo t -q --doc` is invoked for each combination of features.
//! * `tests`: `cargo t -q --tests` is invoked for each combination of features.
+//! * `ignored`: `cargo t -q --tests -- --ignored` is invoked for each combination of features.
+//! * `include-ignored`: `cargo t -q --tests -- --include-ignored` is invoked for each combination of features.
//! * `--color`: `--color always` is passed to the above commands; otherwise without this option, `--color never` is
//! passed.
//! * `--dir <path to directory Cargo.toml is in>`: `ci` changes the working directory to the passed path (after
//! canonicalizing it) before executing. Without this, the current directory is used.
//!
-//! When `clippy`, `doc_tests`, and `tests` are not passed; then all three are invoked.
+//! When `clippy`, `doc_tests`, `tests`, `ignored`, and `include-ignored` are not passed; then `clippy`,
+//! `doc_tests`, and `tests` are invoked.
//!
//! ## Limitations
//!
-//! Any use of [`compile_error`] _not_ related to incompatible features will be silently ignored. Any `ignored`
-//! tests are not run.
-#![deny(
- unknown_lints,
- future_incompatible,
- let_underscore,
- missing_docs,
- nonstandard_style,
- rust_2018_compatibility,
- rust_2018_idioms,
- rust_2021_compatibility,
- rust_2024_compatibility,
- unsafe_code,
- unused,
- unused_crate_dependencies,
- warnings,
- clippy::all,
- clippy::cargo,
- clippy::complexity,
- clippy::correctness,
- clippy::nursery,
- clippy::pedantic,
- clippy::perf,
- clippy::restriction,
- clippy::style,
- clippy::suspicious
-)]
-#![expect(
- clippy::blanket_clippy_restriction_lints,
- clippy::arbitrary_source_item_ordering,
- clippy::implicit_return,
- clippy::min_ident_chars,
- clippy::missing_trait_methods,
- clippy::question_mark_used,
- clippy::ref_patterns,
- clippy::return_and_then,
- clippy::single_call_fn,
- clippy::single_char_lifetime_names,
- clippy::unseparated_literal_suffix,
- reason = "noisy, opinionated, and likely doesn't prevent bugs or improve APIs"
-)]
+//! Any use of [`compile_error`] _not_ related to incompatible features will be silently ignored.
extern crate alloc;
/// Functionality related to the passed arguments.
mod args;