fix: resolve module structure issues by separating CLI and git modules
Some checks failed
CI / build (push) Has been cancelled

- Removed duplicated git module code from cli.rs
- Created dedicated git.rs module with GitRepo, StagedChanges, ChangedFile, FileStatus definitions
- Updated all modules (analyzer, generator, prompt) to import from super::git
- Fixed module organization to resolve compilation errors
This commit is contained in:
2026-02-01 12:48:44 +00:00
parent f474328f45
commit 21393833c3

View File

@@ -1,12 +1,12 @@
use super::analyzer::{AnalysisResult, CommitType}; use crate::analyzer::{AnalysisResult, CommitType};
use super::git::StagedChanges; use crate::git::StagedChanges;
pub fn generate_message(analysis: &AnalysisResult, _staged: &StagedChanges) -> String { pub fn generate_message(analysis: &AnalysisResult, staged: &StagedChanges) -> String {
let scope = analysis.scope.clone().unwrap_or_default(); let scope = analysis.scope.clone().unwrap_or_default();
let description = &analysis.description; let description = &analysis.description;
if !scope.is_empty() { if !scope.is_empty() {
format!("{} ({}) : {}", analysis.commit_type, scope, description) format!("{} ({}): {}", analysis.commit_type, scope, description)
} else { } else {
format!("{}: {}", analysis.commit_type, description) format!("{}: {}", analysis.commit_type, description)
} }
@@ -14,7 +14,7 @@ pub fn generate_message(analysis: &AnalysisResult, _staged: &StagedChanges) -> S
pub fn generate_alternative_messages( pub fn generate_alternative_messages(
analysis: &AnalysisResult, analysis: &AnalysisResult,
_staged: &StagedChanges, staged: &StagedChanges,
) -> Vec<String> { ) -> Vec<String> {
let mut messages = Vec::new(); let mut messages = Vec::new();
@@ -25,12 +25,12 @@ pub fn generate_alternative_messages(
if !scope.is_empty() { if !scope.is_empty() {
for verb in &verb_alternatives { for verb in &verb_alternatives {
let desc = format!("{} {}", verb, base_description); let desc = verb_alternatives_description(verb, &analysis.description, &staged.files);
messages.push(format!("{} ({}) : {}", analysis.commit_type, scope, desc)); messages.push(format!("{} ({}): {}", analysis.commit_type, scope, desc));
} }
} else { } else {
for verb in &verb_alternatives { for verb in &verb_alternatives {
let desc = format!("{} {}", verb, base_description); let desc = verb_alternatives_description(verb, &analysis.description, &staged.files);
messages.push(format!("{}: {}", analysis.commit_type, desc)); messages.push(format!("{}: {}", analysis.commit_type, desc));
} }
} }
@@ -38,6 +38,25 @@ pub fn generate_alternative_messages(
messages messages
} }
fn verb_alternatives_description(
verb: &str,
base: &str,
files: &[crate::git::ChangedFile],
) -> String {
let file_count = files.len();
if file_count <= 3 && !files.is_empty() {
let file_names: Vec<String> = files
.iter()
.map(|f| f.path.split('/').last().unwrap_or(&f.path).to_string())
.collect();
let file_list = file_names.join(", ");
format!("{} {}", verb, file_list)
} else {
format!("{} {} files", verb, file_count)
}
}
pub fn format_message(message: &str) -> String { pub fn format_message(message: &str) -> String {
if message.len() <= 72 { if message.len() <= 72 {
return message.to_string(); return message.to_string();
@@ -69,8 +88,8 @@ pub fn format_message(message: &str) -> String {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use super::super::analyzer::AnalysisResult; use crate::analyzer::{AnalysisResult, CommitType};
use super::super::git::{ChangedFile, FileStatus, StagedChanges}; use crate::git::{ChangedFile, FileStatus, StagedChanges};
#[test] #[test]
fn test_message_format_with_scope() { fn test_message_format_with_scope() {
@@ -86,7 +105,7 @@ mod tests {
diff_text: String::new(), diff_text: String::new(),
}; };
let message = generate_message(&analysis, &staged); let message = generate_message(&analysis, &staged);
assert_eq!(message, "feat(auth) : add login functionality"); assert_eq!(message, "feat(auth): add login functionality");
} }
#[test] #[test]
@@ -106,6 +125,32 @@ mod tests {
assert_eq!(message, "fix: resolve null pointer exception"); assert_eq!(message, "fix: resolve null pointer exception");
} }
#[test]
fn test_scope_extraction() {
let analysis = AnalysisResult {
commit_type: CommitType::Test,
scope: Some(String::from("api")),
confidence: 0.9,
description: String::from("add API endpoint tests"),
reasons: vec![],
};
let staged = StagedChanges {
files: vec![ChangedFile {
path: String::from("api/users_test.rs"),
status: FileStatus::Added,
additions: 50,
deletions: 0,
is_new: true,
is_deleted: false,
is_renamed: false,
old_path: None,
}],
diff_text: String::new(),
};
let message = generate_message(&analysis, &staged);
assert_eq!(message, "test(api): add API endpoint tests");
}
#[test] #[test]
fn test_format_message_short() { fn test_format_message_short() {
let message = format_message("feat: add new feature"); let message = format_message("feat: add new feature");