about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJakub Beránek <berykubik@gmail.com>2025-04-17 17:14:26 +0200
committerJakub Beránek <berykubik@gmail.com>2025-04-17 17:14:26 +0200
commit1a6e0d52e5b008cfd48f78285bb3655ecfd5d73e (patch)
tree536fe90f4e4c1eb6ede77021f14011e26ea0d5fc
parent4b310338f8d2a67cbc863ee799206709e95da6b1 (diff)
downloadrust-1a6e0d52e5b008cfd48f78285bb3655ecfd5d73e.tar.gz
rust-1a6e0d52e5b008cfd48f78285bb3655ecfd5d73e.zip
Render test revisions separately
-rw-r--r--src/ci/citool/src/test_dashboard/mod.rs43
-rw-r--r--src/ci/citool/templates/test_group.askama13
2 files changed, 46 insertions, 10 deletions
diff --git a/src/ci/citool/src/test_dashboard/mod.rs b/src/ci/citool/src/test_dashboard/mod.rs
index 163e9c1acea..c16385baa3b 100644
--- a/src/ci/citool/src/test_dashboard/mod.rs
+++ b/src/ci/citool/src/test_dashboard/mod.rs
@@ -60,19 +60,27 @@ fn gather_test_suites(job_metrics: &HashMap<JobName, JobMetrics>) -> TestSuites
 
             for test in &suite.tests {
                 let test_name = normalize_test_name(&test.name, &suite_name);
-                let test_entry = suite_entry
-                    .tests
-                    .entry(test_name.clone())
-                    .or_insert_with(|| Test { name: test_name, passed: vec![], ignored: vec![] });
+                let (test_name, variant_name) = match test_name.rsplit_once('#') {
+                    Some((name, variant)) => (name.to_string(), variant.to_string()),
+                    None => (test_name, "".to_string()),
+                };
+                let test_entry = suite_entry.tests.entry(test_name.clone()).or_insert_with(|| {
+                    Test { name: test_name.clone(), revisions: Default::default() }
+                });
+                let variant_entry = test_entry
+                    .revisions
+                    .entry(variant_name)
+                    .or_insert_with(|| TestResults { passed: vec![], ignored: vec![] });
+
                 match test.outcome {
                     TestOutcome::Passed => {
-                        test_entry.passed.push(test_metadata);
+                        variant_entry.passed.push(test_metadata);
                     }
                     TestOutcome::Ignored { ignore_reason: _ } => {
-                        test_entry.ignored.push(test_metadata);
+                        variant_entry.ignored.push(test_metadata);
                     }
                     TestOutcome::Failed => {
-                        eprintln!("Warning: failed test");
+                        eprintln!("Warning: failed test {test_name}");
                     }
                 }
             }
@@ -158,12 +166,29 @@ struct TestSuite<'a> {
 }
 
 #[derive(Debug, serde::Serialize)]
-struct Test<'a> {
-    name: String,
+struct TestResults<'a> {
     passed: Vec<TestMetadata<'a>>,
     ignored: Vec<TestMetadata<'a>>,
 }
 
+#[derive(Debug, serde::Serialize)]
+struct Test<'a> {
+    name: String,
+    revisions: BTreeMap<String, TestResults<'a>>,
+}
+
+impl<'a> Test<'a> {
+    /// If this is a test without revisions, it will have a single entry in `revisions` with
+    /// an empty string as the revision name.
+    fn single_test(&self) -> Option<&TestResults<'a>> {
+        if self.revisions.len() == 1 {
+            self.revisions.iter().next().take_if(|e| e.0.is_empty()).map(|e| e.1)
+        } else {
+            None
+        }
+    }
+}
+
 #[derive(Clone, Copy, Debug, serde::Serialize)]
 struct TestMetadata<'a> {
     job: &'a str,
diff --git a/src/ci/citool/templates/test_group.askama b/src/ci/citool/templates/test_group.askama
index a0b7fa863e5..535d98e0c24 100644
--- a/src/ci/citool/templates/test_group.askama
+++ b/src/ci/citool/templates/test_group.askama
@@ -13,7 +13,18 @@
 {% if !root_tests.is_empty() %}
 <ul>
     {% for test in root_tests %}
-    <li><b>{{ test.name }}</b> ({{ test.passed.len() }} passed, {{ test.ignored.len() }} ignored)</li>
+        <li>
+        {% if let Some(result) = test.single_test() %}
+            <b>{{ test.name }}</b> ({{ result.passed.len() }} passed, {{ result.ignored.len() }} ignored)
+        {% else %}
+            <b>{{ test.name }}</b> ({{ test.revisions.len() }} revision{{ test.revisions.len() | pluralize }})
+            <ul>
+            {% for (revision, result) in test.revisions %}
+                <li>#<i>{{ revision }}</i> ({{ result.passed.len() }} passed, {{ result.ignored.len() }} ignored)</li>
+            {% endfor %}
+            </ul>
+        {% endif %}
+        </li>
     {% endfor %}
 </ul>
 {% endif %}