1use std::process::Command;
2
3pub fn run(dry_run: bool) {
4 let output = Command::new("git")
5 .args(get_git_branch_args())
6 .output()
7 .expect("Failed to list merged branches");
8
9 let stdout = String::from_utf8_lossy(&output.stdout);
10 let branches: Vec<String> = stdout
11 .lines()
12 .map(clean_branch_name)
13 .filter(|branch| !is_protected_branch(branch))
14 .collect();
15
16 let mut deleted = Vec::new();
17
18 for branch in branches {
19 if dry_run {
20 println!("{}", format_dry_run_message(&branch));
21 deleted.push(branch);
22 } else {
23 let delete_args = get_git_delete_args(&branch);
24 let status = Command::new("git")
25 .args(delete_args)
26 .status()
27 .expect("Failed to delete branch");
28
29 if status.success() {
30 deleted.push(branch);
31 }
32 }
33 }
34
35 if deleted.is_empty() {
36 println!("{}", format_no_branches_message());
37 } else {
38 println!("{}", format_deletion_summary(deleted.len(), dry_run));
39 for branch in deleted {
40 println!(" {branch}");
41 }
42 }
43}
44
45pub fn get_git_branch_args() -> [&'static str; 2] {
47 ["branch", "--merged"]
48}
49
50const PROTECTED_BRANCHES: &[&str] = &["main", "master", "develop"];
52
53pub fn get_protected_branches() -> &'static [&'static str] {
54 PROTECTED_BRANCHES
55}
56
57pub fn clean_branch_name(line: &str) -> String {
59 line.trim().trim_start_matches('*').trim().to_string()
60}
61
62pub fn is_protected_branch(branch: &str) -> bool {
64 PROTECTED_BRANCHES.contains(&branch)
65}
66
67pub fn get_git_delete_args(branch: &str) -> [&str; 3] {
69 ["branch", "-d", branch]
70}
71
72pub fn format_dry_run_message(branch: &str) -> String {
74 format!("(dry run) Would delete: {branch}")
75}
76
77pub fn format_no_branches_message() -> &'static str {
79 "No merged branches to delete."
80}
81
82pub fn format_deletion_summary(count: usize, dry_run: bool) -> String {
84 if dry_run {
85 format!("🧪 (dry run) {count} branches would be deleted:")
86 } else {
87 format!("🧹 Deleted {count} merged branches:")
88 }
89}