use metacrate_ci_matrix::{ audit, audit_api_surface, audit_artifacts, audit_consolidated_ci, audit_dependencies, audit_documentation, audit_provenance, audit_release_candidate, load, run, run_release_gate, run_required_gate, workspace_root, write_api_baseline, write_documentation_report, write_provenance_reports, }; use std::path::{Path, PathBuf}; fn main() { if let Err(error) = execute() { eprintln!("ci-matrix: {error}"); std::process::exit(1); } } #[allow(clippy::too_many_lines)] // Flat CLI command routing is clearer than nested dispatch. fn execute() -> Result<(), Box> { let current = std::env::current_dir()?; let root = workspace_root(¤t).ok_or("could not locate the Cargo workspace")?; let matrix = load(&root)?; let mut arguments = std::env::args().skip(1); match arguments.next().as_deref() { Some("ci-audit") if arguments.next().is_none() => { audit_consolidated_ci(&root)?; println!("consolidated CI coverage and workflow split: ok"); } Some("required-gate") => { gate_command(&root, arguments, "required", run_required_gate)?; } Some("release-gate") => { gate_command(&root, arguments, "release", run_release_gate)?; } Some("audit") if arguments.next().is_none() => { audit(&root, &matrix)?; println!( "release CI matrix: {} validated profiles; Linux, Windows, macOS, MSRV, stable, default/minimal/optional features, tests, examples, and docs covered", matrix.profiles.len() ); } Some("run") => { let profile = arguments.next().ok_or("run requires a profile")?; let flag = arguments.next().ok_or("run requires --evidence FILE")?; let evidence = arguments.next().ok_or("run requires --evidence FILE")?; if flag != "--evidence" || arguments.next().is_some() { return Err("usage: ci-matrix run PROFILE --evidence FILE".into()); } let evidence = absolute_or_rooted(&root, &evidence); run(&root, &matrix, &profile, &evidence)?; println!("release CI profile {profile}: ok ({})", evidence.display()); } Some("dependency-audit") => { let flag = arguments .next() .ok_or("dependency-audit requires --evidence FILE")?; let evidence = arguments .next() .ok_or("dependency-audit requires --evidence FILE")?; if flag != "--evidence" || arguments.next().is_some() { return Err("usage: ci-matrix dependency-audit --evidence FILE".into()); } let evidence = absolute_or_rooted(&root, &evidence); audit_dependencies(&root, &evidence)?; println!("dependency policy: ok ({})", evidence.display()); } Some("artifact-audit") => { artifact_audit_command(&root, arguments)?; } Some("release-candidate-audit") => { release_candidate_audit_command(&root, arguments)?; } Some("documentation-report") if arguments.next().is_none() => { write_documentation_report(&root)?; println!("documentation coverage report: updated"); } Some("documentation-audit") => { let flag = arguments .next() .ok_or("documentation-audit requires --evidence FILE")?; let evidence = arguments .next() .ok_or("documentation-audit requires --evidence FILE")?; if flag != "--evidence" || arguments.next().is_some() { return Err("usage: ci-matrix documentation-audit --evidence FILE".into()); } let evidence = absolute_or_rooted(&root, &evidence); audit_documentation(&root, &evidence)?; println!("documentation coverage: ok ({})", evidence.display()); } Some("api-baseline-write") if arguments.next().is_none() => { write_api_baseline(&root)?; println!("API/SemVer baseline and report: updated"); } Some("api-audit") => { let flag = arguments .next() .ok_or("api-audit requires --evidence FILE")?; let evidence = arguments .next() .ok_or("api-audit requires --evidence FILE")?; if flag != "--evidence" || arguments.next().is_some() { return Err("usage: ci-matrix api-audit --evidence FILE".into()); } let evidence = absolute_or_rooted(&root, &evidence); audit_api_surface(&root, &evidence)?; println!("API/SemVer surface: ok ({})", evidence.display()); } Some("provenance-report") if arguments.next().is_none() => { write_provenance_reports(&root)?; println!("provenance and distribution reports: updated"); } Some("provenance-audit") => { provenance_audit_command(&root, arguments)?; } _ => { return Err( "usage: ci-matrix ci-audit | required-gate --evidence FILE | release-gate --evidence FILE | audit | run PROFILE --evidence FILE | dependency-audit --evidence FILE | artifact-audit --artifact-dir DIR --package-dir DIR --evidence FILE | release-candidate-audit --evidence FILE | documentation-report | documentation-audit --evidence FILE | api-baseline-write | api-audit --evidence FILE | provenance-report | provenance-audit --evidence FILE" .into(), ); } } Ok(()) } fn gate_command( root: &Path, mut arguments: impl Iterator, gate: &str, run_gate: fn(&Path, &Path) -> metacrate_ci_matrix::Result<()>, ) -> Result<(), Box> { let flag = arguments .next() .ok_or_else(|| format!("{gate}-gate requires --evidence FILE"))?; let evidence = arguments .next() .ok_or_else(|| format!("{gate}-gate requires --evidence FILE"))?; if flag != "--evidence" || arguments.next().is_some() { return Err(format!("usage: ci-matrix {gate}-gate --evidence FILE").into()); } let evidence = absolute_or_rooted(root, &evidence); run_gate(root, &evidence)?; println!("{gate} CI gate: ok ({})", evidence.display()); Ok(()) } fn release_candidate_audit_command( root: &Path, mut arguments: impl Iterator, ) -> Result<(), Box> { let flag = arguments .next() .ok_or("release-candidate-audit requires --evidence FILE")?; let evidence = arguments .next() .ok_or("release-candidate-audit requires --evidence FILE")?; if flag != "--evidence" || arguments.next().is_some() { return Err("usage: ci-matrix release-candidate-audit --evidence FILE".into()); } let evidence = absolute_or_rooted(root, &evidence); audit_release_candidate(root, &evidence)?; println!("first release candidate: ok ({})", evidence.display()); Ok(()) } fn artifact_audit_command( root: &Path, mut arguments: impl Iterator, ) -> Result<(), Box> { let artifact_dir = option(&mut arguments, "--artifact-dir")?; let package_dir = option(&mut arguments, "--package-dir")?; let evidence = option(&mut arguments, "--evidence")?; if arguments.next().is_some() { return Err( "usage: ci-matrix artifact-audit --artifact-dir DIR --package-dir DIR --evidence FILE" .into(), ); } let artifact_dir = absolute_or_rooted(root, &artifact_dir); let package_dir = absolute_or_rooted(root, &package_dir); let evidence = absolute_or_rooted(root, &evidence); audit_artifacts(root, &artifact_dir, &package_dir, &evidence)?; println!("native release artifacts: ok ({})", evidence.display()); Ok(()) } fn option( arguments: &mut impl Iterator, expected: &str, ) -> Result> { let flag = arguments .next() .ok_or_else(|| format!("missing {expected}"))?; if flag != expected { return Err(format!("expected {expected}, found {flag}").into()); } arguments .next() .ok_or_else(|| format!("missing value for {expected}").into()) } fn provenance_audit_command( root: &Path, mut arguments: impl Iterator, ) -> Result<(), Box> { let flag = arguments .next() .ok_or("provenance-audit requires --evidence FILE")?; let evidence = arguments .next() .ok_or("provenance-audit requires --evidence FILE")?; if flag != "--evidence" || arguments.next().is_some() { return Err("usage: ci-matrix provenance-audit --evidence FILE".into()); } let evidence = absolute_or_rooted(root, &evidence); audit_provenance(root, &evidence)?; println!( "license and provenance surface: ok ({})", evidence.display() ); Ok(()) } fn absolute_or_rooted(root: &Path, value: &str) -> PathBuf { let path = PathBuf::from(value); if path.is_absolute() { path } else { root.join(path) } }