Skip to main content

git_workty/commands/
doctor.rs

1use 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}