workhelix_cli_common/
doctor.rs1use crate::types::{DoctorCheck, RepoInfo};
7
8pub trait DoctorChecks {
12 fn repo_info() -> RepoInfo;
14
15 fn current_version() -> &'static str;
17
18 fn tool_checks(&self) -> Vec<DoctorCheck> {
22 Vec::new()
23 }
24}
25
26pub fn run_doctor<T: DoctorChecks>(tool: &T) -> i32 {
33 let tool_name = T::repo_info().name;
34 println!("🏥 {tool_name} health check");
35 println!("{}", "=".repeat(tool_name.len() + 14));
36 println!();
37
38 let mut has_errors = false;
39 let has_warnings = false;
40
41 let tool_checks = tool.tool_checks();
43 if !tool_checks.is_empty() {
44 println!("Configuration:");
45 for check in tool_checks {
46 if check.passed {
47 println!(" ✅ {}", check.name);
48 } else {
49 println!(" ❌ {}", check.name);
50 if let Some(msg) = check.message {
51 println!(" {msg}");
52 }
53 has_errors = true;
54 }
55 }
56 println!();
57 }
58
59 if has_errors {
61 println!("❌ Issues found - see above for details");
62 1
63 } else if has_warnings {
64 println!("⚠️ Warnings found");
65 0 } else {
67 println!("✨ Everything looks healthy!");
68 0
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75
76 struct TestTool;
77
78 impl DoctorChecks for TestTool {
79 fn repo_info() -> RepoInfo {
80 RepoInfo::new("workhelix", "test-tool")
81 }
82
83 fn current_version() -> &'static str {
84 "1.0.0"
85 }
86
87 fn tool_checks(&self) -> Vec<DoctorCheck> {
88 vec![
89 DoctorCheck::pass("Test check 1"),
90 DoctorCheck::fail("Test check 2", "This is a failure"),
91 ]
92 }
93 }
94
95 #[test]
96 fn test_run_doctor() {
97 let tool = TestTool;
98 let exit_code = run_doctor(&tool);
99 assert_eq!(exit_code, 1);
101 }
102}