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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ca7a9199ac933b3d076abc6bcd1f82c5cc096a1c95604294aca7fd15dcccd05c
4
- data.tar.gz: 128c56d3c6bee577a8f152c22f101b98f597524fc40b3cae42d5f63baf463e23
3
+ metadata.gz: 504c10b71930f57d82c42ee4602203394ba6ab930249fd8c2184b3fe4c13010d
4
+ data.tar.gz: 631dfec3f8b6530bb5ad7c04c7daab58ef469685a9853b471fa07ed6c151da19
5
5
  SHA512:
6
- metadata.gz: 9fa153d36b6081843dd3966c3835faa674c78ac3d742f3bce2e72c94bf388196096112531ca1df2abdc3c7e2cce70d6930c4af0c7e5cce73d8176dc4f7a23898
7
- data.tar.gz: c10bf42f067af9a7947cd42c34b94928fccd1f2410d1349e81117182b6dbdd13f14e9bded9ae8725a02d5aa673ae89f1e82524d0f72ec52d12fa1c401bb25901
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
- provider = @prompt.select("Choose AI provider:", {
126
- "OpenAI (GPT-4, GPT-3.5 Turbo)" => "openai",
127
- "Anthropic (Claude 3.5 Sonnet, Claude 3.5 Haiku)" => "claude"
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
@@ -25,6 +25,12 @@ module GitAuto
25
25
  "GPT-4o" => "gpt-4o",
26
26
  "GPT-4o mini" => "gpt-4o-mini"
27
27
  }
28
+ },
29
+ "gemini" => {
30
+ name: "Google (Gemini 2.5 Flash)",
31
+ models: {
32
+ "Gemini 2.5 Flash Preview" => "gemini-2.5-flash-preview-05-20"
33
+ }
28
34
  }
29
35
  }.freeze
30
36
 
@@ -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
- raise RateLimitError, "Rate limit exceeded"
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GitAuto
4
- VERSION = "0.2.2"
4
+ VERSION = "0.3.0"
5
5
  end
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.2.2
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: 2025-03-22 00:00:00.000000000 Z
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.5.22
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: []