bevy/tools/ci/src/prepare.rs

58 lines
1.5 KiB
Rust
Raw Normal View History

tools: Refactor CI to use `argh` (#12923) # Objective The CI tool currently parses input manually. This has worked fine, but makes it just a bit more difficult to maintain and extend. Additionally, it provides no usage help for devs wanting to run the tool locally. It would be better if parsing was handled by a dedicated CLI library like [`clap`](https://github.com/clap-rs/clap) or [`argh`](https://github.com/google/argh). ## Solution Use `argh` to parse command line input for CI. `argh` was chosen over `clap` and other tools due to being more lightweight and already existing in our dependency tree. Using `argh`, the usage notes are generated automatically: ``` $ cargo run -p ci --quiet -- --help Usage: ci [--keep-going] [<command>] [<args>] The CI command line tool for Bevy. Options: --keep-going continue running commands even if one fails --help display usage information Commands: lints Alias for running the `format` and `clippy` subcommands. doc Alias for running the `doc-test` and `doc-check` subcommands. compile Alias for running the `compile-fail`, `bench-check`, `example-check`, `compile-check`, and `test-check` subcommands. format Check code formatting. clippy Check for clippy warnings and errors. test Runs all tests (except for doc tests). test-check Checks that all tests compile. doc-check Checks that all docs compile. doc-test Runs all doc tests. compile-check Checks that the project compiles. cfg-check Checks that the project compiles using the nightly compiler with cfg checks enabled. compile-fail Runs the compile-fail tests. bench-check Checks that the benches compile. example-check Checks that the examples compile. ``` This PR makes each subcommand more modular, allowing them to be called from other subcommands. This also makes it much easier to extract them out of `main.rs` and into their own dedicated modules. Additionally, this PR improves failure output: ``` $ cargo run -p ci -- lints ... One or more CI commands failed: format: Please run 'cargo fmt --all' to format your code. ``` Including when run with the `--keep-going` flag: ``` $ cargo run -p ci -- --keep-going lints ... One or more CI commands failed: - format: Please run 'cargo fmt --all' to format your code. - clippy: Please fix clippy errors in output above. ``` ### Future Work There are a lot of other things we could possibly clean up. I chose to try and keep the API surface as unchanged as I could (for this PR at least). For example, now that each subcommand is an actual command, we can specify custom arguments for each. The `format` subcommand could include a `--check` (making the default fun `cargo fmt` as normal). Or the `compile-fail` subcommand could include `--ecs`, `--reflect`, and `--macros` flags for specifying which set of compile fail tests to run. The `--keep-going` flag could be split so that it doesn't do double-duty where it also enables `--no-fail-fast` for certain commands. Or at least make it more explicit via renaming or using alternative flags. --- ## Changelog - Improved the CI CLI tool - Now includes usage info with the `--help` option! - [Internal] Cleaned up and refactored the `tools/ci` crate using the `argh` crate ## Migration Guide The CI tool no longer supports running multiple subcommands in a single call. Users who are currently doing so will need to split them across multiple commands: ```bash # BEFORE cargo run -p ci -- lints doc compile # AFTER cargo run -p ci -- lints && cargo run -p ci -- doc && cargo run -p ci -- compile # or cargo run -p ci -- lints; cargo run -p ci -- doc; cargo run -p ci -- compile # or cargo run -p ci -- lints cargo run -p ci -- doc cargo run -p ci -- compile ```
2024-04-13 01:48:37 +00:00
use bitflags::bitflags;
/// Trait for preparing a subcommand to be run.
pub(crate) trait Prepare {
fn prepare<'a>(&self, sh: &'a xshell::Shell, flags: Flag) -> Vec<PreparedCommand<'a>>;
}
bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct Flag: u32 {
/// Forces certain checks to continue running even if they hit an error.
const KEEP_GOING = 1 << 0;
}
}
#[derive(Debug)]
pub(crate) struct PreparedCommand<'a> {
/// The name of the command.
pub name: &'static str,
/// The command to execute
pub command: xshell::Cmd<'a>,
/// The message to display if the test command fails
pub failure_message: &'static str,
/// The subdirectory path to run the test command within
pub subdir: Option<&'static str>,
/// Environment variables that need to be set before the test runs
pub env_vars: Vec<(&'static str, &'static str)>,
}
impl<'a> PreparedCommand<'a> {
pub fn new<T: argh::SubCommand>(
command: xshell::Cmd<'a>,
failure_message: &'static str,
) -> Self {
Self {
command,
name: T::COMMAND.name,
failure_message,
subdir: None,
env_vars: vec![],
}
}
pub fn with_subdir(mut self, subdir: &'static str) -> Self {
self.subdir = Some(subdir);
self
}
pub fn with_env_var(mut self, key: &'static str, value: &'static str) -> Self {
self.env_vars.push((key, value));
self
}
}