git_workty/commands/
doctor.rs1use crate::config::{config_exists, Config};
2use crate::git::{is_git_installed, is_in_git_repo, GitRepo};
3use crate::worktree::list_worktrees;
4use owo_colors::OwoColorize;
5use std::path::Path;
6use std::process::Command;
7
8pub fn execute(start_path: Option<&Path>) {
9 let mut all_ok = true;
10
11 print_check("Git installed", is_git_installed(), &mut all_ok);
12
13 let cwd = start_path
14 .map(|p| p.to_path_buf())
15 .unwrap_or_else(|| std::env::current_dir().unwrap_or_default());
16
17 let in_repo = is_in_git_repo(&cwd);
18 print_check("Inside Git repository", in_repo, &mut all_ok);
19
20 if !in_repo {
21 eprintln!(
22 "\n{}: Run this command from inside a Git repository.",
23 "hint".cyan()
24 );
25 return;
26 }
27
28 let repo = match GitRepo::discover(start_path) {
29 Ok(r) => r,
30 Err(e) => {
31 print_fail(&format!("Failed to discover repo: {}", e));
32 return;
33 }
34 };
35
36 eprintln!(" Repository root: {}", repo.root.display());
37 eprintln!(" Common dir: {}", repo.common_dir.display());
38
39 let worktrees = list_worktrees(&repo);
40 print_check("Can list worktrees", worktrees.is_ok(), &mut all_ok);
41
42 if let Ok(wts) = &worktrees {
43 eprintln!(" Found {} worktree(s)", wts.len());
44
45 let prunable: Vec<_> = wts.iter().filter(|wt| wt.prunable).collect();
46 if !prunable.is_empty() {
47 print_warn(&format!("{} prunable worktree(s) found", prunable.len()));
48 eprintln!(" {}: Run `git worktree prune` to clean up.", "hint".cyan());
49 }
50 }
51
52 print_check("Config exists", config_exists(&repo), &mut all_ok);
53
54 if config_exists(&repo) {
55 match Config::load(&repo) {
56 Ok(config) => {
57 eprintln!(" Base branch: {}", config.base);
58 eprintln!(" Workspace root: {}", config.root);
59 }
60 Err(e) => {
61 print_fail(&format!("Config parse error: {}", e));
62 all_ok = false;
63 }
64 }
65 } else {
66 eprintln!(" Using default config (no workty.toml found)");
67 }
68
69 let gh_installed = Command::new("gh")
70 .arg("--version")
71 .output()
72 .map(|o| o.status.success())
73 .unwrap_or(false);
74
75 if gh_installed {
76 eprintln!(" {} GitHub CLI (gh) available", "✓".green());
77
78 let gh_auth = Command::new("gh")
79 .args(["auth", "status"])
80 .output()
81 .map(|o| o.status.success())
82 .unwrap_or(false);
83
84 if gh_auth {
85 eprintln!(" {} GitHub CLI authenticated", "✓".green());
86 } else {
87 eprintln!(" {} GitHub CLI not authenticated", "○".yellow());
88 eprintln!(
89 " {}: Run `gh auth login` to enable PR features.",
90 "hint".cyan()
91 );
92 }
93 } else {
94 eprintln!(
95 " {} GitHub CLI (gh) not installed (optional)",
96 "○".dimmed()
97 );
98 }
99
100 eprintln!();
101 if all_ok {
102 eprintln!("{}", "All checks passed! ✓".green().bold());
103 } else {
104 eprintln!("{}", "Some checks failed. See hints above.".yellow());
105 }
106}
107
108fn print_check(name: &str, ok: bool, all_ok: &mut bool) {
109 if ok {
110 eprintln!("{} {}", "✓".green(), name);
111 } else {
112 eprintln!("{} {}", "✗".red(), name);
113 *all_ok = false;
114 }
115}
116
117fn print_fail(msg: &str) {
118 eprintln!("{} {}", "✗".red(), msg);
119}
120
121fn print_warn(msg: &str) {
122 eprintln!("{} {}", "!".yellow(), msg);
123}