git_iris/changes/
cli.rs

1use super::changelog::ChangelogGenerator;
2use super::releasenotes::ReleaseNotesGenerator;
3use crate::common::{CommonParams, DetailLevel};
4use crate::config::Config;
5use crate::git::GitRepo;
6use crate::ui;
7use anyhow::{Context, Result};
8use colored::Colorize;
9use std::env;
10use std::str::FromStr;
11use std::sync::Arc;
12
13/// Handles the changelog generation command.
14///
15/// This function orchestrates the process of generating a changelog based on the provided
16/// parameters. It sets up the necessary environment, creates a `GitRepo` instance,
17/// and delegates the actual generation to the `ChangelogGenerator`.
18///
19/// # Arguments
20///
21/// * `common` - Common parameters for the command, including configuration overrides.
22/// * `from` - The starting point (commit or tag) for the changelog.
23/// * `to` - The ending point for the changelog. Defaults to "HEAD" if not provided.
24/// * `repository_url` - Optional URL of the remote repository to use.
25/// * `update_file` - Whether to update the changelog file.
26/// * `changelog_path` - Optional path to the changelog file.
27/// * `version_name` - Optional version name to use instead of extracting from Git refs.
28///
29/// # Returns
30///
31/// Returns a Result indicating success or containing an error if the operation failed.
32pub async fn handle_changelog_command(
33    common: CommonParams,
34    from: String,
35    to: Option<String>,
36    repository_url: Option<String>,
37    update_file: bool,
38    changelog_path: Option<String>,
39    version_name: Option<String>,
40) -> Result<()> {
41    // Load and apply configuration
42    let mut config = Config::load()?;
43    common.apply_to_config(&mut config)?;
44
45    // Create a spinner to indicate progress
46    let spinner = ui::create_spinner("Generating changelog...");
47
48    // Ensure we're in a git repository
49    if let Err(e) = config.check_environment() {
50        ui::print_error(&format!("Error: {e}"));
51        ui::print_info("\nPlease ensure the following:");
52        ui::print_info("1. Git is installed and accessible from the command line.");
53        ui::print_info(
54            "2. You are running this command from within a Git repository or provide a repository URL with --repo.",
55        );
56        ui::print_info("3. You have set up your configuration using 'git-iris config'.");
57        return Err(e);
58    }
59
60    // Use the repository URL from command line or common params
61    let repo_url = repository_url.or(common.repository_url);
62
63    // Create a GitRepo instance based on the URL or current directory
64    let git_repo = if let Some(url) = repo_url {
65        Arc::new(GitRepo::clone_remote_repository(&url).context("Failed to clone repository")?)
66    } else {
67        let repo_path = env::current_dir()?;
68        Arc::new(GitRepo::new(&repo_path).context("Failed to create GitRepo")?)
69    };
70
71    // Keep a clone of the Arc for updating the changelog later if needed
72    let git_repo_for_update = Arc::clone(&git_repo);
73
74    // Set the default 'to' reference if not provided
75    let to = to.unwrap_or_else(|| "HEAD".to_string());
76
77    // Parse the detail level for the changelog
78    let detail_level = DetailLevel::from_str(&common.detail_level)?;
79
80    // Generate the changelog
81    let changelog =
82        ChangelogGenerator::generate(git_repo, &from, &to, &config, detail_level).await?;
83
84    // Clear the spinner and display the result
85    spinner.finish_and_clear();
86
87    println!("{}", "━".repeat(50).bright_purple());
88    println!("{}", &changelog);
89    println!("{}", "━".repeat(50).bright_purple());
90
91    // Update the changelog file if requested
92    if update_file {
93        let path = changelog_path.unwrap_or_else(|| "CHANGELOG.md".to_string());
94        let update_spinner = ui::create_spinner(&format!("Updating changelog file at {path}..."));
95
96        match ChangelogGenerator::update_changelog_file(
97            &changelog,
98            &path,
99            &git_repo_for_update,
100            &to,
101            version_name,
102        ) {
103            Ok(()) => {
104                update_spinner.finish_and_clear();
105                ui::print_success(&format!(
106                    "✨ Changelog successfully updated at {}",
107                    path.bright_green()
108                ));
109            }
110            Err(e) => {
111                update_spinner.finish_and_clear();
112                ui::print_error(&format!("Failed to update changelog file: {e}"));
113            }
114        }
115    }
116
117    Ok(())
118}
119
120/// Handles the release notes generation command.
121///
122/// This function orchestrates the process of generating release notes based on the provided
123/// parameters. It sets up the necessary environment, creates a `GitRepo` instance,
124/// and delegates the actual generation to the `ReleaseNotesGenerator`.
125///
126/// # Arguments
127///
128/// * `common` - Common parameters for the command, including configuration overrides.
129/// * `from` - The starting point (commit or tag) for the release notes.
130/// * `to` - The ending point for the release notes. Defaults to "HEAD" if not provided.
131/// * `repository_url` - Optional URL of the remote repository to use.
132/// * `version_name` - Optional version name to use instead of extracting from Git refs.
133///
134/// # Returns
135///
136/// Returns a Result indicating success or containing an error if the operation failed.
137pub async fn handle_release_notes_command(
138    common: CommonParams,
139    from: String,
140    to: Option<String>,
141    repository_url: Option<String>,
142    version_name: Option<String>,
143) -> Result<()> {
144    // Load and apply configuration
145    let mut config = Config::load()?;
146    common.apply_to_config(&mut config)?;
147
148    // Create a spinner to indicate progress
149    let spinner = ui::create_spinner("Generating release notes...");
150
151    // Check environment prerequisites
152    if let Err(e) = config.check_environment() {
153        ui::print_error(&format!("Error: {e}"));
154        ui::print_info("\nPlease ensure the following:");
155        ui::print_info("1. Git is installed and accessible from the command line.");
156        ui::print_info(
157            "2. You are running this command from within a Git repository or provide a repository URL with --repo.",
158        );
159        ui::print_info("3. You have set up your configuration using 'git-iris config'.");
160        return Err(e);
161    }
162
163    // Use the repository URL from command line or common params
164    let repo_url = repository_url.or(common.repository_url);
165
166    // Create a GitRepo instance based on the URL or current directory
167    let git_repo = if let Some(url) = repo_url {
168        Arc::new(GitRepo::clone_remote_repository(&url).context("Failed to clone repository")?)
169    } else {
170        let repo_path = env::current_dir()?;
171        Arc::new(GitRepo::new(&repo_path).context("Failed to create GitRepo")?)
172    };
173
174    // Set the default 'to' reference if not provided
175    let to = to.unwrap_or_else(|| "HEAD".to_string());
176
177    // Parse the detail level for the release notes
178    let detail_level = DetailLevel::from_str(&common.detail_level)?;
179
180    // Generate the release notes
181    let release_notes =
182        ReleaseNotesGenerator::generate(git_repo, &from, &to, &config, detail_level, version_name)
183            .await?;
184
185    // Clear the spinner and display the result
186    spinner.finish_and_clear();
187
188    println!("{}", "━".repeat(50).bright_purple());
189    println!("{}", &release_notes);
190    println!("{}", "━".repeat(50).bright_purple());
191
192    Ok(())
193}