release_kit/commands/
doctor.rs1use serde::Serialize;
9
10use crate::cli::doctor::DoctorArgs;
11use crate::error::RkError;
12use crate::output::Output;
13use crate::probes::{self, ProbeClass, ProbeResult, ProbeStatus};
14
15#[derive(Debug, Serialize)]
17struct Report {
18 schema: &'static str,
20 probes: Vec<ProbeResult>,
22 next: Vec<String>,
24}
25
26pub fn run(args: &DoctorArgs) -> Result<(), RkError> {
33 let out = Output::new(args.json);
34 let probes = probes::run_all();
35 let next = vec!["rk usage lists every verb and flag in one call".to_owned()];
36
37 for class in [ProbeClass::Hard, ProbeClass::Soft] {
38 out.result_line(match class {
39 ProbeClass::Hard => "hard",
40 ProbeClass::Soft => "soft",
41 });
42 for probe in probes.iter().filter(|probe| probe.class == class) {
43 let status = match probe.status {
44 ProbeStatus::Ok => "ok ",
45 ProbeStatus::Failed => "failed",
46 };
47 out.result_line(format!(" {status} {}: {}", probe.id, probe.message));
48 if let Some(remediation) = &probe.remediation {
49 out.result_line(format!(" next: {remediation}"));
50 }
51 }
52 }
53 out.next(&next);
54
55 out.emit(&Report {
56 schema: "rk.doctor/1",
57 probes,
58 next,
59 })
60}
61
62#[cfg(test)]
63mod tests {
64 #![allow(clippy::expect_used)]
65
66 use crate::probes::{ProbeClass, ProbeResult, ProbeStatus};
67
68 #[test]
70 fn the_doctor_report_schema_snapshot_holds() {
71 let report = super::Report {
72 schema: "rk.doctor/1",
73 probes: vec![ProbeResult {
74 id: "sh",
75 class: ProbeClass::Hard,
76 status: ProbeStatus::Ok,
77 message: "sh runs".into(),
78 remediation: None,
79 }],
80 next: vec!["rk usage lists every verb and flag in one call".into()],
81 };
82 assert_eq!(
83 serde_json::to_string(&report).expect("a report serializes"),
84 r#"{"schema":"rk.doctor/1","probes":[{"id":"sh","class":"hard","status":"ok","message":"sh runs"}],"next":["rk usage lists every verb and flag in one call"]}"#
85 );
86 }
87
88 #[test]
90 fn the_probe_schema_snapshot_holds() {
91 let ok = ProbeResult {
92 id: "sh",
93 class: ProbeClass::Hard,
94 status: ProbeStatus::Ok,
95 message: "sh runs".into(),
96 remediation: None,
97 };
98 assert_eq!(
99 serde_json::to_string(&ok).expect("a probe serializes"),
100 r#"{"id":"sh","class":"hard","status":"ok","message":"sh runs"}"#
101 );
102 let failed = ProbeResult {
103 id: "gh-auth",
104 class: ProbeClass::Soft,
105 status: ProbeStatus::Failed,
106 message: "gh is not authenticated".into(),
107 remediation: Some("run gh auth login".into()),
108 };
109 assert_eq!(
110 serde_json::to_string(&failed).expect("a probe serializes"),
111 r#"{"id":"gh-auth","class":"soft","status":"failed","message":"gh is not authenticated","remediation":"run gh auth login"}"#
112 );
113 }
114}