use std::path::PathBuf; use clap::Parser; use indexmap::{ map::{Keys, Values}, IndexMap, }; use regex::Regex; use req::*; use stringlit::s; #[derive(Parser)] struct Args { #[arg(short, long, default_value = "REQ-.*")] allowed_requirements: String, requirements: PathBuf, test_results: PathBuf, } fn nl() -> String { s!("") } fn check_requirements( test_results: &str, output: &mut Vec, requirements: &IndexMap, allowed_requirements: &Regex, ) { for (id, requirement) in requirements { if allowed_requirements.is_match(&id) { let status = if test_results.contains(&format!("{id} succeeded")) { ":white_check_mark:" } else if test_results.contains(&format!("{id} failed")) { ":x:" } else { ":warning:" }; output.push(format!("- _{id}_ - {}: {status}", requirement.name)); } } } fn has_valid_requirements( mut requirements: Keys, allowed_requirements: &Regex, ) -> bool { requirements.any(|id| allowed_requirements.is_match(&id)) } fn has_valid_topics(mut topics: Values, allowed_requirements: &Regex) -> bool { topics.any(|topic| { has_valid_requirements(topic.requirements.keys(), allowed_requirements) || has_valid_topics(topic.subtopics.values(), allowed_requirements) }) } fn check_topics( test_results: &str, output: &mut Vec, topics: &IndexMap, allowed_requirements: &Regex, level: usize, ) { if !has_valid_topics(topics.values(), allowed_requirements) { return; } for (id, topic) in topics { if !has_valid_topics(topic.subtopics.values(), allowed_requirements) && !has_valid_requirements(topic.requirements.keys(), allowed_requirements) { continue; } output.push(format!("{} _{id}_ - {}", "#".repeat(level), topic.name)); if !topic.requirements.is_empty() { check_requirements( test_results, output, &topic.requirements, allowed_requirements, ); output.push(nl()); } if !topic.subtopics.is_empty() { check_topics( test_results, output, &topic.subtopics, allowed_requirements, level + 1, ); output.push(nl()); } } } fn main() -> anyhow::Result<()> { let Args { allowed_requirements, requirements, test_results, } = Args::parse(); let re = Regex::new(&allowed_requirements).unwrap(); let test_results = std::fs::read_to_string(test_results)?; let project: Project = serde_yaml::from_str(&std::fs::read_to_string(requirements)?)?; let mut output = vec![format!("# Test Results - {}", project.name)]; check_topics(&test_results, &mut output, &project.topics, &re, 2); let output = output.join("\n"); println!("{output}"); Ok(()) }