use anyhow::Context;
use strum::IntoEnumIterator;
use worktrunk::HookType;
use worktrunk::config::Approvals;
use worktrunk::git::{GitError, Repository};
use worktrunk::styling::{eprintln, info_message, success_message};
use crate::commands::command_approval::approve_command_batch;
use crate::commands::project_config::{collect_commands_for_aliases, collect_commands_for_hooks};
pub fn add_approvals(show_all: bool) -> anyhow::Result<()> {
let repo = Repository::current()?;
let project_id = repo.project_identifier()?;
let approvals = Approvals::load().context("Failed to load approvals")?;
let config_path = repo
.project_config_path()?
.context("Cannot determine project config location — no worktree found")?;
let project_config = repo
.load_project_config()?
.ok_or(GitError::ProjectConfigNotFound { config_path })?;
let all_hooks: Vec<_> = HookType::iter().collect();
let mut commands = collect_commands_for_hooks(&project_config, &all_hooks);
commands.extend(collect_commands_for_aliases(&project_config));
if commands.is_empty() {
eprintln!("{}", info_message("No commands configured in project"));
return Ok(());
}
let commands_to_approve = if !show_all {
let unapproved: Vec<_> = commands
.into_iter()
.filter(|cmd| !approvals.is_command_approved(&project_id, &cmd.command.template))
.collect();
if unapproved.is_empty() {
eprintln!("{}", info_message("All commands already approved"));
return Ok(());
}
unapproved
} else {
commands
};
let approved =
approve_command_batch(&commands_to_approve, &project_id, &approvals, false, true)?;
if approved {
eprintln!("{}", success_message("Commands approved & saved to config"));
} else {
eprintln!("{}", info_message("Commands declined"));
}
Ok(())
}
pub fn clear_approvals(global: bool) -> anyhow::Result<()> {
let mut approvals = Approvals::load().context("Failed to load approvals")?;
if global {
let project_count = approvals
.projects()
.filter(|(_, cmds)| !cmds.is_empty())
.count();
if project_count == 0 {
eprintln!("{}", info_message("No approvals to clear"));
return Ok(());
}
approvals
.clear_all(None)
.context("Failed to clear approvals")?;
eprintln!(
"{}",
success_message(format!(
"Cleared approvals for {project_count} project{}",
if project_count == 1 { "" } else { "s" }
))
);
} else {
let repo = Repository::current()?;
let project_id = repo.project_identifier()?;
let approval_count = approvals
.projects()
.find(|(id, _)| *id == project_id)
.map(|(_, cmds)| cmds.len())
.unwrap_or(0);
if approval_count == 0 {
eprintln!("{}", info_message("No approvals to clear for this project"));
return Ok(());
}
approvals
.revoke_project(&project_id, None)
.context("Failed to clear project approvals")?;
eprintln!(
"{}",
success_message(format!(
"Cleared {approval_count} approval{} for this project",
if approval_count == 1 { "" } else { "s" }
))
);
}
Ok(())
}