Small changes to ci tool (#13137)

# Objective

- Many of the items in the `ci` tool use `pub(crate)`, which is
functionally equivalent to `pub` when the crate is not a library.
- A few items are missing documentation.

## Solution

- Make all `pub(crate)` items just `pub`.
- `pub` is easier to type and less obscure, and there's not harm from
this change.
- Add / modify documentation on `CI`, `Prepare`, and `PreparedCommand`.
This commit is contained in:
BD103 2024-04-29 20:54:14 -04:00 committed by GitHub
parent 7b4b5966d9
commit abbaa3943e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 74 additions and 35 deletions

View file

@ -4,9 +4,10 @@ use argh::FromArgs;
/// The CI command line tool for Bevy. /// The CI command line tool for Bevy.
#[derive(FromArgs)] #[derive(FromArgs)]
pub(crate) struct CI { pub struct CI {
#[argh(subcommand)] #[argh(subcommand)]
command: Option<Commands>, command: Option<Commands>,
/// continue running commands even if one fails /// continue running commands even if one fails
#[argh(switch)] #[argh(switch)]
keep_going: bool, keep_going: bool,
@ -16,7 +17,7 @@ impl CI {
/// Runs the specified commands or all commands if none are specified. /// Runs the specified commands or all commands if none are specified.
/// ///
/// When run locally, results may differ from actual CI runs triggered by `.github/workflows/ci.yml`. /// When run locally, results may differ from actual CI runs triggered by `.github/workflows/ci.yml`.
/// This is because the official CI runs latest stable, while local runs use whatever the default Rust is locally. /// This is usually related to differing toolchains and configuration.
pub fn run(self) { pub fn run(self) {
let sh = xshell::Shell::new().unwrap(); let sh = xshell::Shell::new().unwrap();
@ -29,10 +30,13 @@ impl CI {
// This will automatically move back to the original directory once dropped. // This will automatically move back to the original directory once dropped.
let _subdir_hook = command.subdir.map(|path| sh.push_dir(path)); let _subdir_hook = command.subdir.map(|path| sh.push_dir(path));
// Execute each command, checking if it returned an error.
if command.command.envs(command.env_vars).run().is_err() { if command.command.envs(command.env_vars).run().is_err() {
let name = command.name; let name = command.name;
let message = command.failure_message; let message = command.failure_message;
if self.keep_going { if self.keep_going {
// We use bullet points here because there can be more than one error.
failures.push(format!("- {name}: {message}")); failures.push(format!("- {name}: {message}"));
} else { } else {
failures.push(format!("{name}: {message}")); failures.push(format!("{name}: {message}"));
@ -41,8 +45,10 @@ impl CI {
} }
} }
// Log errors at the very end.
if !failures.is_empty() { if !failures.is_empty() {
let failures = failures.join("\n"); let failures = failures.join("\n");
panic!( panic!(
"One or more CI commands failed:\n\ "One or more CI commands failed:\n\
{failures}" {failures}"

View file

@ -5,7 +5,7 @@ use xshell::cmd;
/// Checks that the benches compile. /// Checks that the benches compile.
#[derive(FromArgs, Default)] #[derive(FromArgs, Default)]
#[argh(subcommand, name = "bench-check")] #[argh(subcommand, name = "bench-check")]
pub(crate) struct BenchCheckCommand {} pub struct BenchCheckCommand {}
impl Prepare for BenchCheckCommand { impl Prepare for BenchCheckCommand {
fn prepare<'a>(&self, sh: &'a xshell::Shell, _flags: Flag) -> Vec<PreparedCommand<'a>> { fn prepare<'a>(&self, sh: &'a xshell::Shell, _flags: Flag) -> Vec<PreparedCommand<'a>> {

View file

@ -5,7 +5,7 @@ use xshell::cmd;
/// Checks that the project compiles using the nightly compiler with cfg checks enabled. /// Checks that the project compiles using the nightly compiler with cfg checks enabled.
#[derive(FromArgs, Default)] #[derive(FromArgs, Default)]
#[argh(subcommand, name = "cfg-check")] #[argh(subcommand, name = "cfg-check")]
pub(crate) struct CfgCheckCommand {} pub struct CfgCheckCommand {}
impl Prepare for CfgCheckCommand { impl Prepare for CfgCheckCommand {
fn prepare<'a>(&self, sh: &'a xshell::Shell, _flags: Flag) -> Vec<PreparedCommand<'a>> { fn prepare<'a>(&self, sh: &'a xshell::Shell, _flags: Flag) -> Vec<PreparedCommand<'a>> {

View file

@ -5,7 +5,7 @@ use xshell::cmd;
/// Check for clippy warnings and errors. /// Check for clippy warnings and errors.
#[derive(FromArgs, Default)] #[derive(FromArgs, Default)]
#[argh(subcommand, name = "clippy")] #[argh(subcommand, name = "clippy")]
pub(crate) struct ClippyCommand {} pub struct ClippyCommand {}
impl Prepare for ClippyCommand { impl Prepare for ClippyCommand {
fn prepare<'a>(&self, sh: &'a xshell::Shell, _flags: Flag) -> Vec<PreparedCommand<'a>> { fn prepare<'a>(&self, sh: &'a xshell::Shell, _flags: Flag) -> Vec<PreparedCommand<'a>> {

View file

@ -8,7 +8,7 @@ use argh::FromArgs;
/// Alias for running the `compile-fail`, `bench-check`, `example-check`, `compile-check`, and `test-check` subcommands. /// Alias for running the `compile-fail`, `bench-check`, `example-check`, `compile-check`, and `test-check` subcommands.
#[derive(FromArgs, Default)] #[derive(FromArgs, Default)]
#[argh(subcommand, name = "compile")] #[argh(subcommand, name = "compile")]
pub(crate) struct CompileCommand {} pub struct CompileCommand {}
impl Prepare for CompileCommand { impl Prepare for CompileCommand {
fn prepare<'a>(&self, sh: &'a xshell::Shell, flags: Flag) -> Vec<PreparedCommand<'a>> { fn prepare<'a>(&self, sh: &'a xshell::Shell, flags: Flag) -> Vec<PreparedCommand<'a>> {

View file

@ -5,7 +5,7 @@ use xshell::cmd;
/// Checks that the project compiles. /// Checks that the project compiles.
#[derive(FromArgs, Default)] #[derive(FromArgs, Default)]
#[argh(subcommand, name = "compile-check")] #[argh(subcommand, name = "compile-check")]
pub(crate) struct CompileCheckCommand {} pub struct CompileCheckCommand {}
impl Prepare for CompileCheckCommand { impl Prepare for CompileCheckCommand {
fn prepare<'a>(&self, sh: &'a xshell::Shell, _flags: Flag) -> Vec<PreparedCommand<'a>> { fn prepare<'a>(&self, sh: &'a xshell::Shell, _flags: Flag) -> Vec<PreparedCommand<'a>> {

View file

@ -5,7 +5,7 @@ use xshell::cmd;
/// Runs the compile-fail tests. /// Runs the compile-fail tests.
#[derive(FromArgs, Default)] #[derive(FromArgs, Default)]
#[argh(subcommand, name = "compile-fail")] #[argh(subcommand, name = "compile-fail")]
pub(crate) struct CompileFailCommand {} pub struct CompileFailCommand {}
impl Prepare for CompileFailCommand { impl Prepare for CompileFailCommand {
fn prepare<'a>(&self, sh: &'a xshell::Shell, flags: Flag) -> Vec<PreparedCommand<'a>> { fn prepare<'a>(&self, sh: &'a xshell::Shell, flags: Flag) -> Vec<PreparedCommand<'a>> {

View file

@ -5,7 +5,7 @@ use argh::FromArgs;
/// Alias for running the `doc-test` and `doc-check` subcommands. /// Alias for running the `doc-test` and `doc-check` subcommands.
#[derive(FromArgs, Default)] #[derive(FromArgs, Default)]
#[argh(subcommand, name = "doc")] #[argh(subcommand, name = "doc")]
pub(crate) struct DocCommand {} pub struct DocCommand {}
impl Prepare for DocCommand { impl Prepare for DocCommand {
fn prepare<'a>(&self, sh: &'a xshell::Shell, flags: Flag) -> Vec<PreparedCommand<'a>> { fn prepare<'a>(&self, sh: &'a xshell::Shell, flags: Flag) -> Vec<PreparedCommand<'a>> {

View file

@ -5,7 +5,7 @@ use xshell::cmd;
/// Checks that all docs compile. /// Checks that all docs compile.
#[derive(FromArgs, Default)] #[derive(FromArgs, Default)]
#[argh(subcommand, name = "doc-check")] #[argh(subcommand, name = "doc-check")]
pub(crate) struct DocCheckCommand {} pub struct DocCheckCommand {}
impl Prepare for DocCheckCommand { impl Prepare for DocCheckCommand {
fn prepare<'a>(&self, sh: &'a xshell::Shell, _flags: Flag) -> Vec<PreparedCommand<'a>> { fn prepare<'a>(&self, sh: &'a xshell::Shell, _flags: Flag) -> Vec<PreparedCommand<'a>> {

View file

@ -5,7 +5,7 @@ use xshell::cmd;
/// Runs all doc tests. /// Runs all doc tests.
#[derive(FromArgs, Default)] #[derive(FromArgs, Default)]
#[argh(subcommand, name = "doc-test")] #[argh(subcommand, name = "doc-test")]
pub(crate) struct DocTestCommand {} pub struct DocTestCommand {}
impl Prepare for DocTestCommand { impl Prepare for DocTestCommand {
fn prepare<'a>(&self, sh: &'a xshell::Shell, flags: Flag) -> Vec<PreparedCommand<'a>> { fn prepare<'a>(&self, sh: &'a xshell::Shell, flags: Flag) -> Vec<PreparedCommand<'a>> {

View file

@ -5,7 +5,7 @@ use xshell::cmd;
/// Checks that the examples compile. /// Checks that the examples compile.
#[derive(FromArgs, Default)] #[derive(FromArgs, Default)]
#[argh(subcommand, name = "example-check")] #[argh(subcommand, name = "example-check")]
pub(crate) struct ExampleCheckCommand {} pub struct ExampleCheckCommand {}
impl Prepare for ExampleCheckCommand { impl Prepare for ExampleCheckCommand {
fn prepare<'a>(&self, sh: &'a xshell::Shell, _flags: Flag) -> Vec<PreparedCommand<'a>> { fn prepare<'a>(&self, sh: &'a xshell::Shell, _flags: Flag) -> Vec<PreparedCommand<'a>> {

View file

@ -5,7 +5,7 @@ use xshell::cmd;
/// Check code formatting. /// Check code formatting.
#[derive(FromArgs, Default)] #[derive(FromArgs, Default)]
#[argh(subcommand, name = "format")] #[argh(subcommand, name = "format")]
pub(crate) struct FormatCommand {} pub struct FormatCommand {}
impl Prepare for FormatCommand { impl Prepare for FormatCommand {
fn prepare<'a>(&self, sh: &'a xshell::Shell, _flags: Flag) -> Vec<PreparedCommand<'a>> { fn prepare<'a>(&self, sh: &'a xshell::Shell, _flags: Flag) -> Vec<PreparedCommand<'a>> {

View file

@ -5,7 +5,7 @@ use argh::FromArgs;
/// Alias for running the `format` and `clippy` subcommands. /// Alias for running the `format` and `clippy` subcommands.
#[derive(FromArgs, Default)] #[derive(FromArgs, Default)]
#[argh(subcommand, name = "lints")] #[argh(subcommand, name = "lints")]
pub(crate) struct LintsCommand {} pub struct LintsCommand {}
impl Prepare for LintsCommand { impl Prepare for LintsCommand {
fn prepare<'a>(&self, sh: &'a xshell::Shell, flags: Flag) -> Vec<PreparedCommand<'a>> { fn prepare<'a>(&self, sh: &'a xshell::Shell, flags: Flag) -> Vec<PreparedCommand<'a>> {

View file

@ -1,17 +1,17 @@
pub(crate) use bench_check::*; pub use bench_check::*;
pub(crate) use cfg_check::*; pub use cfg_check::*;
pub(crate) use clippy::*; pub use clippy::*;
pub(crate) use compile::*; pub use compile::*;
pub(crate) use compile_check::*; pub use compile_check::*;
pub(crate) use compile_fail::*; pub use compile_fail::*;
pub(crate) use doc::*; pub use doc::*;
pub(crate) use doc_check::*; pub use doc_check::*;
pub(crate) use doc_test::*; pub use doc_test::*;
pub(crate) use example_check::*; pub use example_check::*;
pub(crate) use format::*; pub use format::*;
pub(crate) use lints::*; pub use lints::*;
pub(crate) use test::*; pub use test::*;
pub(crate) use test_check::*; pub use test_check::*;
mod bench_check; mod bench_check;
mod cfg_check; mod cfg_check;

View file

@ -5,7 +5,7 @@ use xshell::cmd;
/// Runs all tests (except for doc tests). /// Runs all tests (except for doc tests).
#[derive(FromArgs, Default)] #[derive(FromArgs, Default)]
#[argh(subcommand, name = "test")] #[argh(subcommand, name = "test")]
pub(crate) struct TestCommand {} pub struct TestCommand {}
impl Prepare for TestCommand { impl Prepare for TestCommand {
fn prepare<'a>(&self, sh: &'a xshell::Shell, flags: Flag) -> Vec<PreparedCommand<'a>> { fn prepare<'a>(&self, sh: &'a xshell::Shell, flags: Flag) -> Vec<PreparedCommand<'a>> {

View file

@ -5,7 +5,7 @@ use xshell::cmd;
/// Checks that all tests compile. /// Checks that all tests compile.
#[derive(FromArgs, Default)] #[derive(FromArgs, Default)]
#[argh(subcommand, name = "test-check")] #[argh(subcommand, name = "test-check")]
pub(crate) struct TestCheckCommand {} pub struct TestCheckCommand {}
impl Prepare for TestCheckCommand { impl Prepare for TestCheckCommand {
fn prepare<'a>(&self, sh: &'a xshell::Shell, _flags: Flag) -> Vec<PreparedCommand<'a>> { fn prepare<'a>(&self, sh: &'a xshell::Shell, _flags: Flag) -> Vec<PreparedCommand<'a>> {

View file

@ -4,8 +4,8 @@ mod ci;
mod commands; mod commands;
mod prepare; mod prepare;
pub(crate) use self::ci::*; pub use self::ci::*;
pub(crate) use self::prepare::*; pub use self::prepare::*;
fn main() { fn main() {
argh::from_env::<CI>().run(); argh::from_env::<CI>().run();

View file

@ -1,20 +1,44 @@
use bitflags::bitflags; use bitflags::bitflags;
/// Trait for preparing a subcommand to be run. /// Trait for preparing a subcommand to be run.
pub(crate) trait Prepare { pub trait Prepare {
/// A method that returns a list of [`PreparedCommand`]s to be run for a given shell and flags.
///
/// # Example
///
/// ```
/// # use crate::{Flag, Prepare, PreparedCommand};
/// # use argh::FromArgs;
/// # use xshell::Shell;
/// #
/// #[derive(FromArgs)]
/// #[argh(subcommand, name = "check")]
/// struct CheckCommand {}
///
/// impl Prepare for CheckCommand {
/// fn prepare<'a>(&self, sh: &'a Shell, flags: Flag) -> Vec<PreparedCommand<'a>> {
/// vec![PreparedCommand::new::<Self>(
/// cmd!(sh, "cargo check --workspace"),
/// "Please fix linter errors",
/// )]
/// }
/// }
/// ```
fn prepare<'a>(&self, sh: &'a xshell::Shell, flags: Flag) -> Vec<PreparedCommand<'a>>; fn prepare<'a>(&self, sh: &'a xshell::Shell, flags: Flag) -> Vec<PreparedCommand<'a>>;
} }
bitflags! { bitflags! {
/// Flags that modify how commands are run.
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct Flag: u32 { pub struct Flag: u32 {
/// Forces certain checks to continue running even if they hit an error. /// Forces certain checks to continue running even if they hit an error.
const KEEP_GOING = 1 << 0; const KEEP_GOING = 1 << 0;
} }
} }
/// A command with associated metadata, created from a command that implements [`Prepare`].
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct PreparedCommand<'a> { pub struct PreparedCommand<'a> {
/// The name of the command. /// The name of the command.
pub name: &'static str, pub name: &'static str,
@ -32,6 +56,13 @@ pub(crate) struct PreparedCommand<'a> {
} }
impl<'a> PreparedCommand<'a> { impl<'a> PreparedCommand<'a> {
/// Creates a new [`PreparedCommand`] from a [`Cmd`] and a failure message.
///
/// The other fields of [`PreparedCommand`] are filled in with their default values.
///
/// For more information about creating a [`Cmd`], please see the [`cmd!`](xshell::cmd) macro.
///
/// [`Cmd`]: xshell::Cmd
pub fn new<T: argh::SubCommand>( pub fn new<T: argh::SubCommand>(
command: xshell::Cmd<'a>, command: xshell::Cmd<'a>,
failure_message: &'static str, failure_message: &'static str,
@ -45,11 +76,13 @@ impl<'a> PreparedCommand<'a> {
} }
} }
/// A builder that overwrites the current sub-directory with a new value.
pub fn with_subdir(mut self, subdir: &'static str) -> Self { pub fn with_subdir(mut self, subdir: &'static str) -> Self {
self.subdir = Some(subdir); self.subdir = Some(subdir);
self self
} }
/// A builder that adds a new environmental variable to the list.
pub fn with_env_var(mut self, key: &'static str, value: &'static str) -> Self { pub fn with_env_var(mut self, key: &'static str, value: &'static str) -> Self {
self.env_vars.push((key, value)); self.env_vars.push((key, value));
self self