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