diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-08-18 10:52:54 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-08-18 10:52:54 +0800 |
| commit | b47a1fb1dd5b82ba14bcf8589c5b2a604569bf19 (patch) | |
| tree | a89c2ec1b4b073390cb010c1080242ffef6a37d6 /mingling_ci/src/cmd | |
| parent | 0c366be05c871fcf182a1276b6637681530c2ed0 (diff) | |
feat(ci-new): add test-examples command
Add a new `test-examples` command that builds each example
and runs its `test.toml` cases, reporting failures and
setting a non-zero exit code when any example fails.
Diffstat (limited to 'mingling_ci/src/cmd')
| -rw-r--r-- | mingling_ci/src/cmd/cmd_test_examples.rs | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/mingling_ci/src/cmd/cmd_test_examples.rs b/mingling_ci/src/cmd/cmd_test_examples.rs new file mode 100644 index 0000000..2b5526f --- /dev/null +++ b/mingling_ci/src/cmd/cmd_test_examples.rs @@ -0,0 +1,78 @@ +use colored::Colorize; +use indicatif::{ProgressBar, ProgressStyle}; +use mingling::{ + Grouped, Routable, + macros::{buffer, command, renderer}, + res::ResExitCode, +}; + +use crate::Next; +use crate::examples::{check_example, load_test_configs}; +use crate::reporter::{self, ReportResult}; + +#[command(node = "test-examples")] +pub async fn test_examples() -> Next { + reporter::set_task("Test-Examples"); + + let configs = load_test_configs(); + let total = configs.len(); + let pb = ProgressBar::new(total as u64); + pb.set_style( + ProgressStyle::default_bar() + .template(&format!( + "{} [{{bar:28}}] {{pos}}/{{len}}: {{msg}}", + " Testing".bold().bright_cyan() + )) + .unwrap() + .progress_chars("=> "), + ); + pb.set_message("examples"); + + // One blocking task per example: build + run its test cases. + let mut handles = Vec::new(); + for example in configs { + handles.push(tokio::task::spawn_blocking(move || check_example(example))); + } + + let mut fail_count = 0; + for handle in handles { + let Ok(outcome) = handle.await else { + continue; + }; + pb.set_message(outcome.name.clone()); + pb.inc(1); + + if outcome.ok { + reporter::export(&outcome.name, &outcome.location, ReportResult::Ok); + } else { + fail_count += 1; + // Plain stderr: `pb.println` is swallowed on non-TTY (CI). + eprintln!(" {} {}", "failed".bright_red(), outcome.name); + eprintln!(" {}", outcome.output); + reporter::export( + &outcome.name, + &outcome.location, + ReportResult::Error(outcome.output), + ); + } + } + + pb.finish_and_clear(); + reporter::flush(); + + ResultTestExamples { fail_count }.to_chain() +} + +/// Number of examples that failed to build or pass their tests. +#[derive(Grouped)] +pub struct ResultTestExamples { + pub fail_count: usize, +} + +/// Silently sets a non-zero exit code when any example failed. +#[renderer(buffer)] +pub fn render_test_examples(r: ResultTestExamples, exit_code: &mut ResExitCode) { + if r.fail_count > 0 { + exit_code.exit_code = 1; + } +} |
