From c8cb7bdf5771c2baab3de82edaf254888a5c27b4 Mon Sep 17 00:00:00 2001 From: Lucas Franca Date: Mon, 16 Jun 2025 18:19:47 -0300 Subject: [PATCH] Allow passing number of thread for building and testing to CI (#19359) # Objective Fixes #16051 Closes #16145 ## Solution Allow passing `--build-jobs` and `--test-threads` to `ci` i.e. ``` cargo run -p ci -- --build-jobs 4 --test-threads 4 ``` ## Testing running ci locally --------- Co-authored-by: Benjamin Brienen --- tools/ci/Cargo.toml | 1 - tools/ci/src/args.rs | 37 ++++++++ tools/ci/src/ci.rs | 84 ++++++++++--------- tools/ci/src/commands/bench_check.rs | 8 +- tools/ci/src/commands/clippy.rs | 8 +- tools/ci/src/commands/compile.rs | 17 ++-- tools/ci/src/commands/compile_check.rs | 8 +- tools/ci/src/commands/compile_fail.rs | 19 +++-- tools/ci/src/commands/doc.rs | 9 +- tools/ci/src/commands/doc_check.rs | 8 +- tools/ci/src/commands/doc_test.rs | 16 ++-- tools/ci/src/commands/example_check.rs | 8 +- tools/ci/src/commands/format.rs | 4 +- tools/ci/src/commands/integration_test.rs | 15 ++-- .../ci/src/commands/integration_test_check.rs | 12 ++- .../ci/src/commands/integration_test_clean.rs | 4 +- tools/ci/src/commands/lints.rs | 9 +- tools/ci/src/commands/test.rs | 13 ++- tools/ci/src/commands/test_check.rs | 8 +- tools/ci/src/main.rs | 1 + tools/ci/src/prepare.rs | 17 +--- 21 files changed, 181 insertions(+), 125 deletions(-) create mode 100644 tools/ci/src/args.rs diff --git a/tools/ci/Cargo.toml b/tools/ci/Cargo.toml index 65d6b7b1be..d42eb55505 100644 --- a/tools/ci/Cargo.toml +++ b/tools/ci/Cargo.toml @@ -8,7 +8,6 @@ license = "MIT OR Apache-2.0" [dependencies] argh = "0.1" xshell = "0.2" -bitflags = "2.3" [lints] workspace = true diff --git a/tools/ci/src/args.rs b/tools/ci/src/args.rs new file mode 100644 index 0000000000..574d98f192 --- /dev/null +++ b/tools/ci/src/args.rs @@ -0,0 +1,37 @@ +use crate::CI; + +/// Arguments that are available to CI commands. +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct Args { + keep_going: bool, + test_threads: Option, + build_jobs: Option, +} + +impl Args { + #[inline(always)] + pub fn keep_going(&self) -> Option<&'static str> { + self.keep_going.then_some("--no-fail-fast") + } + + #[inline(always)] + pub fn build_jobs(&self) -> Option { + self.build_jobs.map(|jobs| format!("--jobs={jobs}")) + } + + #[inline(always)] + pub fn test_threads(&self) -> Option { + self.test_threads + .map(|threads| format!("--test-threads={threads}")) + } +} + +impl From<&CI> for Args { + fn from(value: &CI) -> Self { + Args { + keep_going: value.keep_going, + test_threads: value.test_threads, + build_jobs: value.build_jobs, + } + } +} diff --git a/tools/ci/src/ci.rs b/tools/ci/src/ci.rs index 349e74a5a0..8b8556d90a 100644 --- a/tools/ci/src/ci.rs +++ b/tools/ci/src/ci.rs @@ -1,6 +1,7 @@ use crate::{ + args::Args, commands, - prepare::{Flag, Prepare, PreparedCommand}, + prepare::{Prepare, PreparedCommand}, }; use argh::FromArgs; @@ -12,7 +13,15 @@ pub struct CI { /// continue running commands even if one fails #[argh(switch)] - keep_going: bool, + pub(crate) keep_going: bool, + + /// parallelism of `cargo test` + #[argh(option)] + pub(crate) test_threads: Option, + + /// number of build jobs + #[argh(option)] + pub(crate) build_jobs: Option, } impl CI { @@ -22,7 +31,6 @@ impl CI { /// This is usually related to differing toolchains and configuration. pub fn run(self) { let sh = xshell::Shell::new().unwrap(); - let prepared_commands = self.prepare(&sh); let mut failures = vec![]; @@ -59,34 +67,30 @@ impl CI { } fn prepare<'a>(&self, sh: &'a xshell::Shell) -> Vec> { - let mut flags = Flag::empty(); - - if self.keep_going { - flags |= Flag::KEEP_GOING; - } - + let args = self.into(); match &self.command { - Some(command) => command.prepare(sh, flags), + Some(command) => command.prepare(sh, args), None => { // Note that we are running the subcommands directly rather than using any aliases let mut cmds = vec![]; - cmds.append(&mut commands::FormatCommand::default().prepare(sh, flags)); - cmds.append(&mut commands::ClippyCommand::default().prepare(sh, flags)); - cmds.append(&mut commands::TestCommand::default().prepare(sh, flags)); - cmds.append(&mut commands::TestCheckCommand::default().prepare(sh, flags)); - cmds.append(&mut commands::IntegrationTestCommand::default().prepare(sh, flags)); + cmds.append(&mut commands::FormatCommand::default().prepare(sh, args)); + cmds.append(&mut commands::ClippyCommand::default().prepare(sh, args)); + cmds.append(&mut commands::TestCommand::default().prepare(sh, args)); + cmds.append(&mut commands::TestCheckCommand::default().prepare(sh, args)); + cmds.append(&mut commands::IntegrationTestCommand::default().prepare(sh, args)); cmds.append( - &mut commands::IntegrationTestCheckCommand::default().prepare(sh, flags), + &mut commands::IntegrationTestCheckCommand::default().prepare(sh, args), ); cmds.append( - &mut commands::IntegrationTestCleanCommand::default().prepare(sh, flags), + &mut commands::IntegrationTestCleanCommand::default().prepare(sh, args), ); - cmds.append(&mut commands::DocCheckCommand::default().prepare(sh, flags)); - cmds.append(&mut commands::DocTestCommand::default().prepare(sh, flags)); - cmds.append(&mut commands::CompileCheckCommand::default().prepare(sh, flags)); - cmds.append(&mut commands::CompileFailCommand::default().prepare(sh, flags)); - cmds.append(&mut commands::BenchCheckCommand::default().prepare(sh, flags)); - cmds.append(&mut commands::ExampleCheckCommand::default().prepare(sh, flags)); + cmds.append(&mut commands::DocCheckCommand::default().prepare(sh, args)); + cmds.append(&mut commands::DocTestCommand::default().prepare(sh, args)); + cmds.append(&mut commands::CompileCheckCommand::default().prepare(sh, args)); + cmds.append(&mut commands::CompileFailCommand::default().prepare(sh, args)); + cmds.append(&mut commands::BenchCheckCommand::default().prepare(sh, args)); + cmds.append(&mut commands::ExampleCheckCommand::default().prepare(sh, args)); + cmds } } @@ -118,25 +122,25 @@ enum Commands { } impl Prepare for Commands { - fn prepare<'a>(&self, sh: &'a xshell::Shell, flags: Flag) -> Vec> { + fn prepare<'a>(&self, sh: &'a xshell::Shell, args: Args) -> Vec> { match self { - Commands::Lints(subcommand) => subcommand.prepare(sh, flags), - Commands::Doc(subcommand) => subcommand.prepare(sh, flags), - Commands::Compile(subcommand) => subcommand.prepare(sh, flags), + Commands::Lints(subcommand) => subcommand.prepare(sh, args), + Commands::Doc(subcommand) => subcommand.prepare(sh, args), + Commands::Compile(subcommand) => subcommand.prepare(sh, args), - Commands::Format(subcommand) => subcommand.prepare(sh, flags), - Commands::Clippy(subcommand) => subcommand.prepare(sh, flags), - Commands::Test(subcommand) => subcommand.prepare(sh, flags), - Commands::TestCheck(subcommand) => subcommand.prepare(sh, flags), - Commands::IntegrationTest(subcommand) => subcommand.prepare(sh, flags), - Commands::IntegrationTestCheck(subcommand) => subcommand.prepare(sh, flags), - Commands::IntegrationTestClean(subcommand) => subcommand.prepare(sh, flags), - Commands::DocCheck(subcommand) => subcommand.prepare(sh, flags), - Commands::DocTest(subcommand) => subcommand.prepare(sh, flags), - Commands::CompileCheck(subcommand) => subcommand.prepare(sh, flags), - Commands::CompileFail(subcommand) => subcommand.prepare(sh, flags), - Commands::BenchCheck(subcommand) => subcommand.prepare(sh, flags), - Commands::ExampleCheck(subcommand) => subcommand.prepare(sh, flags), + Commands::Format(subcommand) => subcommand.prepare(sh, args), + Commands::Clippy(subcommand) => subcommand.prepare(sh, args), + Commands::Test(subcommand) => subcommand.prepare(sh, args), + Commands::TestCheck(subcommand) => subcommand.prepare(sh, args), + Commands::IntegrationTest(subcommand) => subcommand.prepare(sh, args), + Commands::IntegrationTestCheck(subcommand) => subcommand.prepare(sh, args), + Commands::IntegrationTestClean(subcommand) => subcommand.prepare(sh, args), + Commands::DocCheck(subcommand) => subcommand.prepare(sh, args), + Commands::DocTest(subcommand) => subcommand.prepare(sh, args), + Commands::CompileCheck(subcommand) => subcommand.prepare(sh, args), + Commands::CompileFail(subcommand) => subcommand.prepare(sh, args), + Commands::BenchCheck(subcommand) => subcommand.prepare(sh, args), + Commands::ExampleCheck(subcommand) => subcommand.prepare(sh, args), } } } diff --git a/tools/ci/src/commands/bench_check.rs b/tools/ci/src/commands/bench_check.rs index 9e72ab0a64..748f10a730 100644 --- a/tools/ci/src/commands/bench_check.rs +++ b/tools/ci/src/commands/bench_check.rs @@ -1,4 +1,4 @@ -use crate::{Flag, Prepare, PreparedCommand}; +use crate::{args::Args, Prepare, PreparedCommand}; use argh::FromArgs; use xshell::cmd; @@ -8,11 +8,13 @@ use xshell::cmd; pub struct BenchCheckCommand {} impl Prepare for BenchCheckCommand { - fn prepare<'a>(&self, sh: &'a xshell::Shell, _flags: Flag) -> Vec> { + fn prepare<'a>(&self, sh: &'a xshell::Shell, args: Args) -> Vec> { + let jobs = args.build_jobs(); + vec![PreparedCommand::new::( cmd!( sh, - "cargo check --benches --target-dir ../target --manifest-path ./benches/Cargo.toml" + "cargo check --benches {jobs...} --target-dir ../target --manifest-path ./benches/Cargo.toml" ), "Failed to check the benches.", )] diff --git a/tools/ci/src/commands/clippy.rs b/tools/ci/src/commands/clippy.rs index 5e097c05a1..7d3d9afb29 100644 --- a/tools/ci/src/commands/clippy.rs +++ b/tools/ci/src/commands/clippy.rs @@ -1,4 +1,4 @@ -use crate::{Flag, Prepare, PreparedCommand}; +use crate::{args::Args, Prepare, PreparedCommand}; use argh::FromArgs; use xshell::cmd; @@ -8,11 +8,13 @@ use xshell::cmd; pub struct ClippyCommand {} impl Prepare for ClippyCommand { - fn prepare<'a>(&self, sh: &'a xshell::Shell, _flags: Flag) -> Vec> { + fn prepare<'a>(&self, sh: &'a xshell::Shell, args: Args) -> Vec> { + let jobs = args.build_jobs(); + vec![PreparedCommand::new::( cmd!( sh, - "cargo clippy --workspace --all-targets --all-features -- -Dwarnings" + "cargo clippy --workspace --all-targets --all-features {jobs...} -- -Dwarnings" ), "Please fix clippy errors in output above.", )] diff --git a/tools/ci/src/commands/compile.rs b/tools/ci/src/commands/compile.rs index f445aaca57..622b5b27f0 100644 --- a/tools/ci/src/commands/compile.rs +++ b/tools/ci/src/commands/compile.rs @@ -1,9 +1,10 @@ use crate::{ + args::Args, commands::{ BenchCheckCommand, CompileCheckCommand, CompileFailCommand, ExampleCheckCommand, IntegrationTestCheckCommand, TestCheckCommand, }, - Flag, Prepare, PreparedCommand, + Prepare, PreparedCommand, }; use argh::FromArgs; @@ -13,14 +14,14 @@ use argh::FromArgs; pub struct CompileCommand {} impl Prepare for CompileCommand { - fn prepare<'a>(&self, sh: &'a xshell::Shell, flags: Flag) -> Vec> { + fn prepare<'a>(&self, sh: &'a xshell::Shell, args: Args) -> Vec> { let mut commands = vec![]; - commands.append(&mut CompileFailCommand::default().prepare(sh, flags)); - commands.append(&mut BenchCheckCommand::default().prepare(sh, flags)); - commands.append(&mut ExampleCheckCommand::default().prepare(sh, flags)); - commands.append(&mut CompileCheckCommand::default().prepare(sh, flags)); - commands.append(&mut TestCheckCommand::default().prepare(sh, flags)); - commands.append(&mut IntegrationTestCheckCommand::default().prepare(sh, flags)); + commands.append(&mut CompileFailCommand::default().prepare(sh, args)); + commands.append(&mut BenchCheckCommand::default().prepare(sh, args)); + commands.append(&mut ExampleCheckCommand::default().prepare(sh, args)); + commands.append(&mut CompileCheckCommand::default().prepare(sh, args)); + commands.append(&mut TestCheckCommand::default().prepare(sh, args)); + commands.append(&mut IntegrationTestCheckCommand::default().prepare(sh, args)); commands } } diff --git a/tools/ci/src/commands/compile_check.rs b/tools/ci/src/commands/compile_check.rs index 62d8a8da75..e3628dc381 100644 --- a/tools/ci/src/commands/compile_check.rs +++ b/tools/ci/src/commands/compile_check.rs @@ -1,4 +1,4 @@ -use crate::{Flag, Prepare, PreparedCommand}; +use crate::{args::Args, Prepare, PreparedCommand}; use argh::FromArgs; use xshell::cmd; @@ -8,9 +8,11 @@ use xshell::cmd; pub struct CompileCheckCommand {} impl Prepare for CompileCheckCommand { - fn prepare<'a>(&self, sh: &'a xshell::Shell, _flags: Flag) -> Vec> { + fn prepare<'a>(&self, sh: &'a xshell::Shell, args: Args) -> Vec> { + let jobs = args.build_jobs(); + vec![PreparedCommand::new::( - cmd!(sh, "cargo check --workspace"), + cmd!(sh, "cargo check --workspace {jobs...}"), "Please fix compiler errors in output above.", )] } diff --git a/tools/ci/src/commands/compile_fail.rs b/tools/ci/src/commands/compile_fail.rs index 65a91e6d2f..e2c6e62d94 100644 --- a/tools/ci/src/commands/compile_fail.rs +++ b/tools/ci/src/commands/compile_fail.rs @@ -1,4 +1,4 @@ -use crate::{Flag, Prepare, PreparedCommand}; +use crate::{args::Args, Prepare, PreparedCommand}; use argh::FromArgs; use xshell::cmd; @@ -8,11 +8,12 @@ use xshell::cmd; pub struct CompileFailCommand {} impl Prepare for CompileFailCommand { - fn prepare<'a>(&self, sh: &'a xshell::Shell, flags: Flag) -> Vec> { - let no_fail_fast = flags - .contains(Flag::KEEP_GOING) - .then_some("--no-fail-fast") - .unwrap_or_default(); + fn prepare<'a>(&self, sh: &'a xshell::Shell, args: Args) -> Vec> { + let no_fail_fast = args.keep_going(); + let jobs = args.build_jobs(); + let test_threads = args.test_threads(); + let jobs_ref = jobs.as_ref(); + let test_threads_ref = test_threads.as_ref(); let mut commands = vec![]; @@ -21,7 +22,7 @@ impl Prepare for CompileFailCommand { // - See crates/bevy_macros_compile_fail_tests/README.md commands.push( PreparedCommand::new::( - cmd!(sh, "cargo test --target-dir ../../../target {no_fail_fast}"), + cmd!(sh, "cargo test --target-dir ../../../target {no_fail_fast...} {jobs_ref...} -- {test_threads_ref...}"), "Compiler errors of the macros compile fail tests seem to be different than expected! Check locally and compare rust versions.", ) .with_subdir("crates/bevy_derive/compile_fail"), @@ -32,7 +33,7 @@ impl Prepare for CompileFailCommand { // - See crates/bevy_ecs_compile_fail_tests/README.md commands.push( PreparedCommand::new::( - cmd!(sh, "cargo test --target-dir ../../../target {no_fail_fast}"), + cmd!(sh, "cargo test --target-dir ../../../target {no_fail_fast...} {jobs_ref...} -- {test_threads_ref...}"), "Compiler errors of the ECS compile fail tests seem to be different than expected! Check locally and compare rust versions.", ) .with_subdir("crates/bevy_ecs/compile_fail"), @@ -43,7 +44,7 @@ impl Prepare for CompileFailCommand { // - See crates/bevy_reflect_compile_fail_tests/README.md commands.push( PreparedCommand::new::( - cmd!(sh, "cargo test --target-dir ../../../target {no_fail_fast}"), + cmd!(sh, "cargo test --target-dir ../../../target {no_fail_fast...} {jobs...} -- {test_threads...}"), "Compiler errors of the Reflect compile fail tests seem to be different than expected! Check locally and compare rust versions.", ) .with_subdir("crates/bevy_reflect/compile_fail"), diff --git a/tools/ci/src/commands/doc.rs b/tools/ci/src/commands/doc.rs index fb8074ca8c..90fbbd30a5 100644 --- a/tools/ci/src/commands/doc.rs +++ b/tools/ci/src/commands/doc.rs @@ -1,6 +1,7 @@ use crate::{ + args::Args, commands::{DocCheckCommand, DocTestCommand}, - Flag, Prepare, PreparedCommand, + Prepare, PreparedCommand, }; use argh::FromArgs; @@ -10,10 +11,10 @@ use argh::FromArgs; pub struct DocCommand {} impl Prepare for DocCommand { - fn prepare<'a>(&self, sh: &'a xshell::Shell, flags: Flag) -> Vec> { + fn prepare<'a>(&self, sh: &'a xshell::Shell, args: Args) -> Vec> { let mut commands = vec![]; - commands.append(&mut DocTestCommand::default().prepare(sh, flags)); - commands.append(&mut DocCheckCommand::default().prepare(sh, flags)); + commands.append(&mut DocTestCommand::default().prepare(sh, args)); + commands.append(&mut DocCheckCommand::default().prepare(sh, args)); commands } } diff --git a/tools/ci/src/commands/doc_check.rs b/tools/ci/src/commands/doc_check.rs index ef5fc502df..75bf0cddf1 100644 --- a/tools/ci/src/commands/doc_check.rs +++ b/tools/ci/src/commands/doc_check.rs @@ -1,4 +1,4 @@ -use crate::{Flag, Prepare, PreparedCommand}; +use crate::{args::Args, Prepare, PreparedCommand}; use argh::FromArgs; use xshell::cmd; @@ -8,11 +8,13 @@ use xshell::cmd; pub struct DocCheckCommand {} impl Prepare for DocCheckCommand { - fn prepare<'a>(&self, sh: &'a xshell::Shell, _flags: Flag) -> Vec> { + fn prepare<'a>(&self, sh: &'a xshell::Shell, args: Args) -> Vec> { + let jobs = args.build_jobs(); + vec![PreparedCommand::new::( cmd!( sh, - "cargo doc --workspace --all-features --no-deps --document-private-items --keep-going" + "cargo doc --workspace --all-features --no-deps --document-private-items {jobs...} --keep-going" ), "Please fix doc warnings in output above.", ) diff --git a/tools/ci/src/commands/doc_test.rs b/tools/ci/src/commands/doc_test.rs index c1ce22c3e6..67d1d21720 100644 --- a/tools/ci/src/commands/doc_test.rs +++ b/tools/ci/src/commands/doc_test.rs @@ -1,4 +1,4 @@ -use crate::{Flag, Prepare, PreparedCommand}; +use crate::{args::Args, Prepare, PreparedCommand}; use argh::FromArgs; use xshell::cmd; @@ -8,14 +8,16 @@ use xshell::cmd; pub struct DocTestCommand {} impl Prepare for DocTestCommand { - fn prepare<'a>(&self, sh: &'a xshell::Shell, flags: Flag) -> Vec> { - let no_fail_fast = flags - .contains(Flag::KEEP_GOING) - .then_some("--no-fail-fast") - .unwrap_or_default(); + fn prepare<'a>(&self, sh: &'a xshell::Shell, args: Args) -> Vec> { + let no_fail_fast = args.keep_going(); + let jobs = args.build_jobs(); + let test_threads = args.test_threads(); vec![PreparedCommand::new::( - cmd!(sh, "cargo test --workspace --doc {no_fail_fast}"), + cmd!( + sh, + "cargo test --workspace --doc {no_fail_fast...} {jobs...} -- {test_threads...}" + ), "Please fix failing doc tests in output above.", )] } diff --git a/tools/ci/src/commands/example_check.rs b/tools/ci/src/commands/example_check.rs index d3d3f5ddf2..6533dbac0e 100644 --- a/tools/ci/src/commands/example_check.rs +++ b/tools/ci/src/commands/example_check.rs @@ -1,4 +1,4 @@ -use crate::{Flag, Prepare, PreparedCommand}; +use crate::{args::Args, Prepare, PreparedCommand}; use argh::FromArgs; use xshell::cmd; @@ -8,9 +8,11 @@ use xshell::cmd; pub struct ExampleCheckCommand {} impl Prepare for ExampleCheckCommand { - fn prepare<'a>(&self, sh: &'a xshell::Shell, _flags: Flag) -> Vec> { + fn prepare<'a>(&self, sh: &'a xshell::Shell, args: Args) -> Vec> { + let jobs = args.build_jobs(); + vec![PreparedCommand::new::( - cmd!(sh, "cargo check --workspace --examples"), + cmd!(sh, "cargo check --workspace --examples {jobs...}"), "Please fix compiler errors for examples in output above.", )] } diff --git a/tools/ci/src/commands/format.rs b/tools/ci/src/commands/format.rs index f5aacc5301..a6ae00cf1f 100644 --- a/tools/ci/src/commands/format.rs +++ b/tools/ci/src/commands/format.rs @@ -1,4 +1,4 @@ -use crate::{Flag, Prepare, PreparedCommand}; +use crate::{args::Args, Prepare, PreparedCommand}; use argh::FromArgs; use xshell::cmd; @@ -8,7 +8,7 @@ use xshell::cmd; pub struct FormatCommand {} impl Prepare for FormatCommand { - fn prepare<'a>(&self, sh: &'a xshell::Shell, _flags: Flag) -> Vec> { + fn prepare<'a>(&self, sh: &'a xshell::Shell, _args: Args) -> Vec> { vec![PreparedCommand::new::( cmd!(sh, "cargo fmt --all -- --check"), "Please run 'cargo fmt --all' to format your code.", diff --git a/tools/ci/src/commands/integration_test.rs b/tools/ci/src/commands/integration_test.rs index b86a027a56..35fefacd24 100644 --- a/tools/ci/src/commands/integration_test.rs +++ b/tools/ci/src/commands/integration_test.rs @@ -1,4 +1,4 @@ -use crate::{commands::get_integration_tests, Flag, Prepare, PreparedCommand}; +use crate::{args::Args, commands::get_integration_tests, Prepare, PreparedCommand}; use argh::FromArgs; use xshell::cmd; @@ -8,11 +8,12 @@ use xshell::cmd; pub struct IntegrationTestCommand {} impl Prepare for IntegrationTestCommand { - fn prepare<'a>(&self, sh: &'a xshell::Shell, flags: Flag) -> Vec> { - let no_fail_fast = flags - .contains(Flag::KEEP_GOING) - .then_some("--no-fail-fast") - .unwrap_or_default(); + fn prepare<'a>(&self, sh: &'a xshell::Shell, args: Args) -> Vec> { + let no_fail_fast = args.keep_going(); + let jobs = args.build_jobs(); + let test_threads = args.test_threads(); + let jobs_ref = jobs.as_ref(); + let test_threads_ref = test_threads.as_ref(); get_integration_tests(sh) .into_iter() @@ -20,7 +21,7 @@ impl Prepare for IntegrationTestCommand { PreparedCommand::new::( cmd!( sh, - "cargo test --manifest-path {path}/Cargo.toml --tests {no_fail_fast}" + "cargo test --manifest-path {path}/Cargo.toml --tests {no_fail_fast...} {jobs_ref...} -- {test_threads_ref...}" ), "Please fix failing integration tests in output above.", ) diff --git a/tools/ci/src/commands/integration_test_check.rs b/tools/ci/src/commands/integration_test_check.rs index d10808a746..af47b9bffa 100644 --- a/tools/ci/src/commands/integration_test_check.rs +++ b/tools/ci/src/commands/integration_test_check.rs @@ -1,6 +1,6 @@ use std::path::Path; -use crate::{Flag, Prepare, PreparedCommand}; +use crate::{args::Args, Prepare, PreparedCommand}; use argh::FromArgs; use xshell::cmd; @@ -21,12 +21,18 @@ pub fn get_integration_tests(sh: &xshell::Shell) -> Vec { pub struct IntegrationTestCheckCommand {} impl Prepare for IntegrationTestCheckCommand { - fn prepare<'a>(&self, sh: &'a xshell::Shell, _flags: Flag) -> Vec> { + fn prepare<'a>(&self, sh: &'a xshell::Shell, args: Args) -> Vec> { + let jobs = args.build_jobs(); + let jobs_ref = jobs.as_ref(); + get_integration_tests(sh) .into_iter() .map(|path| { PreparedCommand::new::( - cmd!(sh, "cargo check --manifest-path {path}/Cargo.toml --tests"), + cmd!( + sh, + "cargo check --manifest-path {path}/Cargo.toml --tests {jobs_ref...}" + ), "Please fix compiler errors for tests in output above.", ) }) diff --git a/tools/ci/src/commands/integration_test_clean.rs b/tools/ci/src/commands/integration_test_clean.rs index 9ad7a44f0b..5ac13bf6ff 100644 --- a/tools/ci/src/commands/integration_test_clean.rs +++ b/tools/ci/src/commands/integration_test_clean.rs @@ -1,4 +1,4 @@ -use crate::{Flag, Prepare, PreparedCommand}; +use crate::{args::Args, Prepare, PreparedCommand}; use argh::FromArgs; use xshell::cmd; @@ -10,7 +10,7 @@ use super::get_integration_tests; pub struct IntegrationTestCleanCommand {} impl Prepare for IntegrationTestCleanCommand { - fn prepare<'a>(&self, sh: &'a xshell::Shell, _flags: Flag) -> Vec> { + fn prepare<'a>(&self, sh: &'a xshell::Shell, _args: Args) -> Vec> { get_integration_tests(sh) .into_iter() .map(|path| { diff --git a/tools/ci/src/commands/lints.rs b/tools/ci/src/commands/lints.rs index befdaf5fc5..f21bb1b8ef 100644 --- a/tools/ci/src/commands/lints.rs +++ b/tools/ci/src/commands/lints.rs @@ -1,6 +1,7 @@ use crate::{ + args::Args, commands::{ClippyCommand, FormatCommand}, - Flag, Prepare, PreparedCommand, + Prepare, PreparedCommand, }; use argh::FromArgs; @@ -10,10 +11,10 @@ use argh::FromArgs; pub struct LintsCommand {} impl Prepare for LintsCommand { - fn prepare<'a>(&self, sh: &'a xshell::Shell, flags: Flag) -> Vec> { + fn prepare<'a>(&self, sh: &'a xshell::Shell, args: Args) -> Vec> { let mut commands = vec![]; - commands.append(&mut FormatCommand::default().prepare(sh, flags)); - commands.append(&mut ClippyCommand::default().prepare(sh, flags)); + commands.append(&mut FormatCommand::default().prepare(sh, args)); + commands.append(&mut ClippyCommand::default().prepare(sh, args)); commands } } diff --git a/tools/ci/src/commands/test.rs b/tools/ci/src/commands/test.rs index bdb4b663d1..a904e59c46 100644 --- a/tools/ci/src/commands/test.rs +++ b/tools/ci/src/commands/test.rs @@ -1,4 +1,4 @@ -use crate::{Flag, Prepare, PreparedCommand}; +use crate::{args::Args, Prepare, PreparedCommand}; use argh::FromArgs; use xshell::cmd; @@ -8,18 +8,17 @@ use xshell::cmd; pub struct TestCommand {} impl Prepare for TestCommand { - fn prepare<'a>(&self, sh: &'a xshell::Shell, flags: Flag) -> Vec> { - let no_fail_fast = flags - .contains(Flag::KEEP_GOING) - .then_some("--no-fail-fast") - .unwrap_or_default(); + fn prepare<'a>(&self, sh: &'a xshell::Shell, args: Args) -> Vec> { + let no_fail_fast = args.keep_going(); + let jobs = args.build_jobs(); + let test_threads = args.test_threads(); vec![PreparedCommand::new::( cmd!( sh, // `--benches` runs each benchmark once in order to verify that they behave // correctly and do not panic. - "cargo test --workspace --lib --bins --tests --benches {no_fail_fast}" + "cargo test --workspace --lib --bins --tests --benches {no_fail_fast...} {jobs...} -- {test_threads...}" ), "Please fix failing tests in output above.", )] diff --git a/tools/ci/src/commands/test_check.rs b/tools/ci/src/commands/test_check.rs index 8671b4f6cf..9f62b15ad1 100644 --- a/tools/ci/src/commands/test_check.rs +++ b/tools/ci/src/commands/test_check.rs @@ -1,4 +1,4 @@ -use crate::{Flag, Prepare, PreparedCommand}; +use crate::{args::Args, Prepare, PreparedCommand}; use argh::FromArgs; use xshell::cmd; @@ -8,9 +8,11 @@ use xshell::cmd; pub struct TestCheckCommand {} impl Prepare for TestCheckCommand { - fn prepare<'a>(&self, sh: &'a xshell::Shell, _flags: Flag) -> Vec> { + fn prepare<'a>(&self, sh: &'a xshell::Shell, args: Args) -> Vec> { + let jobs = args.build_jobs(); + vec![PreparedCommand::new::( - cmd!(sh, "cargo check --workspace --tests"), + cmd!(sh, "cargo check --workspace --tests {jobs...}"), "Please fix compiler errors for tests in output above.", )] } diff --git a/tools/ci/src/main.rs b/tools/ci/src/main.rs index 40893a528d..7758fc9202 100644 --- a/tools/ci/src/main.rs +++ b/tools/ci/src/main.rs @@ -1,5 +1,6 @@ //! CI script used for Bevy. +mod args; mod ci; mod commands; mod prepare; diff --git a/tools/ci/src/prepare.rs b/tools/ci/src/prepare.rs index 923bc33f80..b3a3d8f568 100644 --- a/tools/ci/src/prepare.rs +++ b/tools/ci/src/prepare.rs @@ -1,4 +1,4 @@ -use bitflags::bitflags; +use crate::args::Args; /// Trait for preparing a subcommand to be run. pub trait Prepare { @@ -7,7 +7,7 @@ pub trait Prepare { /// # Example /// /// ``` - /// # use crate::{Flag, Prepare, PreparedCommand}; + /// # use crate::{args::Args, Prepare, PreparedCommand}; /// # use argh::FromArgs; /// # use xshell::Shell; /// # @@ -16,7 +16,7 @@ pub trait Prepare { /// struct CheckCommand {} /// /// impl Prepare for CheckCommand { - /// fn prepare<'a>(&self, sh: &'a Shell, flags: Flag) -> Vec> { + /// fn prepare<'a>(&self, sh: &'a Shell, args: Args) -> Vec> { /// vec![PreparedCommand::new::( /// cmd!(sh, "cargo check --workspace"), /// "Please fix linter errors", @@ -24,16 +24,7 @@ pub trait Prepare { /// } /// } /// ``` - fn prepare<'a>(&self, sh: &'a xshell::Shell, flags: Flag) -> Vec>; -} - -bitflags! { - /// Flags that modify how commands are run. - #[derive(Clone, Copy, Debug, PartialEq, Eq)] - pub struct Flag: u32 { - /// Forces certain checks to continue running even if they hit an error. - const KEEP_GOING = 1 << 0; - } + fn prepare<'a>(&self, sh: &'a xshell::Shell, args: Args) -> Vec>; } /// A command with associated metadata, created from a command that implements [`Prepare`].