auto_commit/api/
client.rs1use anyhow::Result;
2use async_trait::async_trait;
3
4#[async_trait]
6pub trait LlmClient: Send + Sync {
7 async fn generate_commit_message(
16 &self,
17 diff: &str,
18 template: Option<&str>,
19 ) -> Result<(String, String)>;
20
21 fn provider_name(&self) -> &str;
23}
24
25pub fn build_prompt(diff: &str, template: Option<&str>) -> String {
27 let rules = template.unwrap_or(DEFAULT_PROMPT_TEMPLATE);
28
29 format!(
30 "以下のGit diffを分析して、適切なコミットメッセージを生成してください。\n\n\
31 ## コミットメッセージのルール\n\
32 {}\n\n\
33 ## 重要な指示\n\
34 - コミットメッセージのみを出力してください(説明や補足は不要)\n\
35 - 1行目はタイトル、空行を挟んで本文を記述\n\
36 - prefixとemojiを適切に選択してください\n\n\
37 ## Git diff\n\
38 ```\n{}\n```",
39 rules, diff
40 )
41}
42
43pub fn parse_commit_message(message: &str) -> (String, String) {
45 let parts: Vec<&str> = message.splitn(2, "\n\n").collect();
46 let title = parts[0].trim().to_string();
47 let description = parts.get(1).map(|s| s.trim()).unwrap_or("").to_string();
48 (title, description)
49}
50
51const DEFAULT_PROMPT_TEMPLATE: &str = r#"以下のGit diffを分析して、適切なコミットメッセージを生成してください。
52
53コミットメッセージは以下のフォーマットで生成してください:
541行目: コミットタイトル(50文字以内、prefix: を含む)
552行目: 空行
563行目以降: 詳細説明(必要に応じて)
57
58使用可能なprefix:
59- feat: 新機能
60- fix: バグ修正
61- docs: ドキュメント
62- style: フォーマット
63- refactor: リファクタリング
64- test: テスト
65- chore: ビルド/CI"#;
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn test_parse_commit_message_with_description() {
73 let message = "feat: Add new feature\n\nThis is the description";
74 let (title, desc) = parse_commit_message(message);
75 assert_eq!(title, "feat: Add new feature");
76 assert_eq!(desc, "This is the description");
77 }
78
79 #[test]
80 fn test_parse_commit_message_without_description() {
81 let message = "fix: Quick fix";
82 let (title, desc) = parse_commit_message(message);
83 assert_eq!(title, "fix: Quick fix");
84 assert_eq!(desc, "");
85 }
86
87 #[test]
88 fn test_build_prompt_with_template() {
89 let diff = "+added line";
90 let template = "Custom template";
91 let prompt = build_prompt(diff, Some(template));
92 assert!(prompt.contains("Custom template"));
93 assert!(prompt.contains("+added line"));
94 }
95
96 #[test]
97 fn test_build_prompt_without_template() {
98 let diff = "+added line";
99 let prompt = build_prompt(diff, None);
100 assert!(prompt.contains("使用可能なprefix"));
101 assert!(prompt.contains("+added line"));
102 }
103}