use crate::cli::output::Output;
use crate::errors::{CascadeError, Result};
use crate::git::GitRepository;
use chrono::{DateTime, Utc};
use std::env;
pub async fn run(execute: bool, force: bool) -> Result<()> {
let repo_path = env::current_dir()
.map_err(|e| CascadeError::config(format!("Failed to get current directory: {e}")))?;
let git_repo = GitRepository::open(&repo_path)?;
Output::section("๐งน Scanning for orphaned temporary branches");
let all_branches = git_repo.list_branches()?;
let temp_branches: Vec<String> = all_branches
.iter()
.filter(|b| b.contains("-temp-"))
.cloned()
.collect();
if temp_branches.is_empty() {
Output::success("โ No orphaned temporary branches found");
return Ok(());
}
Output::info(format!("Found {} temporary branches:", temp_branches.len()));
for branch_name in &temp_branches {
let branch_info = analyze_temp_branch(&git_repo, branch_name)?;
Output::sub_item(format!(" {} {}", branch_name, branch_info));
}
println!();
if !execute {
Output::warning("๐ DRY RUN MODE - No branches will be deleted");
Output::info("Run with --execute to actually delete these branches");
Output::info("Use --force to delete branches with unmerged commits");
return Ok(());
}
Output::section(format!(
"Deleting {} temporary branches...",
temp_branches.len()
));
let mut deleted = 0;
let mut failed = 0;
for branch_name in &temp_branches {
match git_repo.delete_branch_unsafe(branch_name) {
Ok(_) => {
Output::success(format!("โ Deleted: {}", branch_name));
deleted += 1;
}
Err(e) if !force => {
Output::warning(format!("โ ๏ธ Skipped: {} ({})", branch_name, e));
Output::sub_item(" Use --force to delete branches with unmerged commits");
failed += 1;
}
Err(e) => {
Output::error(format!("โ Failed to delete: {} ({})", branch_name, e));
failed += 1;
}
}
}
println!();
if deleted > 0 {
Output::success(format!("โ Successfully deleted {} branches", deleted));
}
if failed > 0 {
Output::warning(format!("โ ๏ธ {} branches could not be deleted", failed));
}
Ok(())
}
fn analyze_temp_branch(git_repo: &GitRepository, branch_name: &str) -> Result<String> {
let parts: Vec<&str> = branch_name.split("-temp-").collect();
if parts.len() == 2 {
if let Ok(timestamp) = parts[1].parse::<i64>() {
if let Some(created_at) = DateTime::from_timestamp(timestamp, 0) {
let now = Utc::now();
let age = now.signed_duration_since(created_at);
if age.num_days() > 0 {
return Ok(format!("(created {} days ago)", age.num_days()));
} else if age.num_hours() > 0 {
return Ok(format!("(created {} hours ago)", age.num_hours()));
} else {
return Ok(format!("(created {} minutes ago)", age.num_minutes()));
}
}
}
}
match git_repo.get_branch_commit_hash(branch_name) {
Ok(commit_hash) => Ok(format!("(commit: {})", &commit_hash[..8])),
Err(_) => Ok("(orphaned)".to_string()),
}
}