use anyhow::{Context, Result, anyhow};
use indicatif::{ProgressBar, ProgressStyle};
use std::process::Command;
use crate::config::AuthConfig;
use crate::providers::get_provider;
use crate::utils::git;
pub async fn generate_commit(dry_run: bool, amend: bool, add_all: bool) -> Result<()> {
let repo_path = std::env::current_dir()
.context("Failed to get current directory")?;
let git_dir = repo_path.join(".git");
if !git_dir.exists() {
return Err(anyhow!("Failed to open git repository. Make sure you're in a git repository."));
}
if add_all {
let output = Command::new("git")
.current_dir(&repo_path)
.args(["add", "."])
.output()
.context("Failed to execute git add command")?;
if !output.status.success() {
let error = String::from_utf8_lossy(&output.stderr);
return Err(anyhow!("Failed to add files: {}", error));
}
}
if amend {
let output = Command::new("git")
.current_dir(&repo_path)
.args(["rev-parse", "HEAD"])
.output()
.context("Failed to check for HEAD commit")?;
if !output.status.success() {
return Err(anyhow!("No commits found to amend message for"));
}
} else {
let output = Command::new("git")
.current_dir(&repo_path)
.args(["diff", "--cached", "--quiet"])
.status()
.context("Failed to check for staged changes")?;
if output.success() {
return Err(anyhow!(
"No staged changes found. Stage your changes with 'git add' first."
));
}
}
let diff = if amend {
let last_commit_diff = git::get_last_commit_diff(&repo_path)?;
let staged_diff = git::get_staged_diff(&repo_path)?;
if !staged_diff.is_empty() {
format!("{last_commit_diff}\n\n--- STAGED CHANGES ---\n\n{staged_diff}")
} else {
last_commit_diff
}
} else {
let diff = git::get_staged_diff(&repo_path)?;
if diff.is_empty() {
return Err(anyhow!("No changes to commit"));
}
diff
};
let config = AuthConfig::load()?;
let active_provider = config.get_active_provider()?;
let provider = get_provider(&active_provider)?;
let spinner = ProgressBar::new_spinner();
spinner.set_style(
ProgressStyle::default_spinner()
.tick_strings(&["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"])
.template("{spinner} Generating commit message...")
.unwrap(),
);
spinner.enable_steady_tick(std::time::Duration::from_millis(100));
let commit_message = provider.generate_commit_message(&diff).await?;
spinner.finish_and_clear();
println!("{}\n", commit_message);
if !dry_run {
if amend {
git::amend_commit(&repo_path, &commit_message)?;
println!("Commit amended successfully");
} else {
git::create_commit(&repo_path, &commit_message)?;
println!("Commit created successfully");
}
} else if amend {
println!("Dry run mode - no commit amended");
} else {
println!("Dry run mode - no commit created");
}
Ok(())
}