feat(commit): 添加提交消息模板支持
- 移除 config 命令中未使用的 List 子命令及相关显示字段 - 统一 ChangelogCommand 和 CommitCommand 的 ContentGenerator 初始化方式
This commit is contained in:
@@ -217,7 +217,7 @@ impl ChangelogCommand {
|
||||
|
||||
println!("{}", messages.ai_generating_changelog());
|
||||
|
||||
let generator = ContentGenerator::new_with_think(&manager, self.think).await?;
|
||||
let generator = ContentGenerator::new_with_think(&manager, self.think, None).await?;
|
||||
generator
|
||||
.generate_changelog_entry(version, commits, language)
|
||||
.await
|
||||
|
||||
@@ -280,7 +280,11 @@ impl CommitCommand {
|
||||
) -> Result<String> {
|
||||
let manager = ConfigManager::new()?;
|
||||
|
||||
let generator = ContentGenerator::new_with_think(&manager, self.think)
|
||||
let template = manager
|
||||
.default_profile()
|
||||
.and_then(|p| p.commit_template().map(|t| t.to_string()));
|
||||
|
||||
let generator = ContentGenerator::new_with_think(&manager, self.think, template)
|
||||
.await
|
||||
.context("Failed to initialize LLM. Use --manual for manual commit.")?;
|
||||
|
||||
|
||||
@@ -37,9 +37,6 @@ enum ConfigSubcommand {
|
||||
/// Show current configuration
|
||||
Show,
|
||||
|
||||
/// List all configuration information (with masked API keys)
|
||||
List,
|
||||
|
||||
/// Edit configuration file
|
||||
Edit,
|
||||
|
||||
@@ -167,7 +164,6 @@ impl ConfigCommand {
|
||||
pub async fn execute(&self, config_path: Option<PathBuf>) -> Result<()> {
|
||||
match &self.command {
|
||||
Some(ConfigSubcommand::Show) => self.show_config(&config_path).await,
|
||||
Some(ConfigSubcommand::List) => self.list_config(&config_path).await,
|
||||
Some(ConfigSubcommand::Edit) => self.edit_config(&config_path).await,
|
||||
Some(ConfigSubcommand::Set { key, value }) => {
|
||||
self.set_value(key, value, &config_path).await
|
||||
@@ -311,15 +307,6 @@ impl ConfigCommand {
|
||||
"no".red()
|
||||
}
|
||||
);
|
||||
println!(
|
||||
" GPG sign: {}",
|
||||
if config.commit.gpg_sign {
|
||||
"yes".green()
|
||||
} else {
|
||||
"no".red()
|
||||
}
|
||||
);
|
||||
println!(" Max subject length: {}", config.commit.max_subject_length);
|
||||
|
||||
println!("\n{}", "Tag Configuration:".bold());
|
||||
println!(" Version prefix: '{}'", config.tag.version_prefix);
|
||||
@@ -331,22 +318,6 @@ impl ConfigCommand {
|
||||
"no".red()
|
||||
}
|
||||
);
|
||||
println!(
|
||||
" GPG sign: {}",
|
||||
if config.tag.gpg_sign {
|
||||
"yes".green()
|
||||
} else {
|
||||
"no".red()
|
||||
}
|
||||
);
|
||||
println!(
|
||||
" Include changelog: {}",
|
||||
if config.tag.include_changelog {
|
||||
"yes".green()
|
||||
} else {
|
||||
"no".red()
|
||||
}
|
||||
);
|
||||
|
||||
println!("\n{}", "Language Configuration:".bold());
|
||||
let language = manager.get_language().unwrap_or(Language::English);
|
||||
@@ -378,243 +349,17 @@ impl ConfigCommand {
|
||||
"no".red()
|
||||
}
|
||||
);
|
||||
println!(
|
||||
" Include hashes: {}",
|
||||
if config.changelog.include_hashes {
|
||||
"yes".green()
|
||||
} else {
|
||||
"no".red()
|
||||
}
|
||||
);
|
||||
println!(
|
||||
" Include authors: {}",
|
||||
if config.changelog.include_authors {
|
||||
"yes".green()
|
||||
} else {
|
||||
"no".red()
|
||||
}
|
||||
);
|
||||
println!(
|
||||
" Group by type: {}",
|
||||
if config.changelog.group_by_type {
|
||||
"yes".green()
|
||||
} else {
|
||||
"no".red()
|
||||
}
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn list_config(&self, config_path: &Option<PathBuf>) -> Result<()> {
|
||||
let manager = self.get_manager(config_path)?;
|
||||
let config = manager.config();
|
||||
|
||||
println!("{}", "\nQuiCommit Configuration".bold());
|
||||
println!("{}", "═".repeat(80));
|
||||
|
||||
println!("\n{}", "📁 General Configuration:".bold().blue());
|
||||
println!(" Config file: {}", manager.path().display());
|
||||
println!("\n{}", "Security:".bold());
|
||||
println!(" Repository mappings: {} mapping(s)", config.repo_profiles.len());
|
||||
println!(
|
||||
" Default profile: {}",
|
||||
config.default_profile.as_deref().unwrap_or("(none)").cyan()
|
||||
);
|
||||
println!(" Profiles: {} profile(s)", config.profiles.len());
|
||||
println!(
|
||||
" Repository mappings: {} mapping(s)",
|
||||
config.repo_profiles.len()
|
||||
);
|
||||
|
||||
println!("\n{}", "🤖 LLM Configuration:".bold().blue());
|
||||
println!(" Provider: {}", config.llm.provider.cyan());
|
||||
println!(" Model: {}", config.llm.model.cyan());
|
||||
println!(" Base URL: {}", manager.llm_base_url());
|
||||
println!(
|
||||
" API Key: {}",
|
||||
mask_api_key(manager.get_api_key().as_deref())
|
||||
);
|
||||
println!(" Max tokens: {}", config.llm.max_tokens);
|
||||
println!(" Temperature: {}", config.llm.temperature);
|
||||
println!(" Timeout: {}s", config.llm.timeout);
|
||||
|
||||
println!("\n{}", "📝 Commit Configuration:".bold().blue());
|
||||
println!(" Format: {}", config.commit.format.to_string().cyan());
|
||||
println!(
|
||||
" Auto-generate: {}",
|
||||
if config.commit.auto_generate {
|
||||
"✓ yes".green()
|
||||
" Keyring: {}",
|
||||
if manager.keyring().is_available() {
|
||||
"available".green()
|
||||
} else {
|
||||
"✗ no".red()
|
||||
"unavailable".red()
|
||||
}
|
||||
);
|
||||
println!(
|
||||
" Allow empty: {}",
|
||||
if config.commit.allow_empty {
|
||||
"✓ yes".green()
|
||||
} else {
|
||||
"✗ no".red()
|
||||
}
|
||||
);
|
||||
println!(
|
||||
" GPG sign: {}",
|
||||
if config.commit.gpg_sign {
|
||||
"✓ yes".green()
|
||||
} else {
|
||||
"✗ no".red()
|
||||
}
|
||||
);
|
||||
println!(
|
||||
" Default scope: {}",
|
||||
config
|
||||
.commit
|
||||
.default_scope
|
||||
.as_deref()
|
||||
.unwrap_or("(none)")
|
||||
.cyan()
|
||||
);
|
||||
println!(" Max subject length: {}", config.commit.max_subject_length);
|
||||
println!(
|
||||
" Require scope: {}",
|
||||
if config.commit.require_scope {
|
||||
"✓ yes".green()
|
||||
} else {
|
||||
"✗ no".red()
|
||||
}
|
||||
);
|
||||
println!(
|
||||
" Require body: {}",
|
||||
if config.commit.require_body {
|
||||
"✓ yes".green()
|
||||
} else {
|
||||
"✗ no".red()
|
||||
}
|
||||
);
|
||||
if !config.commit.body_required_types.is_empty() {
|
||||
println!(
|
||||
" Body required types: {}",
|
||||
config.commit.body_required_types.join(", ").cyan()
|
||||
);
|
||||
}
|
||||
|
||||
println!("\n{}", "🏷️ Tag Configuration:".bold().blue());
|
||||
println!(" Version prefix: '{}'", config.tag.version_prefix.cyan());
|
||||
println!(
|
||||
" Auto-generate: {}",
|
||||
if config.tag.auto_generate {
|
||||
"✓ yes".green()
|
||||
} else {
|
||||
"✗ no".red()
|
||||
}
|
||||
);
|
||||
println!(
|
||||
" GPG sign: {}",
|
||||
if config.tag.gpg_sign {
|
||||
"✓ yes".green()
|
||||
} else {
|
||||
"✗ no".red()
|
||||
}
|
||||
);
|
||||
println!(
|
||||
" Include changelog: {}",
|
||||
if config.tag.include_changelog {
|
||||
"✓ yes".green()
|
||||
} else {
|
||||
"✗ no".red()
|
||||
}
|
||||
);
|
||||
println!(
|
||||
" Annotation template: {}",
|
||||
config
|
||||
.tag
|
||||
.annotation_template
|
||||
.as_deref()
|
||||
.unwrap_or("(none)")
|
||||
.cyan()
|
||||
);
|
||||
|
||||
println!("\n{}", "📋 Changelog Configuration:".bold().blue());
|
||||
println!(" Path: {}", config.changelog.path);
|
||||
println!(
|
||||
" Auto-generate: {}",
|
||||
if config.changelog.auto_generate {
|
||||
"✓ yes".green()
|
||||
} else {
|
||||
"✗ no".red()
|
||||
}
|
||||
);
|
||||
println!(
|
||||
" Format: {}",
|
||||
format!("{:?}", config.changelog.format).cyan()
|
||||
);
|
||||
println!(
|
||||
" Include hashes: {}",
|
||||
if config.changelog.include_hashes {
|
||||
"✓ yes".green()
|
||||
} else {
|
||||
"✗ no".red()
|
||||
}
|
||||
);
|
||||
println!(
|
||||
" Include authors: {}",
|
||||
if config.changelog.include_authors {
|
||||
"✓ yes".green()
|
||||
} else {
|
||||
"✗ no".red()
|
||||
}
|
||||
);
|
||||
println!(
|
||||
" Group by type: {}",
|
||||
if config.changelog.group_by_type {
|
||||
"✓ yes".green()
|
||||
} else {
|
||||
"✗ no".red()
|
||||
}
|
||||
);
|
||||
if !config.changelog.custom_categories.is_empty() {
|
||||
println!(
|
||||
" Custom categories: {} category(ies)",
|
||||
config.changelog.custom_categories.len()
|
||||
);
|
||||
}
|
||||
|
||||
println!("\n{}", "🎨 Theme Configuration:".bold().blue());
|
||||
println!(
|
||||
" Colors: {}",
|
||||
if config.theme.colors {
|
||||
"✓ enabled".green()
|
||||
} else {
|
||||
"✗ disabled".red()
|
||||
}
|
||||
);
|
||||
println!(
|
||||
" Icons: {}",
|
||||
if config.theme.icons {
|
||||
"✓ enabled".green()
|
||||
} else {
|
||||
"✗ disabled".red()
|
||||
}
|
||||
);
|
||||
println!(" Date format: {}", config.theme.date_format.cyan());
|
||||
|
||||
println!("\n{}", "🔒 Security:".bold().blue());
|
||||
println!(
|
||||
" Encrypt sensitive: {}",
|
||||
if config.encrypt_sensitive {
|
||||
"✓ yes".green()
|
||||
} else {
|
||||
"✗ no".red()
|
||||
}
|
||||
);
|
||||
|
||||
println!("\n{}", "🔑 Keyring:".bold().blue());
|
||||
let keyring = manager.keyring();
|
||||
if keyring.is_available() {
|
||||
println!(" Status: {}", "✓ available".green());
|
||||
println!(" Backend: {}", keyring.get_status_message());
|
||||
} else {
|
||||
println!(" Status: {}", "✗ unavailable".red());
|
||||
println!(" Note: {}", keyring.get_status_message());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -671,7 +416,22 @@ impl ConfigCommand {
|
||||
manager.set_auto_generate_commits(value == "true");
|
||||
}
|
||||
"tag.version_prefix" => manager.set_version_prefix(value.to_string()),
|
||||
"tag.auto_generate" => {
|
||||
manager.config_mut().tag.auto_generate = value == "true";
|
||||
}
|
||||
"changelog.path" => manager.set_changelog_path(value.to_string()),
|
||||
"changelog.auto_generate" => {
|
||||
manager.config_mut().changelog.auto_generate = value == "true";
|
||||
}
|
||||
"language.output_language" => {
|
||||
manager.set_output_language(value.to_string());
|
||||
}
|
||||
"language.keep_types_english" => {
|
||||
manager.set_keep_types_english(value == "true");
|
||||
}
|
||||
"language.keep_changelog_types_english" => {
|
||||
manager.set_keep_changelog_types_english(value == "true");
|
||||
}
|
||||
_ => bail!("Unknown configuration key: {}", key),
|
||||
}
|
||||
|
||||
@@ -702,7 +462,14 @@ impl ConfigCommand {
|
||||
"commit.format" => config.commit.format.to_string(),
|
||||
"commit.auto_generate" => config.commit.auto_generate.to_string(),
|
||||
"tag.version_prefix" => config.tag.version_prefix.clone(),
|
||||
"tag.auto_generate" => config.tag.auto_generate.to_string(),
|
||||
"changelog.path" => config.changelog.path.clone(),
|
||||
"changelog.auto_generate" => config.changelog.auto_generate.to_string(),
|
||||
"language.output_language" => config.language.output_language.clone(),
|
||||
"language.keep_types_english" => config.language.keep_types_english.to_string(),
|
||||
"language.keep_changelog_types_english" => {
|
||||
config.language.keep_changelog_types_english.to_string()
|
||||
}
|
||||
_ => bail!("Unknown configuration key: {}", key),
|
||||
};
|
||||
|
||||
|
||||
@@ -331,6 +331,17 @@ impl InitCommand {
|
||||
.default(ssh_dir.join("id_rsa").display().to_string())
|
||||
.interact_text()?;
|
||||
|
||||
let pub_key_path: String = Input::new()
|
||||
.with_prompt("SSH public key path (optional, leave empty to auto-detect)")
|
||||
.default(ssh_dir.join("id_rsa.pub").display().to_string())
|
||||
.allow_empty(true)
|
||||
.interact_text()?;
|
||||
let public_key_path = if pub_key_path.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(PathBuf::from(pub_key_path))
|
||||
};
|
||||
|
||||
let has_passphrase = Confirm::new()
|
||||
.with_prompt(messages.has_passphrase())
|
||||
.default(false)
|
||||
@@ -342,13 +353,38 @@ impl InitCommand {
|
||||
None
|
||||
};
|
||||
|
||||
let agent_forwarding = Confirm::new()
|
||||
.with_prompt("Enable SSH agent forwarding (-A)?")
|
||||
.default(false)
|
||||
.interact()?;
|
||||
|
||||
let known_hosts: String = Input::new()
|
||||
.with_prompt("Custom known_hosts file path (optional)")
|
||||
.allow_empty(true)
|
||||
.interact_text()?;
|
||||
let known_hosts_file = if known_hosts.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(PathBuf::from(known_hosts))
|
||||
};
|
||||
|
||||
let custom_cmd: String = Input::new()
|
||||
.with_prompt("Custom SSH command (optional, overrides all other SSH settings)")
|
||||
.allow_empty(true)
|
||||
.interact_text()?;
|
||||
let ssh_command = if custom_cmd.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(custom_cmd)
|
||||
};
|
||||
|
||||
Ok(SshConfig {
|
||||
private_key_path: Some(PathBuf::from(key_path)),
|
||||
public_key_path: None,
|
||||
public_key_path,
|
||||
passphrase,
|
||||
agent_forwarding: false,
|
||||
ssh_command: None,
|
||||
known_hosts_file: None,
|
||||
agent_forwarding,
|
||||
ssh_command,
|
||||
known_hosts_file,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -345,6 +345,13 @@ impl ProfileCommand {
|
||||
if profile.has_gpg() {
|
||||
println!(" {} GPG configured", "🔒".to_string().dimmed());
|
||||
}
|
||||
if profile.signing_key().is_some() {
|
||||
println!(
|
||||
" {} Signing key: {}",
|
||||
"🔏".to_string().dimmed(),
|
||||
profile.signing_key().unwrap().dimmed()
|
||||
);
|
||||
}
|
||||
if profile.has_tokens() {
|
||||
println!(
|
||||
" {} {} token(s)",
|
||||
@@ -596,11 +603,64 @@ impl ProfileCommand {
|
||||
println!("Organization: {}", org);
|
||||
}
|
||||
|
||||
if let Some(ref key) = profile.signing_key {
|
||||
println!("Signing key: {}", key);
|
||||
}
|
||||
|
||||
// Profile settings
|
||||
println!("\n{}", "Settings:".bold());
|
||||
println!(
|
||||
" Auto-sign commits: {}",
|
||||
if profile.settings.auto_sign_commits {
|
||||
"yes"
|
||||
} else {
|
||||
"no"
|
||||
}
|
||||
);
|
||||
println!(
|
||||
" Auto-sign tags: {}",
|
||||
if profile.settings.auto_sign_tags {
|
||||
"yes"
|
||||
} else {
|
||||
"no"
|
||||
}
|
||||
);
|
||||
if let Some(ref fmt) = profile.settings.default_commit_format {
|
||||
println!(" Default commit format: {}", fmt.to_string());
|
||||
}
|
||||
if !profile.settings.repo_patterns.is_empty() {
|
||||
println!(" Repo patterns: {:?}", profile.settings.repo_patterns);
|
||||
}
|
||||
if let Some(ref provider) = profile.settings.llm_provider {
|
||||
println!(" Preferred LLM: {}", provider);
|
||||
}
|
||||
if let Some(ref template) = profile.settings.commit_template {
|
||||
println!(" Commit template: {}", template);
|
||||
}
|
||||
|
||||
if let Some(ref ssh) = profile.ssh {
|
||||
println!("\n{}", "SSH Configuration:".bold());
|
||||
if let Some(ref path) = ssh.private_key_path {
|
||||
println!(" Private key: {:?}", path);
|
||||
}
|
||||
if let Some(ref path) = ssh.public_key_path {
|
||||
println!(" Public key: {:?}", path);
|
||||
} else if let Some(ref path) = ssh.effective_public_key_path() {
|
||||
println!(" Public key: {:?} (auto-detected)", path);
|
||||
}
|
||||
println!(
|
||||
" Agent forwarding: {}",
|
||||
if ssh.agent_forwarding { "yes" } else { "no" }
|
||||
);
|
||||
if let Some(ref cmd) = ssh.ssh_command {
|
||||
println!(" Custom command: {}", cmd);
|
||||
}
|
||||
if let Some(ref kh) = ssh.known_hosts_file {
|
||||
println!(" Known hosts file: {:?}", kh);
|
||||
}
|
||||
if ssh.passphrase.is_some() {
|
||||
println!(" Passphrase: [set]");
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref gpg) = profile.gpg {
|
||||
@@ -749,9 +809,9 @@ impl ProfileCommand {
|
||||
}
|
||||
|
||||
async fn edit_profile(&self, name: &str, config_path: &Option<PathBuf>) -> Result<()> {
|
||||
let mut manager = self.get_manager(config_path)?;
|
||||
let manager = self.get_manager(config_path)?;
|
||||
|
||||
let profile = manager
|
||||
let mut profile = manager
|
||||
.get_profile(name)
|
||||
.ok_or_else(|| anyhow::anyhow!("Profile '{}' not found", name))?
|
||||
.clone();
|
||||
@@ -772,16 +832,54 @@ impl ProfileCommand {
|
||||
})
|
||||
.interact_text()?;
|
||||
|
||||
let mut new_profile = GitProfile::new(name.to_string(), user_name, user_email);
|
||||
new_profile.description = profile.description;
|
||||
new_profile.is_work = profile.is_work;
|
||||
new_profile.organization = profile.organization;
|
||||
new_profile.ssh = profile.ssh;
|
||||
new_profile.gpg = profile.gpg;
|
||||
new_profile.tokens = profile.tokens;
|
||||
new_profile.usage = profile.usage;
|
||||
profile.user_name = user_name;
|
||||
profile.user_email = user_email;
|
||||
|
||||
manager.update_profile(name, new_profile)?;
|
||||
// Sub-menu loop for optional configuration
|
||||
loop {
|
||||
println!();
|
||||
let options = vec![
|
||||
"Done / Save changes",
|
||||
"Edit SSH configuration",
|
||||
"Edit GPG configuration",
|
||||
"Edit signing preferences",
|
||||
"Manage tokens",
|
||||
];
|
||||
let selection = Select::new()
|
||||
.with_prompt("What would you like to edit?")
|
||||
.items(&options)
|
||||
.default(0)
|
||||
.interact()?;
|
||||
|
||||
match selection {
|
||||
0 => break,
|
||||
1 => {
|
||||
profile.ssh = Some(self.setup_ssh_interactive().await?);
|
||||
}
|
||||
2 => {
|
||||
profile.gpg = Some(self.setup_gpg_interactive().await?);
|
||||
}
|
||||
3 => {
|
||||
profile.settings.auto_sign_commits = Confirm::new()
|
||||
.with_prompt("Auto-sign commits?")
|
||||
.default(profile.settings.auto_sign_commits)
|
||||
.interact()?;
|
||||
profile.settings.auto_sign_tags = Confirm::new()
|
||||
.with_prompt("Auto-sign tags?")
|
||||
.default(profile.settings.auto_sign_tags)
|
||||
.interact()?;
|
||||
}
|
||||
4 => {
|
||||
self.edit_tokens_interactive(&mut profile, &manager).await?;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
// Reload manager as mut to save
|
||||
let config_path = manager.path().to_path_buf();
|
||||
let mut manager = ConfigManager::with_path(&config_path)?;
|
||||
manager.update_profile(name, profile)?;
|
||||
manager.save()?;
|
||||
|
||||
println!("{} Profile '{}' updated", "✓".green(), name);
|
||||
@@ -789,6 +887,50 @@ impl ProfileCommand {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn edit_tokens_interactive(
|
||||
&self,
|
||||
profile: &mut GitProfile,
|
||||
manager: &ConfigManager,
|
||||
) -> Result<()> {
|
||||
loop {
|
||||
println!();
|
||||
let mut options: Vec<String> = profile
|
||||
.tokens
|
||||
.keys()
|
||||
.map(|s| format!("Remove token: {}", s))
|
||||
.collect();
|
||||
options.push("Add new token".to_string());
|
||||
options.push("Back".to_string());
|
||||
|
||||
let selection = Select::new()
|
||||
.with_prompt(format!("Manage tokens for '{}'", profile.name))
|
||||
.items(&options)
|
||||
.default(options.len() - 1)
|
||||
.interact()?;
|
||||
|
||||
if selection == options.len() - 1 {
|
||||
break;
|
||||
}
|
||||
if selection < profile.tokens.len() {
|
||||
let service: String = profile
|
||||
.tokens
|
||||
.keys()
|
||||
.nth(selection)
|
||||
.unwrap()
|
||||
.clone();
|
||||
profile.remove_token(&service);
|
||||
println!(
|
||||
"{} Token '{}' removed",
|
||||
"✓".green(),
|
||||
service.cyan()
|
||||
);
|
||||
} else {
|
||||
self.setup_token_interactive(profile, manager).await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_default(&self, name: &str, config_path: &Option<PathBuf>) -> Result<()> {
|
||||
let mut manager = self.get_manager(config_path)?;
|
||||
|
||||
@@ -1231,18 +1373,56 @@ impl ProfileCommand {
|
||||
.map(|h| h.join(".ssh"))
|
||||
.unwrap_or_else(|| PathBuf::from("~/.ssh"));
|
||||
|
||||
println!("\n{}", "SSH Configuration".bold());
|
||||
|
||||
let key_path: String = Input::new()
|
||||
.with_prompt("SSH private key path")
|
||||
.default(ssh_dir.join("id_rsa").display().to_string())
|
||||
.interact_text()?;
|
||||
|
||||
let pub_key_path: String = Input::new()
|
||||
.with_prompt("SSH public key path (optional, leave empty to auto-detect)")
|
||||
.default(ssh_dir.join("id_rsa.pub").display().to_string())
|
||||
.allow_empty(true)
|
||||
.interact_text()?;
|
||||
let public_key_path = if pub_key_path.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(PathBuf::from(pub_key_path))
|
||||
};
|
||||
|
||||
let agent_forwarding = Confirm::new()
|
||||
.with_prompt("Enable SSH agent forwarding (-A)?")
|
||||
.default(false)
|
||||
.interact()?;
|
||||
|
||||
let known_hosts: String = Input::new()
|
||||
.with_prompt("Custom known_hosts file path (optional)")
|
||||
.allow_empty(true)
|
||||
.interact_text()?;
|
||||
let known_hosts_file = if known_hosts.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(PathBuf::from(known_hosts))
|
||||
};
|
||||
|
||||
let custom_cmd: String = Input::new()
|
||||
.with_prompt("Custom SSH command (optional, overrides all other SSH settings)")
|
||||
.allow_empty(true)
|
||||
.interact_text()?;
|
||||
let ssh_command = if custom_cmd.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(custom_cmd)
|
||||
};
|
||||
|
||||
Ok(SshConfig {
|
||||
private_key_path: Some(PathBuf::from(key_path)),
|
||||
public_key_path: None,
|
||||
public_key_path,
|
||||
passphrase: None,
|
||||
agent_forwarding: false,
|
||||
ssh_command: None,
|
||||
known_hosts_file: None,
|
||||
agent_forwarding,
|
||||
ssh_command,
|
||||
known_hosts_file,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -319,7 +319,7 @@ impl TagCommand {
|
||||
|
||||
println!("{}", messages.ai_generating_tag(commits.len()));
|
||||
|
||||
let generator = ContentGenerator::new_with_think(&manager, self.think).await?;
|
||||
let generator = ContentGenerator::new_with_think(&manager, self.think, None).await?;
|
||||
generator
|
||||
.generate_tag_message(version, &commits, language)
|
||||
.await
|
||||
|
||||
Reference in New Issue
Block a user