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!("\n{}: Run this command from inside a Git repository.", "hint".cyan());
22 return;
23 }
24
25 let repo = match GitRepo::discover(start_path) {
26 Ok(r) => r,
27 Err(e) => {
28 print_fail(&format!("Failed to discover repo: {}", e));
29 return;
30 }
31 };
32
33 eprintln!(" Repository root: {}", repo.root.display());
34 eprintln!(" Common dir: {}", repo.common_dir.display());
35
36 let worktrees = list_worktrees(&repo);
37 print_check("Can list worktrees", worktrees.is_ok(), &mut all_ok);
38
39 if let Ok(wts) = &worktrees {
40 eprintln!(" Found {} worktree(s)", wts.len());
41
42 let prunable: Vec<_> = wts.iter().filter(|wt| wt.prunable).collect();
43 if !prunable.is_empty() {
44 print_warn(&format!("{} prunable worktree(s) found", prunable.len()));
45 eprintln!(
46 " {}: Run `git worktree prune` to clean up.",
47 "hint".cyan()
48 );
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!(" {}: Run `gh auth login` to enable PR features.", "hint".cyan());
89 }
90 } else {
91 eprintln!(" {} GitHub CLI (gh) not installed (optional)", "○".dimmed());
92 }
93
94 eprintln!();
95 if all_ok {
96 eprintln!("{}", "All checks passed! ✓".green().bold());
97 } else {
98 eprintln!("{}", "Some checks failed. See hints above.".yellow());
99 }
100}
101
102fn print_check(name: &str, ok: bool, all_ok: &mut bool) {
103 if ok {
104 eprintln!("{} {}", "✓".green(), name);
105 } else {
106 eprintln!("{} {}", "✗".red(), name);
107 *all_ok = false;
108 }
109}
110
111fn print_fail(msg: &str) {
112 eprintln!("{} {}", "✗".red(), msg);
113}
114
115fn print_warn(msg: &str) {
116 eprintln!("{} {}", "!".yellow(), msg);
117}