git_auto 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +4 -1
- data/lib/git_auto/commands/config_command.rb +9 -4
- data/lib/git_auto/config/settings.rb +6 -0
- data/lib/git_auto/services/ai_service.rb +147 -7
- data/lib/git_auto/version.rb +1 -1
- metadata +3 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 504c10b71930f57d82c42ee4602203394ba6ab930249fd8c2184b3fe4c13010d
|
4
|
+
data.tar.gz: 631dfec3f8b6530bb5ad7c04c7daab58ef469685a9853b471fa07ed6c151da19
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 12dd89f31b4815e2dd829b2596a02bed1aeb991fe830f621448aa9b3bb70c0d8dcd634844faf0c1174e39506f36e42c7882d2999cb8a29c3826fa9f55a8a8720
|
7
|
+
data.tar.gz: 3705440bfca64d8ab4eb84c0ce0b94d2724da839dbc79821689474cb9729bdc01b9a29bdfcd2d88e5cd74918b34ceda807a8ff346cb8dac693647cd4fb2c74ba
|
data/CHANGELOG.md
CHANGED
@@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
7
|
|
8
|
+
## [0.3.0] - 2025-01-06
|
9
|
+
|
10
|
+
### Added
|
11
|
+
- Support for Google Gemini 2.5 Flash Preview AI model
|
12
|
+
- Gemini-specific error handling and messages
|
13
|
+
- Integration tests for Gemini API
|
14
|
+
|
15
|
+
### Changed
|
16
|
+
- Updated provider selection in setup and config commands to be dynamic
|
17
|
+
- Enhanced error messages to be provider-specific
|
18
|
+
|
8
19
|
## [0.2.2] - 2025-03-22
|
9
20
|
|
10
21
|
### Fixed
|
data/README.md
CHANGED
@@ -17,6 +17,7 @@ GitAuto is a Ruby gem that streamlines your git workflow by automatically genera
|
|
17
17
|
- 🤖 **AI Providers**: Supports multiple AI providers:
|
18
18
|
- OpenAI (GPT-4o, GPT-4o mini)
|
19
19
|
- Anthropic (Claude 3.5 Sonnet, Claude 3.5 Haiku)
|
20
|
+
- Google (Gemini 2.5 Flash)
|
20
21
|
- 🔒 **Secure Storage**: Your API keys are encrypted using AES-256-CBC and stored securely
|
21
22
|
|
22
23
|
## Requirements ⚙️
|
@@ -26,6 +27,7 @@ GitAuto is a Ruby gem that streamlines your git workflow by automatically genera
|
|
26
27
|
- 🎟️ One magical ingredient: an API key! Choose your AI companion:
|
27
28
|
- 🔑 OpenAI API key ([Get one here](https://platform.openai.com/api-keys))
|
28
29
|
- 🗝️ Anthropic API key ([Get one here](https://console.anthropic.com/))
|
30
|
+
- 🌟 Google Gemini API key ([Get one here](https://makersuite.google.com/app/apikey))
|
29
31
|
|
30
32
|
That's it! Say goodbye to "misc fixes" and hello to commits that actually tell a story. Your future self will thank you! 🎩✨
|
31
33
|
|
@@ -108,8 +110,9 @@ git-auto commit
|
|
108
110
|
|
109
111
|
Here's what we're planning for future releases:
|
110
112
|
|
111
|
-
- 🤖 Support for Google Gemini AI
|
112
113
|
- 📝 Automatic PR description generation
|
114
|
+
- 🎯 Custom commit message templates
|
115
|
+
- 🔄 Integration with Git hooks
|
113
116
|
- More exciting features coming soon!
|
114
117
|
|
115
118
|
## Contributing 🤝
|
@@ -65,6 +65,9 @@ module GitAuto
|
|
65
65
|
when "claude_api_key"
|
66
66
|
@credential_store.store_api_key(value, "claude")
|
67
67
|
puts "✓ Claude API key updated".green
|
68
|
+
when "gemini_api_key"
|
69
|
+
@credential_store.store_api_key(value, "gemini")
|
70
|
+
puts "✓ Gemini API key updated".green
|
68
71
|
else
|
69
72
|
@settings.set(key.to_sym, value)
|
70
73
|
puts "✓ Setting '#{key}' updated to '#{value}'".green
|
@@ -122,10 +125,12 @@ module GitAuto
|
|
122
125
|
end
|
123
126
|
|
124
127
|
def configure_ai_provider
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
128
|
+
# Use the supported providers from settings
|
129
|
+
provider_choices = Config::Settings::SUPPORTED_PROVIDERS.map do |key, info|
|
130
|
+
{ name: info[:name], value: key }
|
131
|
+
end
|
132
|
+
|
133
|
+
provider = @prompt.select("Choose AI provider:", provider_choices)
|
129
134
|
|
130
135
|
@settings.save(ai_provider: provider)
|
131
136
|
puts "✓ AI provider updated to #{provider}".green
|
@@ -14,6 +14,7 @@ module GitAuto
|
|
14
14
|
|
15
15
|
OPENAI_API_URL = "https://api.openai.com/v1/chat/completions"
|
16
16
|
CLAUDE_API_URL = "https://api.anthropic.com/v1/messages"
|
17
|
+
GEMINI_API_URL = "https://generativelanguage.googleapis.com/v1beta/models"
|
17
18
|
MAX_DIFF_SIZE = 10_000
|
18
19
|
MAX_RETRIES = 3
|
19
20
|
BACKOFF_BASE = 2
|
@@ -25,10 +26,10 @@ module GitAuto
|
|
25
26
|
end
|
26
27
|
|
27
28
|
TEMPERATURE_VARIATIONS = [
|
28
|
-
{ openai: 0.7, claude: 0.7 },
|
29
|
-
{ openai: 0.8, claude: 0.8 },
|
30
|
-
{ openai: 0.9, claude: 0.9 },
|
31
|
-
{ openai: 1.0, claude: 1.0 }
|
29
|
+
{ openai: 0.7, claude: 0.7, gemini: 0.7 },
|
30
|
+
{ openai: 0.8, claude: 0.8, gemini: 0.8 },
|
31
|
+
{ openai: 0.9, claude: 0.9, gemini: 0.9 },
|
32
|
+
{ openai: 1.0, claude: 1.0, gemini: 1.0 }
|
32
33
|
].freeze
|
33
34
|
|
34
35
|
def initialize(settings)
|
@@ -169,6 +170,8 @@ module GitAuto
|
|
169
170
|
generate_openai_commit_message(diff, style, scope)
|
170
171
|
when "claude"
|
171
172
|
generate_claude_commit_message(diff, style, scope)
|
173
|
+
when "gemini"
|
174
|
+
generate_gemini_commit_message(diff, style, scope)
|
172
175
|
else
|
173
176
|
raise GitAuto::Errors::InvalidProviderError, "Invalid AI provider specified"
|
174
177
|
end
|
@@ -192,8 +195,7 @@ module GitAuto
|
|
192
195
|
def previous_suggestions_prompt
|
193
196
|
return "" if @previous_suggestions.empty?
|
194
197
|
|
195
|
-
"\nPrevious suggestions that you MUST NOT repeat:\n"
|
196
|
-
@previous_suggestions.map { |s| "- #{s}" }.join("\n")
|
198
|
+
"\nPrevious suggestions that you MUST NOT repeat:\n#{@previous_suggestions.map { |s| "- #{s}" }.join("\n")}"
|
197
199
|
end
|
198
200
|
|
199
201
|
def generate_openai_commit_message(diff, style, scope = nil, retry_attempt = nil)
|
@@ -388,6 +390,110 @@ module GitAuto
|
|
388
390
|
add_suggestion(message)
|
389
391
|
end
|
390
392
|
|
393
|
+
def generate_gemini_commit_message(diff, style, scope = nil, retry_attempt = nil)
|
394
|
+
api_key = @credential_store.get_api_key("gemini")
|
395
|
+
raise APIKeyError, "Gemini API key is not set. Please set it using `git_auto config`" unless api_key
|
396
|
+
|
397
|
+
# Only use temperature variations for retries
|
398
|
+
temperature = retry_attempt ? get_temperature(retry_attempt) : TEMPERATURE_VARIATIONS[0][:gemini]
|
399
|
+
commit_types = ["feat", "fix", "docs", "style", "refactor", "test", "chore", "perf", "ci", "build",
|
400
|
+
"revert"].join("|")
|
401
|
+
|
402
|
+
system_message = case style.to_s
|
403
|
+
when "minimal"
|
404
|
+
"You are a commit message generator that MUST follow the minimal commit format: <type>: <description>\n" \
|
405
|
+
"Valid types are: #{commit_types}\n" \
|
406
|
+
"Rules:\n" \
|
407
|
+
"1. ALWAYS start with a type from the list above\n" \
|
408
|
+
"2. NEVER include a scope\n" \
|
409
|
+
"3. Keep the message under 72 characters\n" \
|
410
|
+
"4. ALWAYS use lowercase - this is mandatory\n" \
|
411
|
+
"5. Use present tense\n" \
|
412
|
+
"6. Be descriptive but concise\n" \
|
413
|
+
"7. Do not include a period at the end"
|
414
|
+
when "conventional"
|
415
|
+
"You are a commit message generator that MUST follow these rules EXACTLY:\n" \
|
416
|
+
"1. ONLY output a single line containing the commit message\n" \
|
417
|
+
"2. Use format: <type>(<scope>): <description>\n" \
|
418
|
+
"3. Valid types are: #{commit_types}\n" \
|
419
|
+
"4. Keep under 72 characters\n" \
|
420
|
+
"5. ALWAYS use lowercase - this is mandatory\n" \
|
421
|
+
"6. Use present tense\n" \
|
422
|
+
"7. Be descriptive but concise\n" \
|
423
|
+
"8. No period at the end\n" \
|
424
|
+
"9. NO explanations or additional text\n" \
|
425
|
+
"10. NO markdown formatting"
|
426
|
+
when "detailed"
|
427
|
+
"You are a commit message generator that MUST follow this format EXACTLY:\n" \
|
428
|
+
"<summary line>\n" \
|
429
|
+
"\n" \
|
430
|
+
"<detailed description>\n" \
|
431
|
+
"\n" \
|
432
|
+
"Rules:\n" \
|
433
|
+
"1. First line is a summary under 72 characters\n" \
|
434
|
+
"2. ALWAYS use lowercase - this is mandatory\n" \
|
435
|
+
"3. ALWAYS include a blank line after the summary\n" \
|
436
|
+
"4. ALWAYS include a detailed description explaining:\n" \
|
437
|
+
" - What changes were made\n" \
|
438
|
+
" - Why the changes were necessary\n" \
|
439
|
+
" - Any technical details worth noting\n" \
|
440
|
+
"5. Use bullet points for multiple changes\n" \
|
441
|
+
"6. Use present tense\n" \
|
442
|
+
"7. You can use periods in the detailed description\n" \
|
443
|
+
"8. NO explanations or additional text\n" \
|
444
|
+
"9. NO markdown formatting"
|
445
|
+
else
|
446
|
+
"You are an expert in writing clear and concise git commit messages.\n" \
|
447
|
+
"Rules:\n" \
|
448
|
+
"1. Keep the message under 72 characters\n" \
|
449
|
+
"2. ALWAYS use lowercase - this is mandatory\n" \
|
450
|
+
"3. Use present tense\n" \
|
451
|
+
"4. Be descriptive but concise\n" \
|
452
|
+
"5. Do not include a period at the end"
|
453
|
+
end
|
454
|
+
|
455
|
+
user_message = if scope
|
456
|
+
"Generate a conventional commit message with scope '#{scope}' for this diff:\n\n#{diff}"
|
457
|
+
else
|
458
|
+
"Generate a #{style} commit message for this diff:\n\n#{diff}"
|
459
|
+
end
|
460
|
+
|
461
|
+
model = @settings.get(:ai_model)
|
462
|
+
url = "#{GEMINI_API_URL}/#{model}:generateContent?key=#{api_key}"
|
463
|
+
|
464
|
+
payload = {
|
465
|
+
contents: [
|
466
|
+
{
|
467
|
+
parts: [
|
468
|
+
{
|
469
|
+
text: "#{system_message}\n\n#{user_message}"
|
470
|
+
}
|
471
|
+
]
|
472
|
+
}
|
473
|
+
],
|
474
|
+
generationConfig: {
|
475
|
+
temperature: temperature,
|
476
|
+
topK: 40,
|
477
|
+
topP: 0.95,
|
478
|
+
candidateCount: 1,
|
479
|
+
maxOutputTokens: 1024
|
480
|
+
}
|
481
|
+
}
|
482
|
+
|
483
|
+
log_api_request("gemini", payload, temperature) if @debug_mode
|
484
|
+
|
485
|
+
response = HTTP.headers({
|
486
|
+
"Content-Type" => "application/json"
|
487
|
+
}).post(url, json: payload)
|
488
|
+
|
489
|
+
log_api_response(response.body) if @debug_mode
|
490
|
+
|
491
|
+
message = handle_response(response)
|
492
|
+
message = message.downcase.strip
|
493
|
+
message = message.sub(/\.$/, "") # Remove trailing period if present
|
494
|
+
add_suggestion(message)
|
495
|
+
end
|
496
|
+
|
391
497
|
def style_description(style, scope)
|
392
498
|
case style
|
393
499
|
when :conventional, "conventional"
|
@@ -436,6 +542,21 @@ module GitAuto
|
|
436
542
|
raise Error, "No valid commit message found in response" if commit_message.nil?
|
437
543
|
commit_message.strip
|
438
544
|
end
|
545
|
+
|
546
|
+
when "gemini"
|
547
|
+
content = json.dig("candidates", 0, "content", "parts", 0, "text")
|
548
|
+
raise Error, "No message content in response" if content.nil? || content.empty?
|
549
|
+
|
550
|
+
# For detailed style, keep the full message
|
551
|
+
if @settings.get(:commit_style) == "detailed"
|
552
|
+
content.strip
|
553
|
+
else
|
554
|
+
# Clean up the response and extract just the commit message
|
555
|
+
lines = content.strip.split("\n")
|
556
|
+
# Find the first line that looks like a commit message
|
557
|
+
commit_line = lines.find { |line| line.match(/^(feat|fix|docs|style|refactor|test|chore|perf|ci|build|revert)/) }
|
558
|
+
commit_line || lines.first.strip
|
559
|
+
end
|
439
560
|
end
|
440
561
|
when 401
|
441
562
|
raise APIKeyError, "Invalid API key" unless ENV["RACK_ENV"] == "test"
|
@@ -447,8 +568,27 @@ module GitAuto
|
|
447
568
|
|
448
569
|
"test commit message"
|
449
570
|
|
571
|
+
when 403
|
572
|
+
# Gemini-specific error for invalid API key
|
573
|
+
provider = @settings.get(:ai_provider)
|
574
|
+
if provider == "gemini"
|
575
|
+
raise APIKeyError, "Invalid Gemini API key. Please check your API key at https://makersuite.google.com/app/apikey"
|
576
|
+
else
|
577
|
+
raise APIKeyError, "Access forbidden. Please check your API key."
|
578
|
+
end
|
579
|
+
|
450
580
|
when 429
|
451
|
-
|
581
|
+
provider = @settings.get(:ai_provider)
|
582
|
+
case provider
|
583
|
+
when "gemini"
|
584
|
+
raise RateLimitError, "Gemini API rate limit exceeded. Please wait a moment and try again."
|
585
|
+
when "openai"
|
586
|
+
raise RateLimitError, "OpenAI API rate limit exceeded. Please try again later."
|
587
|
+
when "claude"
|
588
|
+
raise RateLimitError, "Claude API rate limit exceeded. Please try again later."
|
589
|
+
else
|
590
|
+
raise RateLimitError, "Rate limit exceeded"
|
591
|
+
end
|
452
592
|
else
|
453
593
|
raise Error, "API request failed with status #{response.code}: #{response.body}"
|
454
594
|
end
|
data/lib/git_auto/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: git_auto
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Guillermo Diaz
|
8
|
-
autorequire:
|
9
8
|
bindir: exe
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: thor
|
@@ -248,7 +247,6 @@ metadata:
|
|
248
247
|
source_code_uri: https://github.com/diazgdev/git_auto
|
249
248
|
changelog_uri: https://github.com/diazgdev/git_auto/blob/main/CHANGELOG.md
|
250
249
|
rubygems_mfa_required: 'true'
|
251
|
-
post_install_message:
|
252
250
|
rdoc_options: []
|
253
251
|
require_paths:
|
254
252
|
- lib
|
@@ -263,8 +261,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
263
261
|
- !ruby/object:Gem::Version
|
264
262
|
version: '0'
|
265
263
|
requirements: []
|
266
|
-
rubygems_version: 3.
|
267
|
-
signing_key:
|
264
|
+
rubygems_version: 3.6.8
|
268
265
|
specification_version: 4
|
269
266
|
summary: AI-powered git commit messages using OpenAI or Anthropic APIs
|
270
267
|
test_files: []
|