feat(generator): 按文件重要性对暂存差异排序
This commit is contained in:
10
Cargo.toml
10
Cargo.toml
@@ -83,11 +83,13 @@ mockall = "0.12"
|
||||
wiremock = "0.6"
|
||||
|
||||
[profile.release]
|
||||
opt-level = 3
|
||||
lto = true
|
||||
codegen-units = 1
|
||||
opt-level = "s"
|
||||
lto = "thin"
|
||||
codegen-units = 2
|
||||
panic = "abort"
|
||||
strip = true
|
||||
debug = false
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 0
|
||||
opt-level = 1
|
||||
debug = true
|
||||
|
||||
@@ -47,7 +47,7 @@ impl ContentGenerator {
|
||||
format: CommitFormat,
|
||||
language: Language,
|
||||
) -> Result<GeneratedCommit> {
|
||||
let diff = repo.get_staged_diff()
|
||||
let diff = repo.get_staged_diff_sorted()
|
||||
.context("Failed to get staged diff")?;
|
||||
|
||||
if diff.is_empty() {
|
||||
@@ -116,7 +116,7 @@ impl ContentGenerator {
|
||||
) -> Result<GeneratedCommit> {
|
||||
use dialoguer::Select;
|
||||
|
||||
let diff = repo.get_staged_diff()?;
|
||||
let diff = repo.get_staged_diff_sorted()?;
|
||||
|
||||
if diff.is_empty() {
|
||||
anyhow::bail!("No staged changes");
|
||||
|
||||
113
src/git/mod.rs
113
src/git/mod.rs
@@ -346,6 +346,119 @@ impl GitRepo {
|
||||
Ok(diff_text)
|
||||
}
|
||||
|
||||
/// Get staged diff with files sorted by importance
|
||||
/// Important files (source code) come first, then config files like Cargo.toml,
|
||||
/// then lock files like Cargo.lock
|
||||
pub fn get_staged_diff_sorted(&self) -> Result<String> {
|
||||
let diff = self.get_staged_diff()?;
|
||||
|
||||
if diff.is_empty() {
|
||||
return Ok(diff);
|
||||
}
|
||||
|
||||
let mut file_diffs = Vec::new();
|
||||
let mut current_file_diff = String::new();
|
||||
let mut current_file = String::new();
|
||||
|
||||
for line in diff.lines() {
|
||||
if line.starts_with("diff --git") {
|
||||
// Save previous file diff if any
|
||||
if !current_file_diff.is_empty() && !current_file.is_empty() {
|
||||
file_diffs.push((current_file.clone(), current_file_diff.clone()));
|
||||
}
|
||||
current_file = extract_file_from_diff_line(line);
|
||||
current_file_diff = format!("{}\n", line);
|
||||
} else {
|
||||
current_file_diff.push_str(line);
|
||||
current_file_diff.push('\n');
|
||||
}
|
||||
}
|
||||
|
||||
// Add the last file diff
|
||||
if !current_file_diff.is_empty() && !current_file.is_empty() {
|
||||
file_diffs.push((current_file, current_file_diff));
|
||||
}
|
||||
|
||||
// Sort by file importance
|
||||
file_diffs.sort_by(|a, b| {
|
||||
let score_a = file_importance_score(&a.0);
|
||||
let score_b = file_importance_score(&b.0);
|
||||
score_b.cmp(&score_a) // Descending order
|
||||
});
|
||||
|
||||
// Combine sorted diffs
|
||||
let sorted_diff: String = file_diffs.into_iter()
|
||||
.map(|(_, diff)| diff)
|
||||
.collect();
|
||||
|
||||
Ok(sorted_diff)
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract filename from diff --git line
|
||||
fn extract_file_from_diff_line(line: &str) -> String {
|
||||
// Format: "diff --git a/path/to/file b/path/to/file"
|
||||
let parts: Vec<&str> = line.split_whitespace().collect();
|
||||
if parts.len() >= 3 {
|
||||
// Return the second path (after b/)
|
||||
if let Some(path) = parts[2].strip_prefix("b/") {
|
||||
return path.to_string();
|
||||
}
|
||||
// Fallback to first path (after a/)
|
||||
if let Some(path) = parts[1].strip_prefix("a/") {
|
||||
return path.to_string();
|
||||
}
|
||||
}
|
||||
line.to_string()
|
||||
}
|
||||
|
||||
/// Calculate file importance score
|
||||
/// Higher score = more important
|
||||
fn file_importance_score(filename: &str) -> i32 {
|
||||
// Priority list for important file types
|
||||
let important_extensions = [
|
||||
".rs", ".py", ".js", ".ts", ".tsx", ".jsx", ".go", ".java", ".cpp", ".c", ".rust",
|
||||
".vue", ".svelte", ".html", ".css", ".scss", ".sass", ".less",
|
||||
];
|
||||
|
||||
// Config files that are important but less than source code
|
||||
let config_files = [
|
||||
"Cargo.toml", "package.json", "go.mod", "go.sum", "pom.xml",
|
||||
"Makefile", "CMakeLists.txt", "build.gradle", "gradle.properties",
|
||||
];
|
||||
|
||||
// Lock files - lowest priority
|
||||
let lock_files = [
|
||||
"Cargo.lock", "package-lock.json", "yarn.lock", "pnpm-lock.yaml",
|
||||
"Gemfile.lock", "composer.lock",
|
||||
];
|
||||
|
||||
// Check lock files first (lowest priority)
|
||||
for lock in lock_files.iter() {
|
||||
if filename.ends_with(lock) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Check config files (medium priority)
|
||||
for config in config_files.iter() {
|
||||
if filename.ends_with(config) {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Check important source files (highest priority)
|
||||
for ext in important_extensions.iter() {
|
||||
if filename.ends_with(ext) {
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
// Default priority for other files
|
||||
2
|
||||
}
|
||||
|
||||
impl GitRepo {
|
||||
/// Get unstaged diff
|
||||
pub fn get_unstaged_diff(&self) -> Result<String> {
|
||||
let diff = self.repo.diff_index_to_workdir(None, None)?;
|
||||
|
||||
Reference in New Issue
Block a user