3 Commits

Author SHA1 Message Date
c9073ff4a7 feat(profile):应用配置文件时自动设置GPG签名和SSH配置
♻️ refactor(generator):移除未使用的导入和剪贴板功能
♻️ refactor(git):清理未使用的导入和优化代码结构
♻️ refactor(i18n):简化翻译模块的导出结构
♻️ refactor(llm):移除未使用的序列化导入
♻️ refactor(openrouter):简化模型验证函数
2026-02-04 10:57:15 +08:00
88324c21c2 fix: 增强 GPG 签名失败时的错误提示 2026-02-02 14:57:54 +08:00
ffc9741d1e refactor(git): 移除重复的 git commit 命令并添加 tempfile 导入 2026-02-02 14:50:12 +08:00
11 changed files with 80 additions and 39 deletions

View File

@@ -350,8 +350,23 @@ impl CommitCommand {
.output()?; .output()?;
if !output.status.success() { if !output.status.success() {
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr); let stderr = String::from_utf8_lossy(&output.stderr);
bail!("Failed to amend commit: {}", stderr);
let error_msg = if stderr.is_empty() {
if stdout.is_empty() {
"GPG signing failed. Please check:\n\
1. GPG signing key is configured (git config --get user.signingkey)\n\
2. GPG agent is running\n\
3. You can sign commits manually (try: git commit --amend -S)".to_string()
} else {
stdout.to_string()
}
} else {
stderr.to_string()
};
bail!("Failed to amend commit: {}", error_msg);
} }
Ok(()) Ok(())

View File

@@ -437,10 +437,18 @@ impl ProfileCommand {
let repo_path = repo.path().to_string_lossy().to_string(); let repo_path = repo.path().to_string_lossy().to_string();
manager.set_repo_profile(repo_path, name.to_string())?; manager.set_repo_profile(repo_path.clone(), name.to_string())?;
// Get the profile and apply it to the repository
let profile = manager.get_profile(name)
.ok_or_else(|| anyhow::anyhow!("Profile '{}' not found", name))?;
profile.apply_to_repo(repo.inner())?;
manager.record_profile_usage(name, Some(repo_path))?;
manager.save()?; manager.save()?;
println!("{} Set '{}' for current repository", "".green(), name.cyan()); println!("{} Set '{}' for current repository", "".green(), name.cyan());
println!("{} Applied profile '{}' to current repository", "".green(), name.cyan());
Ok(()) Ok(())
} }

View File

@@ -194,6 +194,21 @@ impl GitProfile {
if let Some(key) = self.signing_key() { if let Some(key) = self.signing_key() {
config.set_str("user.signingkey", key)?; config.set_str("user.signingkey", key)?;
if self.settings.auto_sign_commits {
config.set_bool("commit.gpgsign", true)?;
}
if self.settings.auto_sign_tags {
config.set_bool("tag.gpgsign", true)?;
}
}
if let Some(ref ssh) = self.ssh {
if let Some(ref key_path) = ssh.private_key_path {
config.set_str("core.sshCommand",
&format!("ssh -i {}", key_path.display()))?;
}
} }
Ok(()) Ok(())

View File

@@ -2,7 +2,6 @@ use crate::config::{CommitFormat, LlmConfig, Language};
use crate::git::{CommitInfo, GitRepo}; use crate::git::{CommitInfo, GitRepo};
use crate::llm::{GeneratedCommit, LlmClient}; use crate::llm::{GeneratedCommit, LlmClient};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use chrono::Utc;
/// Content generator using LLM /// Content generator using LLM
pub struct ContentGenerator { pub struct ContentGenerator {
@@ -114,8 +113,7 @@ impl ContentGenerator {
format: CommitFormat, format: CommitFormat,
language: Language, language: Language,
) -> Result<GeneratedCommit> { ) -> Result<GeneratedCommit> {
use dialoguer::{Confirm, Select}; use dialoguer::Select;
use console::Term;
let diff = repo.get_staged_diff()?; let diff = repo.get_staged_diff()?;
@@ -145,7 +143,6 @@ impl ContentGenerator {
"✓ Accept and commit", "✓ Accept and commit",
"🔄 Regenerate", "🔄 Regenerate",
"✏️ Edit", "✏️ Edit",
"📋 Copy to clipboard",
"❌ Cancel", "❌ Cancel",
]; ];
@@ -165,24 +162,13 @@ impl ContentGenerator {
let edited = crate::utils::editor::edit_content(&generated.to_conventional())?; let edited = crate::utils::editor::edit_content(&generated.to_conventional())?;
generated = self.parse_edited_commit(&edited, format)?; generated = self.parse_edited_commit(&edited, format)?;
} }
3 => { 3 => anyhow::bail!("Cancelled by user"),
#[cfg(feature = "clipboard")]
{
arboard::Clipboard::new()?.set_text(generated.to_conventional())?;
println!("Copied to clipboard!");
}
#[cfg(not(feature = "clipboard"))]
{
println!("Clipboard feature not enabled");
}
}
4 => anyhow::bail!("Cancelled by user"),
_ => {} _ => {}
} }
} }
} }
fn parse_edited_commit(&self, edited: &str, format: CommitFormat) -> Result<GeneratedCommit> { fn parse_edited_commit(&self, edited: &str, _format: CommitFormat) -> Result<GeneratedCommit> {
let parsed = crate::git::commit::parse_commit_message(edited); let parsed = crate::git::commit::parse_commit_message(edited);
Ok(GeneratedCommit { Ok(GeneratedCommit {

View File

@@ -1,6 +1,6 @@
use super::{CommitInfo, GitRepo}; use super::{CommitInfo, GitRepo};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use chrono::{DateTime, TimeZone, Utc}; use chrono::{DateTime, Utc};
use std::collections::HashMap; use std::collections::HashMap;
use std::fs; use std::fs;
use std::path::Path; use std::path::Path;
@@ -232,8 +232,6 @@ impl ChangelogGenerator {
let mut breaking = vec![]; let mut breaking = vec![];
for commit in commits { for commit in commits {
let msg = commit.subject();
if commit.message.contains("BREAKING CHANGE") { if commit.message.contains("BREAKING CHANGE") {
breaking.push(commit); breaking.push(commit);
} }

View File

@@ -1,5 +1,5 @@
use super::GitRepo; use super::GitRepo;
use anyhow::{bail, Context, Result}; use anyhow::{bail, Result};
use chrono::Local; use chrono::Local;
/// Commit builder for creating commits /// Commit builder for creating commits
@@ -174,8 +174,23 @@ impl CommitBuilder {
.output()?; .output()?;
if !output.status.success() { if !output.status.success() {
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr); let stderr = String::from_utf8_lossy(&output.stderr);
bail!("Failed to amend commit: {}", stderr);
let error_msg = if stderr.is_empty() {
if stdout.is_empty() {
"GPG signing failed. Please check:\n\
1. GPG signing key is configured (git config --get user.signingkey)\n\
2. GPG agent is running\n\
3. You can sign commits manually (try: git commit --amend -S)".to_string()
} else {
stdout.to_string()
}
} else {
stderr.to_string()
};
bail!("Failed to amend commit: {}", error_msg);
} }
Ok(()) Ok(())

View File

@@ -2,15 +2,12 @@ use anyhow::{bail, Context, Result};
use git2::{Repository, Signature, StatusOptions, Config, Oid, ObjectType}; use git2::{Repository, Signature, StatusOptions, Config, Oid, ObjectType};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::collections::HashMap; use std::collections::HashMap;
use tempfile;
pub mod changelog; pub mod changelog;
pub mod commit; pub mod commit;
pub mod tag; pub mod tag;
pub use changelog::ChangelogGenerator;
pub use commit::CommitBuilder;
pub use tag::TagBuilder;
/// Git repository wrapper with enhanced cross-platform support /// Git repository wrapper with enhanced cross-platform support
pub struct GitRepo { pub struct GitRepo {
repo: Repository, repo: Repository,
@@ -367,19 +364,29 @@ impl GitRepo {
let temp_file = tempfile::NamedTempFile::new()?; let temp_file = tempfile::NamedTempFile::new()?;
std::fs::write(temp_file.path(), message)?; std::fs::write(temp_file.path(), message)?;
let mut cmd = std::process::Command::new("git");
cmd.args(&["commit", "-S", "-F", temp_file.path().to_str().unwrap()])
.current_dir(&self.path)
.output()?;
let output = std::process::Command::new("git") let output = std::process::Command::new("git")
.args(&["commit", "-S", "-F", temp_file.path().to_str().unwrap()]) .args(&["commit", "-S", "-F", temp_file.path().to_str().unwrap()])
.current_dir(&self.path) .current_dir(&self.path)
.output()?; .output()?;
if !output.status.success() { if !output.status.success() {
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr); let stderr = String::from_utf8_lossy(&output.stderr);
bail!("Failed to create signed commit: {}", stderr);
let error_msg = if stderr.is_empty() {
if stdout.is_empty() {
"GPG signing failed. Please check:\n\
1. GPG signing key is configured (git config --get user.signingkey)\n\
2. GPG agent is running\n\
3. You can sign commits manually (try: git commit -S -m 'test')".to_string()
} else {
stdout.to_string()
}
} else {
stderr.to_string()
};
bail!("Failed to create signed commit: {}", error_msg);
} }
let head = self.repo.head()?; let head = self.repo.head()?;

View File

@@ -1,5 +1,5 @@
use super::GitRepo; use super::GitRepo;
use anyhow::{bail, Context, Result}; use anyhow::{bail, Result};
use semver::Version; use semver::Version;
/// Tag builder for creating tags /// Tag builder for creating tags

View File

@@ -2,6 +2,4 @@ pub mod messages;
pub mod translator; pub mod translator;
pub use messages::Messages; pub use messages::Messages;
pub use translator::Translator;
pub use translator::translate_commit_type;
pub use translator::translate_changelog_category; pub use translator::translate_changelog_category;

View File

@@ -1,6 +1,5 @@
use anyhow::{bail, Context, Result}; use anyhow::{bail, Context, Result};
use async_trait::async_trait; use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use std::time::Duration; use std::time::Duration;
use crate::config::Language; use crate::config::Language;

View File

@@ -239,7 +239,7 @@ pub const OPENROUTER_MODELS: &[&str] = &[
]; ];
/// Check if a model name is valid /// Check if a model name is valid
pub fn is_valid_model(model: &str) -> bool { pub fn is_valid_model(_model: &str) -> bool {
// Since OpenRouter supports many models, we'll allow any model name // Since OpenRouter supports many models, we'll allow any model name
// but provide some popular ones as suggestions // but provide some popular ones as suggestions
true true