feat(tag): 支持从多个配置文件读取版本并交互选择

将 `read_project_version` 重构为 `read_project_versions`,支持从 Cargo.toml、package.json、pyproject.toml 等多个配置文件同时读取版本。当检测到多个版本时,提供交互式选择界面让用户决定使用哪个版本。
This commit is contained in:
2026-08-07 15:41:37 +08:00
parent 35fe6e09b7
commit cc80604710
7 changed files with 397 additions and 62 deletions

View File

@@ -8,8 +8,8 @@ use std::path::PathBuf;
use crate::config::{Language, manager::ConfigManager};
use crate::generator::ContentGenerator;
use crate::git::tag::{
TagBuilder, VersionBump, bump_version, get_latest_version, read_project_version,
suggest_version_bump,
ConfigVersion, TagBuilder, VersionBump, bump_version, get_latest_version,
read_project_versions, suggest_version_bump,
};
use crate::git::{GitRepo, find_repo};
use crate::i18n::Messages;
@@ -343,14 +343,23 @@ impl TagCommand {
let project_dir = std::env::current_dir()?;
// 1. Try reading from project config files
if let Some(version) = read_project_version(&project_dir) {
let tag_name = format!("{}{}", prefix, version);
println!(
"{} {}",
messages.latest_version(),
tag_name.cyan()
);
return Ok(tag_name);
let config_versions = read_project_versions(&project_dir);
if !config_versions.is_empty() {
if config_versions.len() == 1 {
let cv = &config_versions[0];
let tag_name = format!("{}{}", prefix, cv.version);
println!(
"{} ({}): {}",
messages.found_version_in(),
cv.source,
tag_name.cyan()
);
return Ok(tag_name);
}
// Multiple config files: let user choose
return self.select_config_version(&config_versions, prefix, messages);
}
// 2. Fall back to commit analysis
@@ -385,6 +394,29 @@ impl TagCommand {
Ok(tag_name)
}
fn select_config_version(
&self,
config_versions: &[ConfigVersion],
prefix: &str,
messages: &Messages,
) -> Result<String> {
println!("\n{}", messages.found_multiple_versions().bold());
let items: Vec<String> = config_versions
.iter()
.map(|cv| format!("{}{}{}", cv.source, prefix, cv.version))
.collect();
let selection = Select::new()
.with_prompt(messages.select_version_to_use())
.items(&items)
.default(0)
.interact()?;
let cv = &config_versions[selection];
Ok(format!("{}{}", prefix, cv.version))
}
fn input_message_interactive(&self, version: &str, messages: &Messages) -> Result<String> {
let default_msg = format!("Release {}", version);