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 <Benjamin.Brienen@outlook.com>
This commit is contained in:
Lucas Franca 2025-06-16 18:19:47 -03:00 committed by GitHub
parent f7e112a3c9
commit c8cb7bdf57
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 181 additions and 125 deletions

View File

@ -8,7 +8,6 @@ license = "MIT OR Apache-2.0"
[dependencies]
argh = "0.1"
xshell = "0.2"
bitflags = "2.3"
[lints]
workspace = true

37
tools/ci/src/args.rs Normal file
View File

@ -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<usize>,
build_jobs: Option<usize>,
}
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<String> {
self.build_jobs.map(|jobs| format!("--jobs={jobs}"))
}
#[inline(always)]
pub fn test_threads(&self) -> Option<String> {
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,
}
}
}

View File

@ -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<usize>,
/// number of build jobs
#[argh(option)]
pub(crate) build_jobs: Option<usize>,
}
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<PreparedCommand<'a>> {
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<PreparedCommand<'a>> {
fn prepare<'a>(&self, sh: &'a xshell::Shell, args: Args) -> Vec<PreparedCommand<'a>> {
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),
}
}
}

View File

@ -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<PreparedCommand<'a>> {
fn prepare<'a>(&self, sh: &'a xshell::Shell, args: Args) -> Vec<PreparedCommand<'a>> {
let jobs = args.build_jobs();
vec![PreparedCommand::new::<Self>(
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.",
)]

View File

@ -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<PreparedCommand<'a>> {
fn prepare<'a>(&self, sh: &'a xshell::Shell, args: Args) -> Vec<PreparedCommand<'a>> {
let jobs = args.build_jobs();
vec![PreparedCommand::new::<Self>(
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.",
)]

View File

@ -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<PreparedCommand<'a>> {
fn prepare<'a>(&self, sh: &'a xshell::Shell, args: Args) -> Vec<PreparedCommand<'a>> {
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
}
}

View File

@ -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<PreparedCommand<'a>> {
fn prepare<'a>(&self, sh: &'a xshell::Shell, args: Args) -> Vec<PreparedCommand<'a>> {
let jobs = args.build_jobs();
vec![PreparedCommand::new::<Self>(
cmd!(sh, "cargo check --workspace"),
cmd!(sh, "cargo check --workspace {jobs...}"),
"Please fix compiler errors in output above.",
)]
}

View File

@ -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<PreparedCommand<'a>> {
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<PreparedCommand<'a>> {
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::<Self>(
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::<Self>(
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::<Self>(
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"),

View File

@ -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<PreparedCommand<'a>> {
fn prepare<'a>(&self, sh: &'a xshell::Shell, args: Args) -> Vec<PreparedCommand<'a>> {
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
}
}

View File

@ -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<PreparedCommand<'a>> {
fn prepare<'a>(&self, sh: &'a xshell::Shell, args: Args) -> Vec<PreparedCommand<'a>> {
let jobs = args.build_jobs();
vec![PreparedCommand::new::<Self>(
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.",
)

View File

@ -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<PreparedCommand<'a>> {
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<PreparedCommand<'a>> {
let no_fail_fast = args.keep_going();
let jobs = args.build_jobs();
let test_threads = args.test_threads();
vec![PreparedCommand::new::<Self>(
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.",
)]
}

View File

@ -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<PreparedCommand<'a>> {
fn prepare<'a>(&self, sh: &'a xshell::Shell, args: Args) -> Vec<PreparedCommand<'a>> {
let jobs = args.build_jobs();
vec![PreparedCommand::new::<Self>(
cmd!(sh, "cargo check --workspace --examples"),
cmd!(sh, "cargo check --workspace --examples {jobs...}"),
"Please fix compiler errors for examples in output above.",
)]
}

View File

@ -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<PreparedCommand<'a>> {
fn prepare<'a>(&self, sh: &'a xshell::Shell, _args: Args) -> Vec<PreparedCommand<'a>> {
vec![PreparedCommand::new::<Self>(
cmd!(sh, "cargo fmt --all -- --check"),
"Please run 'cargo fmt --all' to format your code.",

View File

@ -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<PreparedCommand<'a>> {
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<PreparedCommand<'a>> {
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::<Self>(
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.",
)

View File

@ -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<String> {
pub struct IntegrationTestCheckCommand {}
impl Prepare for IntegrationTestCheckCommand {
fn prepare<'a>(&self, sh: &'a xshell::Shell, _flags: Flag) -> Vec<PreparedCommand<'a>> {
fn prepare<'a>(&self, sh: &'a xshell::Shell, args: Args) -> Vec<PreparedCommand<'a>> {
let jobs = args.build_jobs();
let jobs_ref = jobs.as_ref();
get_integration_tests(sh)
.into_iter()
.map(|path| {
PreparedCommand::new::<Self>(
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.",
)
})

View File

@ -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<PreparedCommand<'a>> {
fn prepare<'a>(&self, sh: &'a xshell::Shell, _args: Args) -> Vec<PreparedCommand<'a>> {
get_integration_tests(sh)
.into_iter()
.map(|path| {

View File

@ -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<PreparedCommand<'a>> {
fn prepare<'a>(&self, sh: &'a xshell::Shell, args: Args) -> Vec<PreparedCommand<'a>> {
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
}
}

View File

@ -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<PreparedCommand<'a>> {
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<PreparedCommand<'a>> {
let no_fail_fast = args.keep_going();
let jobs = args.build_jobs();
let test_threads = args.test_threads();
vec![PreparedCommand::new::<Self>(
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.",
)]

View File

@ -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<PreparedCommand<'a>> {
fn prepare<'a>(&self, sh: &'a xshell::Shell, args: Args) -> Vec<PreparedCommand<'a>> {
let jobs = args.build_jobs();
vec![PreparedCommand::new::<Self>(
cmd!(sh, "cargo check --workspace --tests"),
cmd!(sh, "cargo check --workspace --tests {jobs...}"),
"Please fix compiler errors for tests in output above.",
)]
}

View File

@ -1,5 +1,6 @@
//! CI script used for Bevy.
mod args;
mod ci;
mod commands;
mod prepare;

View File

@ -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<PreparedCommand<'a>> {
/// fn prepare<'a>(&self, sh: &'a Shell, args: Args) -> Vec<PreparedCommand<'a>> {
/// vec![PreparedCommand::new::<Self>(
/// 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<PreparedCommand<'a>>;
}
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<PreparedCommand<'a>>;
}
/// A command with associated metadata, created from a command that implements [`Prepare`].