git_gardener/commands/
list.rs1use crate::error::Result;
2use crate::git::GitWorktree;
3use colored::*;
4
5pub struct ListCommand {
6 pub names_only: bool,
7}
8
9impl ListCommand {
10 pub fn new(names_only: bool) -> Self {
11 Self { names_only }
12 }
13
14 pub fn execute(&self) -> Result<()> {
15 let git_worktree = GitWorktree::new()?;
16 let worktrees = git_worktree.list_worktrees()?;
17
18 if worktrees.is_empty() {
19 if !self.names_only {
20 println!("No worktrees found.");
21 }
22 return Ok(());
23 }
24
25 if self.names_only {
26 for worktree in worktrees {
28 println!("{}", worktree.branch);
29 }
30 } else {
31 println!(
33 "{:<30} {:<50}",
34 "BRANCH".blue().bold(),
35 "PATH".blue().bold()
36 );
37 println!("{}", "-".repeat(80).bright_black());
38
39 for worktree in worktrees {
40 println!(
41 "{:<30} {:<50}",
42 worktree.branch.green(),
43 worktree.path.display().to_string().yellow()
44 );
45 }
46 }
47
48 Ok(())
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55 use tempfile::tempdir;
56 use std::fs;
57 use std::process::Command;
58
59 fn setup_git_repo_with_worktree() -> tempfile::TempDir {
60 let temp_dir = tempdir().unwrap();
61 let repo_path = temp_dir.path();
62
63 Command::new("git")
65 .args(&["init"])
66 .current_dir(repo_path)
67 .output()
68 .expect("Failed to init git repo");
69
70 Command::new("git")
72 .args(&["config", "user.name", "Test User"])
73 .current_dir(repo_path)
74 .output()
75 .unwrap();
76
77 Command::new("git")
78 .args(&["config", "user.email", "test@example.com"])
79 .current_dir(repo_path)
80 .output()
81 .unwrap();
82
83 fs::write(repo_path.join("README.md"), "# Test Repo").unwrap();
85
86 Command::new("git")
87 .args(&["add", "."])
88 .current_dir(repo_path)
89 .output()
90 .unwrap();
91
92 Command::new("git")
93 .args(&["commit", "-m", "Initial commit"])
94 .current_dir(repo_path)
95 .output()
96 .unwrap();
97
98 let worktree_path = repo_path.join("feature-test");
100 Command::new("git")
101 .args(&["worktree", "add", "-b", "feature-test", &worktree_path.to_string_lossy()])
102 .current_dir(repo_path)
103 .output()
104 .unwrap();
105
106 temp_dir
107 }
108
109 #[test]
110 fn test_list_command_new_creates_instance() {
111 let cmd = ListCommand::new(true);
113 assert_eq!(cmd.names_only, true);
114
115 let cmd = ListCommand::new(false);
116 assert_eq!(cmd.names_only, false);
117 }
118
119 #[test]
120 fn test_list_command_fails_without_git_repo() {
121 let temp_dir = tempdir().unwrap();
123 std::env::set_current_dir(temp_dir.path()).unwrap();
124
125 let cmd = ListCommand::new(false);
126 let result = cmd.execute();
127
128 assert!(result.is_err());
129 }
130
131 #[test]
132 fn test_list_command_empty_repo_shows_no_worktrees() {
133 let temp_dir = tempdir().unwrap();
135 let repo_path = temp_dir.path();
136
137 Command::new("git")
139 .args(&["init"])
140 .current_dir(repo_path)
141 .output()
142 .expect("Failed to init git repo");
143
144 std::env::set_current_dir(repo_path).unwrap();
145
146 let cmd = ListCommand::new(false);
147 let result = cmd.execute();
148
149 assert!(result.is_ok());
151 }
152
153 #[test]
154 fn test_list_command_names_only_flag() {
155 let temp_dir = setup_git_repo_with_worktree();
157 std::env::set_current_dir(temp_dir.path()).unwrap();
158
159 let cmd = ListCommand::new(true);
161 let result = cmd.execute();
162 assert!(result.is_ok());
163
164 let cmd = ListCommand::new(false);
166 let result = cmd.execute();
167 assert!(result.is_ok());
168 }
169}