aboutsummaryrefslogtreecommitdiff
path: root/mingling_ci/src/cmd
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-08-18 10:52:54 +0800
committer魏曹先生 <1992414357@qq.com>2026-08-18 10:52:54 +0800
commitb47a1fb1dd5b82ba14bcf8589c5b2a604569bf19 (patch)
treea89c2ec1b4b073390cb010c1080242ffef6a37d6 /mingling_ci/src/cmd
parent0c366be05c871fcf182a1276b6637681530c2ed0 (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.rs78
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;
+ }
+}