feat(changelog): 添加 --no-generate 标志以支持纯模板生成

- 新增 `--no-generate` 参数,强制使用模板生成而非 AI
- 调整 `--yes` 参数仅跳过交互提示,不改变生成行为
- 统一使用工具函数替代 println 输出
This commit is contained in:
2026-08-21 13:57:25 +08:00
parent e6b8b344aa
commit a40c88c768
22 changed files with 5709 additions and 1473 deletions

View File

@@ -11,6 +11,7 @@ use crate::git::GitRepo;
use crate::git::find_repo;
use crate::git::{CommitInfo, changelog::*};
use crate::i18n::{Messages, translate_changelog_category};
use crate::utils::{print_progress, print_success, print_warning};
/// Generate changelog
#[derive(Parser)]
@@ -60,7 +61,11 @@ pub struct ChangelogCommand {
#[arg(long)]
think: bool,
/// Skip interactive prompts
/// Generate deterministically from template (no AI call)
#[arg(long, conflicts_with = "generate")]
no_generate: bool,
/// Skip interactive prompts only (generation behavior unchanged)
#[arg(short = 'y', long)]
yes: bool,
}
@@ -85,7 +90,7 @@ impl ChangelogCommand {
.unwrap_or_else(|| PathBuf::from(&config.changelog.path));
init_changelog(&path)?;
println!("{}", messages.initialized_changelog(&format!("{:?}", path)));
print_success(&messages.initialized_changelog(&path.display().to_string()));
return Ok(());
}
@@ -101,10 +106,7 @@ impl ChangelogCommand {
Some("keep") | Some("keep-a-changelog") => ChangelogFormat::KeepAChangelog,
Some("custom") => ChangelogFormat::Custom,
None => ChangelogFormat::KeepAChangelog,
Some(f) => bail!(
"Unknown format: {}. Use: keep-a-changelog, github-releases",
f
),
Some(f) => bail!("{}", messages.unknown_changelog_format(f)),
};
// Get version
@@ -120,7 +122,7 @@ impl ChangelogCommand {
};
// Get commits
println!("{}", messages.fetching_commits());
print_progress(messages.fetching_commits());
// Determine from_tag: use explicit --from, or auto-detect from changelog
let from_tag = self.resolve_from_tag(&repo, &output_path, &messages);
@@ -130,10 +132,10 @@ impl ChangelogCommand {
bail!("{}", messages.no_commits_found());
}
println!("{}", messages.found_commits(commits.len()));
print_success(&messages.found_commits(commits.len()));
// Generate changelog
let changelog = if self.generate || (config.changelog.auto_generate && !self.yes) {
let changelog = if self.generate || (config.changelog.auto_generate && !self.no_generate) {
self.generate_with_ai(&version, &commits, &messages).await?
} else {
self.generate_with_template(format, &version, &commits, language)?
@@ -161,12 +163,12 @@ impl ChangelogCommand {
println!("{}", "─".repeat(60));
let confirm = Confirm::new()
.with_prompt(messages.write_to_file(&format!("{:?}", output_path)))
.with_prompt(messages.write_to_file(&output_path.display().to_string()))
.default(true)
.interact()?;
if !confirm {
println!("{}", messages.cancelled().yellow());
print_warning(messages.cancelled());
return Ok(());
}
}
@@ -185,7 +187,11 @@ impl ChangelogCommand {
std::fs::write(&output_path, content)?;
}
println!("{} {:?}", messages.changelog_written(), output_path);
print_success(&format!(
"{} {}",
messages.changelog_written(),
output_path.display()
));
Ok(())
}
@@ -221,12 +227,13 @@ impl ChangelogCommand {
let manager = ConfigManager::new()?;
let language = manager.get_language().unwrap_or(Language::English);
println!("{}", messages.ai_generating_changelog());
let generator = ContentGenerator::new_with_think(&manager, self.think, None).await?;
generator
let spinner = crate::utils::Spinner::start(messages.ai_generating_changelog());
let result = generator
.generate_changelog_entry(version, commits, language)
.await
.await;
spinner.finish_clear();
result
}
fn generate_with_template(