ferrous_forge/safety/checks/
doc.rs1use crate::Result;
4use std::path::Path;
5use std::process::Command;
6use std::time::Instant;
7
8use super::SafetyCheck;
9use crate::safety::{CheckType, report::CheckResult};
10
11pub struct DocCheck;
13
14impl SafetyCheck for DocCheck {
15 async fn run(project_path: &Path) -> Result<CheckResult> {
16 run(project_path).await
17 }
18
19 fn name() -> &'static str {
20 "doc"
21 }
22
23 fn description() -> &'static str {
24 "Builds project documentation"
25 }
26}
27
28pub async fn run(project_path: &Path) -> Result<CheckResult> {
34 let start = Instant::now();
35 let mut result = CheckResult::new(CheckType::Doc);
36
37 match Command::new("cargo")
38 .args(["doc", "--no-deps"])
39 .current_dir(project_path)
40 .output()
41 {
42 Ok(output) => {
43 if !output.status.success() {
44 let stderr = String::from_utf8_lossy(&output.stderr);
45 result.add_error(&format!("cargo doc failed: {stderr}"));
46 result.fail();
47 } else {
48 result.add_context("Documentation built successfully");
49 }
50 }
51 Err(e) => {
52 result.add_error(&format!("Failed to execute cargo doc: {e}"));
53 result.fail();
54 }
55 }
56
57 result.set_duration(start.elapsed());
58 Ok(result)
59}
60
61pub async fn coverage_check(project_path: &Path) -> Result<CheckResult> {
67 let start = Instant::now();
68 let mut result = CheckResult::new(CheckType::DocCoverage);
69
70 let coverage = crate::doc_coverage::check_documentation_coverage(project_path).await?;
71 let threshold = 50.0;
72
73 if !coverage.meets_threshold(threshold) {
74 result.add_error(&format!(
75 "Documentation coverage {:.1}% is below the {:.0}% threshold",
76 coverage.coverage_percent, threshold
77 ));
78 result.fail();
79 }
80
81 result.add_context(&format!(
82 "Documentation coverage: {:.1}% ({}/{} items documented)",
83 coverage.coverage_percent, coverage.documented_items, coverage.total_items
84 ));
85
86 result.set_duration(start.elapsed());
87 Ok(result)
88}