diff --git a/.github/scripts/publish_hive.sh b/.github/scripts/publish_hive.sh index 1873e63b73d..9ab0193ace2 100644 --- a/.github/scripts/publish_hive.sh +++ b/.github/scripts/publish_hive.sh @@ -1,22 +1,28 @@ -curl -X POST $1 \ --H 'Content-Type: application/json; charset=utf-8' \ ---data @- < 0 then [ + { + "type": "actions", + "elements": [ { - "type": "section", - "text": { - "type": "mrkdwn", - "text": $text - } + "type": "button", + "text": { + "type": "plain_text", + "text": "View full breakdown" + }, + "url": $run_url } - ] -}') -EOF + ] + } + ] else [] end) +' "$BLOCKS_FILE") + +printf '%s' "$PAYLOAD" | curl -X POST "$WEBHOOK_URL" \ +-H 'Content-Type: application/json; charset=utf-8' \ +--data @- diff --git a/.github/workflows/daily_hive_report.yaml b/.github/workflows/daily_hive_report.yaml index 741942f6f65..388b43186a3 100644 --- a/.github/workflows/daily_hive_report.yaml +++ b/.github/workflows/daily_hive_report.yaml @@ -192,7 +192,9 @@ jobs: uses: actions/upload-artifact@v4 with: name: results_daily.md - path: results.md + path: | + results.md + hive_slack_blocks.json if-no-files-found: error - name: Post results in summary @@ -224,8 +226,9 @@ jobs: ) || secrets.TEST_CHANNEL_SLACK }} + RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} run: | for webhook in $SLACK_WEBHOOKS; do - sh .github/scripts/publish_hive.sh "$webhook" results.md + bash .github/scripts/publish_hive.sh "$webhook" hive_slack_blocks.json "$RUN_URL" done echo "Sending Results" >> $GITHUB_STEP_SUMMARY diff --git a/tooling/Cargo.lock b/tooling/Cargo.lock index fceb0ba508c..896f0a45d71 100644 --- a/tooling/Cargo.lock +++ b/tooling/Cargo.lock @@ -4309,6 +4309,7 @@ dependencies = [ name = "guest_program" version = "7.0.0" dependencies = [ + "bincode", "bytes", "ethrex-blockchain", "ethrex-common 7.0.0", diff --git a/tooling/hive_report/src/main.rs b/tooling/hive_report/src/main.rs index 3f37cd7e351..773844da1b2 100644 --- a/tooling/hive_report/src/main.rs +++ b/tooling/hive_report/src/main.rs @@ -1,4 +1,5 @@ use serde::Deserialize; +use serde_json::json; use std::cmp::Ordering; use std::collections::HashMap; use std::fs::{self, File}; @@ -24,6 +25,8 @@ struct JsonFile { test_cases: std::collections::HashMap, } +const HIVE_SLACK_BLOCKS_FILE_PATH: &str = "./hive_slack_blocks.json"; + struct HiveResult { category: String, display_name: String, @@ -32,6 +35,25 @@ struct HiveResult { success_percentage: f64, } +struct CategoryResults { + name: String, + tests: Vec, +} + +impl CategoryResults { + fn total_passed(&self) -> usize { + self.tests.iter().map(|res| res.passed_tests).sum() + } + + fn total_tests(&self) -> usize { + self.tests.iter().map(|res| res.total_tests).sum() + } + + fn success_percentage(&self) -> f64 { + calculate_success_percentage(self.total_passed(), self.total_tests()) + } +} + impl HiveResult { fn new(suite: String, fork: String, passed_tests: usize, total_tests: usize) -> Self { let (category, display_name) = match suite.as_str() { @@ -109,6 +131,64 @@ fn calculate_success_percentage(passed_tests: usize, total_tests: usize) -> f64 } } +fn build_slack_blocks( + categories: &[CategoryResults], + total_passed: usize, + total_tests: usize, +) -> serde_json::Value { + let total_percentage = calculate_success_percentage(total_passed, total_tests); + let mut blocks = vec![json!({ + "type": "header", + "text": { + "type": "plain_text", + "text": format!( + "Daily Hive Coverage report — {total_passed}/{total_tests} ({total_percentage:.02}%)" + ) + } + })]; + + for category in categories { + let category_passed = category.total_passed(); + let category_total = category.total_tests(); + let category_percentage = category.success_percentage(); + let status = if category_passed == category_total { "✅" } else { "⚠️" }; + + let mut lines = vec![format!( + "*{}* {}/{} ({:.02}%) {}", + category.name, category_passed, category_total, category_percentage, status + )]; + + let mut failing_tests: Vec<_> = category + .tests + .iter() + .filter(|result| result.passed_tests < result.total_tests) + .collect(); + + failing_tests.sort_by(|a, b| { + a.success_percentage + .partial_cmp(&b.success_percentage) + .unwrap_or(Ordering::Equal) + }); + + for result in failing_tests { + lines.push(format!( + "- {}: {}/{} ({:.02}%)", + result.display_name, result.passed_tests, result.total_tests, result.success_percentage + )); + } + + blocks.push(json!({ + "type": "section", + "text": { + "type": "mrkdwn", + "text": lines.join("\n"), + }, + })); + } + + json!({ "blocks": blocks }) +} + fn aggregate_result( aggregated_results: &mut HashMap<(String, String), (usize, usize)>, result: HiveResult, @@ -238,22 +318,48 @@ fn main() -> Result<(), Box> { }) }); - let results_by_category = results.chunk_by(|a, b| a.category == b.category); + let mut grouped_results: Vec = Vec::new(); + for result in results { + if let Some(last) = grouped_results + .last_mut() + .filter(|last| last.name == result.category) + { + last.tests.push(result); + continue; + } + + let name = result.category.clone(); + grouped_results.push(CategoryResults { + name, + tests: vec![result], + }); + } - for results in results_by_category { - // print category - println!("*{}*", results[0].category); - for result in results { + for category in &grouped_results { + println!("*{}*", category.name); + for result in &category.tests { println!("\t{result}"); } println!(); } println!(); - let total_passed = results.iter().map(|r| r.passed_tests).sum::(); - let total_tests = results.iter().map(|r| r.total_tests).sum::(); + let total_passed = grouped_results + .iter() + .flat_map(|group| group.tests.iter().map(|r| r.passed_tests)) + .sum::(); + let total_tests = grouped_results + .iter() + .flat_map(|group| group.tests.iter().map(|r| r.total_tests)) + .sum::(); let total_percentage = calculate_success_percentage(total_passed, total_tests); println!("*Total: {total_passed}/{total_tests} ({total_percentage:.02}%)*"); + let slack_blocks = build_slack_blocks(&grouped_results, total_passed, total_tests); + fs::write( + HIVE_SLACK_BLOCKS_FILE_PATH, + serde_json::to_string_pretty(&slack_blocks)?, + )?; + Ok(()) }