Skip to content

Commit 6c9f7f4

Browse files
committed
Fix CI
1 parent 1cea097 commit 6c9f7f4

File tree

11 files changed

+949
-159
lines changed

11 files changed

+949
-159
lines changed

src/commands/analysis.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::Result;
2+
use crate::core::git::AsyncGitOperations;
23
use crate::core::traits::*;
34
use crate::core::{git::*, output::*};
45
use chrono::{NaiveDate, Utc};

src/commands/branch.rs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,111 @@ impl Command for CleanBranchesCommand {
118118
}
119119

120120
impl GitCommand for CleanBranchesCommand {}
121+
122+
/// Async parallel version of CleanBranchesCommand
123+
pub struct AsyncCleanBranchesCommand {
124+
dry_run: bool,
125+
}
126+
127+
impl AsyncCleanBranchesCommand {
128+
pub fn new(dry_run: bool) -> Self {
129+
Self { dry_run }
130+
}
131+
132+
pub async fn execute_parallel(&self) -> Result<String> {
133+
use crate::core::{git::AsyncGitOperations, safety::Safety};
134+
135+
// Get merged branches and current branch in parallel
136+
let (merged_branches_result, current_branch_result) = tokio::try_join!(
137+
AsyncGitOperations::merged_branches(),
138+
AsyncGitOperations::current_branch()
139+
)?;
140+
141+
let branches_to_delete: Vec<String> = merged_branches_result
142+
.into_iter()
143+
.filter(|branch| branch != &current_branch_result)
144+
.filter(|branch| !Self::is_protected_branch(branch))
145+
.collect();
146+
147+
if branches_to_delete.is_empty() {
148+
return Ok("No merged branches to delete.".to_string());
149+
}
150+
151+
if self.dry_run {
152+
let mut result = format!(
153+
"🧪 (dry run) {} branches would be deleted:\n",
154+
branches_to_delete.len()
155+
);
156+
for branch in &branches_to_delete {
157+
result.push_str(&format!("(dry run) Would delete: {branch}\n"));
158+
}
159+
return Ok(result);
160+
}
161+
162+
// Confirm deletion
163+
let details = format!(
164+
"This will delete {} merged branches: {}",
165+
branches_to_delete.len(),
166+
branches_to_delete.join(", ")
167+
);
168+
169+
if !Safety::confirm_destructive_operation("Clean merged branches", &details)? {
170+
return Ok("Operation cancelled by user.".to_string());
171+
}
172+
173+
// Delete branches in parallel (but carefully)
174+
let delete_tasks = branches_to_delete
175+
.iter()
176+
.map(|branch| self.delete_branch_async(branch.clone()));
177+
178+
let results = futures::future::join_all(delete_tasks).await;
179+
180+
let mut deleted = Vec::new();
181+
let mut failed = Vec::new();
182+
183+
for (branch, result) in branches_to_delete.iter().zip(results.iter()) {
184+
match result {
185+
Ok(true) => deleted.push(branch.clone()),
186+
Ok(false) | Err(_) => failed.push(branch.clone()),
187+
}
188+
}
189+
190+
let mut result = String::new();
191+
192+
if !deleted.is_empty() {
193+
result.push_str(&format!("✅ Deleted {} branches:\n", deleted.len()));
194+
for branch in deleted {
195+
result.push_str(&format!(" 🗑️ {branch}\n"));
196+
}
197+
}
198+
199+
if !failed.is_empty() {
200+
result.push_str(&format!("❌ Failed to delete {} branches:\n", failed.len()));
201+
for branch in failed {
202+
result.push_str(&format!(" ⚠️ {branch}\n"));
203+
}
204+
}
205+
206+
Ok(result)
207+
}
208+
209+
async fn delete_branch_async(&self, branch: String) -> Result<bool> {
210+
use crate::core::git::AsyncGitOperations;
211+
212+
match AsyncGitOperations::run_status(&["branch", "-d", &branch]).await {
213+
Ok(_) => Ok(true),
214+
Err(_) => Ok(false),
215+
}
216+
}
217+
218+
fn get_protected_branches() -> Vec<&'static str> {
219+
vec!["main", "master", "develop"]
220+
}
221+
222+
fn is_protected_branch(branch: &str) -> bool {
223+
Self::get_protected_branches().contains(&branch)
224+
}
225+
}
121226
impl DryRunnable for CleanBranchesCommand {
122227
fn execute_dry_run(&self) -> Result<String> {
123228
CleanBranchesCommand::new(true).execute()

0 commit comments

Comments
 (0)