git_iris/commit/
cli.rs

1use super::format_commit_result;
2use super::service::IrisCommitService;
3use crate::common::CommonParams;
4use crate::config::Config;
5use crate::context::format_commit_message;
6use crate::llm_providers::LLMProviderType;
7use crate::messages;
8use crate::tui::run_tui_commit;
9use crate::ui;
10use anyhow::{Context, Result};
11use std::str::FromStr;
12use std::sync::Arc;
13
14#[allow(clippy::fn_params_excessive_bools)] // its ok to use multiple bools here
15pub async fn handle_gen_command(
16    common: CommonParams,
17    auto_commit: bool,
18    use_gitmoji: bool,
19    print: bool,
20    verify: bool,
21) -> Result<()> {
22    let mut config = Config::load()?;
23    common.apply_to_config(&mut config)?;
24    let current_dir = std::env::current_dir()?;
25
26    let provider_type = LLMProviderType::from_str(&config.default_provider)?;
27
28    let service = Arc::new(
29        IrisCommitService::new(
30            config.clone(),
31            &current_dir.clone(),
32            provider_type,
33            use_gitmoji && config.use_gitmoji,
34            verify,
35        )
36        .context("Failed to create IrisCommitService")?,
37    );
38
39    // Check environment prerequisites
40    if let Err(e) = service.check_environment() {
41        ui::print_error(&format!("Error: {e}"));
42        ui::print_info("\nPlease ensure the following:");
43        ui::print_info("1. Git is installed and accessible from the command line.");
44        ui::print_info("2. You are running this command from within a Git repository.");
45        ui::print_info("3. You have set up your configuration using 'git-iris config'.");
46        return Err(e);
47    }
48
49    let git_info = service.get_git_info().await?;
50
51    if git_info.staged_files.is_empty() {
52        ui::print_warning(
53            "No staged changes. Please stage your changes before generating a commit message.",
54        );
55        ui::print_info("You can stage changes using 'git add <file>' or 'git add .'");
56        return Ok(());
57    }
58
59    // Run pre-commit hook before we do anything else
60    if let Err(e) = service.pre_commit() {
61        ui::print_error(&format!("Pre-commit failed: {e}"));
62        return Err(e);
63    }
64
65    let effective_instructions = common
66        .instructions
67        .unwrap_or_else(|| config.instructions.clone());
68    let preset_str = common.preset.as_deref().unwrap_or("");
69
70    // Create and start the spinner
71    let spinner = ui::create_spinner("");
72    let random_message = messages::get_waiting_message();
73    spinner.set_message(random_message.text);
74
75    // Generate an initial message
76    let initial_message = service
77        .generate_message(preset_str, &effective_instructions)
78        .await?;
79
80    // Stop the spinner
81    spinner.finish_and_clear();
82
83    if print {
84        println!("{}", format_commit_message(&initial_message));
85        return Ok(());
86    }
87
88    if auto_commit {
89        match service.perform_commit(&format_commit_message(&initial_message)) {
90            Ok(result) => {
91                let output =
92                    format_commit_result(&result, &format_commit_message(&initial_message));
93                println!("{output}");
94            }
95            Err(e) => {
96                eprintln!("Failed to commit: {e}");
97                return Err(e);
98            }
99        }
100        return Ok(());
101    }
102
103    run_tui_commit(
104        vec![initial_message],
105        effective_instructions,
106        String::from(preset_str),
107        git_info.user_name,
108        git_info.user_email,
109        service,
110        config.use_gitmoji,
111    )
112    .await?;
113
114    Ok(())
115}