git_auto 0.2.0 → 0.2.2

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: 8ab4962fee719c30fca3c7b4577154fed588495e61b6d95e91bb66ae15f5504e
4
- data.tar.gz: 837bac312ba13254250e8b149c97e823557e4099cf7459e40dc993db86468caf
3
+ metadata.gz: ca7a9199ac933b3d076abc6bcd1f82c5cc096a1c95604294aca7fd15dcccd05c
4
+ data.tar.gz: 128c56d3c6bee577a8f152c22f101b98f597524fc40b3cae42d5f63baf463e23
5
5
  SHA512:
6
- metadata.gz: 2f1aacf6b7c6635baf6f6bbeafabc980f39b6797201bb9eab4602d1845e52b14d7e0afd957047f305260c695830cffb51b92011d445705daea1712d6b62cc732
7
- data.tar.gz: 85948f7190233c795197c49f833c249c55fe6e7f381c601deecc494a9aa1b16c56dfd02cbc268830749196a9a58ba24f69b1eff7adfa692b9d83df76270aecfc
6
+ metadata.gz: 9fa153d36b6081843dd3966c3835faa674c78ac3d742f3bce2e72c94bf388196096112531ca1df2abdc3c7e2cce70d6930c4af0c7e5cce73d8176dc4f7a23898
7
+ data.tar.gz: c10bf42f067af9a7947cd42c34b94928fccd1f2410d1349e81117182b6dbdd13f14e9bded9ae8725a02d5aa673ae89f1e82524d0f72ec52d12fa1c401bb25901
data/CHANGELOG.md CHANGED
@@ -1,16 +1,52 @@
1
- ## [0.2.0] - 2024-12-15
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.2.2] - 2025-03-22
9
+
10
+ ### Fixed
11
+ - Fixed API key storage in credential store when using `config set` command
12
+ - Fixed commit message validation to properly handle different styles (conventional, minimal, simple, detailed)
13
+ - Extended conventional commit scope pattern to allow dots in file names (e.g., `index.js`)
14
+ - Improved AI prompts to consistently generate lowercase commit messages
2
15
 
3
16
  ### Added
4
- - New "Minimal" commit message style option for more concise commits
5
- - Display of AI model used in commit message generation for better transparency
17
+ - Enhanced detailed commit style to include multi-line messages with:
18
+ - Concise summary line
19
+ - Detailed bullet points explaining changes
20
+ - Technical context and reasoning
21
+
22
+ ## [0.2.1] - 2024-12-19
6
23
 
7
24
  ### Fixed
8
- - Improved Git staged changes detection for more reliable operation
9
- - Improved commit message validation for both minimal and conventional formats
25
+ - Improve Claude AI response handling for conventional commit messages
26
+ - Make system prompts more explicit to ensure consistent output format
27
+ - Fixed error when displaying repository status with no staged files
28
+ - Improved error handling in repository status display
10
29
 
11
30
  ### Changed
12
- - Updated AI service integration to support minimal commit style across OpenAI and Claude
13
- - Improved error handling and user feedback during Git operations
31
+ - Update system prompts to be more strict and specific
32
+ - Enhance commit message validation for Claude responses
33
+
34
+ ## [0.2.0] - 2024-12-15
35
+
36
+ ### Added
37
+ - Support for multiple AI providers (OpenAI and Anthropic)
38
+ - New commit message styles (minimal, conventional, simple)
39
+ - Commit history analysis
40
+ - Pattern detection for commit types and scopes
41
+ - Secure API key storage with encryption
42
+
43
+ ### Changed
44
+ - Improved error messages and validation
45
+ - Enhanced diff formatting and preview
46
+ - Better handling of commit message generation
47
+
48
+ ### Fixed
49
+ - Various bug fixes and performance improvements
14
50
 
15
51
  ## [0.1.1] - 2024-12-13
16
52
 
data/exe/git-auto ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "git_auto"
5
+ require "git_auto/cli"
6
+
7
+ GitAuto::CLI.start(ARGV)
@@ -19,6 +19,7 @@ module GitAuto
19
19
  @git_service = Services::GitService.new
20
20
  @ai_service = Services::AIService.new(@settings)
21
21
  @history_service = Services::HistoryService.new
22
+ @validator = Validators::CommitMessageValidator.new(get_commit_style)
22
23
  @retry_count = 0
23
24
  end
24
25
 
@@ -27,8 +28,11 @@ module GitAuto
27
28
  status = @git_service.repository_status
28
29
  validate_repository(status)
29
30
 
31
+ # Get staged files
32
+ staged_files = @git_service.get_staged_files
33
+
30
34
  # Get and validate changes
31
- diff = @git_service.get_staged_diff
35
+ diff = @git_service.get_staged_diff(staged_files)
32
36
  validate_changes(diff)
33
37
 
34
38
  # Show diff preview if requested
@@ -51,8 +55,7 @@ module GitAuto
51
55
  return if status[:has_staged_changes]
52
56
 
53
57
  puts "ℹ️ Status:".blue
54
- puts " Branch: #{status[:branch]}"
55
- puts " Staged files: #{status[:staged_files].join(", ")}"
58
+ puts " No changes staged for commit"
56
59
  puts "\n❌ No changes staged for commit. Use 'git add' to stage changes.".red
57
60
  exit 1
58
61
  end
@@ -113,6 +116,24 @@ module GitAuto
113
116
  message
114
117
  end
115
118
 
119
+ # Message Validation Methods
120
+ def validate_message(message)
121
+ result = @validator.validate(message)
122
+
123
+ if result[:errors].any?
124
+ puts "\n❌ Validation errors:".red
125
+ result[:errors].each { |error| puts @validator.format_error(error) }
126
+ end
127
+
128
+ if result[:warnings].any?
129
+ puts "\n⚠️ Suggestions:".yellow
130
+ result[:warnings].each { |warning| puts @validator.format_warning(warning) }
131
+ end
132
+
133
+ puts "\nPlease edit the message to fix these errors." if result[:errors].any?
134
+ result
135
+ end
136
+
116
137
  # Message Handling Methods
117
138
  def handle_message(message, diff)
118
139
  formatted = Formatters::MessageFormatter.new.format(message)
@@ -125,37 +146,23 @@ module GitAuto
125
146
  end
126
147
  end
127
148
 
128
- def validate_message(message)
129
- validator = Validators::CommitMessageValidator.new
130
- validator.validate(message)
131
- end
132
-
133
149
  def display_message_and_validation(formatted_message, validation)
134
- provider = @settings.get(:ai_provider)
135
- model = @settings.get(:ai_model)
136
- model_info = "(#{provider}/#{model})".light_black
137
-
138
- puts "\n📝 Generated commit message #{model_info}:".blue
150
+ puts "\n📝 Generated commit message (#{@settings.get(:ai_provider)}/#{@settings.get(:ai_model)}):".blue
139
151
  puts formatted_message
140
152
 
141
- display_validation_errors(validation[:errors]) if validation[:errors].any?
153
+ return unless validation[:errors].any? || validation[:warnings].any?
142
154
 
143
- return unless validation[:warnings].any?
144
-
145
- display_validation_warnings(validation[:warnings])
146
- end
155
+ if validation[:errors].any?
156
+ puts "\n❌ Validation errors:".red
157
+ validation[:errors].each { |error| puts @validator.format_error(error) }
158
+ end
147
159
 
148
- def display_validation_errors(errors)
149
- puts "\n❌ Validation errors:".red
150
- validator = Validators::CommitMessageValidator.new
151
- errors.each { |error| puts validator.format_error(error) }
152
- puts "\nPlease edit the message to fix these errors.".yellow
153
- end
160
+ if validation[:warnings].any?
161
+ puts "\n⚠️ Suggestions:".yellow
162
+ validation[:warnings].each { |warning| puts @validator.format_warning(warning) }
163
+ end
154
164
 
155
- def display_validation_warnings(warnings)
156
- puts "\n⚠️ Suggestions:".yellow
157
- validator = Validators::CommitMessageValidator.new
158
- warnings.each { |warning| puts validator.format_warning(warning) }
165
+ puts "\nPlease edit the message to fix these errors." if validation[:errors].any?
159
166
  end
160
167
 
161
168
  def prompt_user_action
@@ -58,8 +58,17 @@ module GitAuto
58
58
  exit 1
59
59
  end
60
60
 
61
- @settings.set(key.to_sym, value)
62
- puts "✓ Setting '#{key}' updated to '#{value}'".green
61
+ case key.to_s
62
+ when "openai_api_key"
63
+ @credential_store.store_api_key(value, "openai")
64
+ puts "✓ OpenAI API key updated".green
65
+ when "claude_api_key"
66
+ @credential_store.store_api_key(value, "claude")
67
+ puts "✓ Claude API key updated".green
68
+ else
69
+ @settings.set(key.to_sym, value)
70
+ puts "✓ Setting '#{key}' updated to '#{value}'".green
71
+ end
63
72
  end
64
73
 
65
74
  def interactive_config
@@ -156,19 +165,19 @@ module GitAuto
156
165
  "Simple (description only)" => "simple"
157
166
  })
158
167
 
159
- @settings.set(:commit_style, style)
168
+ @settings.save(commit_style: style)
160
169
  puts "✓ Commit style updated to #{style}".green
161
170
  end
162
171
 
163
172
  def configure_preferences
164
173
  show_diff = @prompt.yes?("Show diff before committing?")
165
- @settings.set(:show_diff, show_diff)
174
+ @settings.save(show_diff: show_diff)
166
175
  puts "✓ Show diff preference updated".green
167
176
  end
168
177
 
169
178
  def configure_history_settings
170
179
  save_history = @prompt.yes?("Save commit history for analysis?")
171
- @settings.set(:save_history, save_history)
180
+ @settings.save(save_history: save_history)
172
181
  puts "✓ History settings updated".green
173
182
  end
174
183
  end
@@ -52,6 +52,11 @@ module GitAuto
52
52
  @settings[key.to_sym]
53
53
  end
54
54
 
55
+ def set(key, value)
56
+ @settings[key.to_sym] = value
57
+ save
58
+ end
59
+
55
60
  def all
56
61
  @settings
57
62
  end
@@ -39,10 +39,13 @@ module GitAuto
39
39
  @@temperature ||= TEMPERATURE_VARIATIONS[0]
40
40
  @request_count = 0
41
41
  @previous_suggestions = []
42
+ @debug_mode = ENV["GIT_AUTO_DEBUG"] == "true"
42
43
  end
43
44
 
44
45
  def log_api_request(provider, payload, temperature)
45
- puts "\n=== API Request ##{@request_count += 1} ==="
46
+ return unless @debug_mode
47
+
48
+ puts "\n=== API Request ##{@request_count += 1} ===".yellow
46
49
  puts "Provider: #{provider}"
47
50
  puts "Temperature: #{temperature}"
48
51
  puts "Full Payload:"
@@ -51,7 +54,9 @@ module GitAuto
51
54
  end
52
55
 
53
56
  def log_api_response(response_body)
54
- puts "\n=== API Response ==="
57
+ return unless @debug_mode
58
+
59
+ puts "\n=== API Response ===".yellow
55
60
  puts JSON.pretty_generate(JSON.parse(response_body.to_s))
56
61
  puts "===================="
57
62
  end
@@ -73,14 +78,45 @@ module GitAuto
73
78
  "1. ALWAYS start with a type from the list above\n" \
74
79
  "2. NEVER include a scope\n" \
75
80
  "3. Keep the message under 72 characters\n" \
76
- "4. Use lowercase\n" \
81
+ "4. ALWAYS use lowercase - this is mandatory\n" \
77
82
  "5. Use present tense\n" \
78
83
  "6. Be descriptive but concise\n" \
79
84
  "7. Do not include a period at the end"
80
85
  when "conventional"
81
- "You are an expert in writing conventional commit messages..."
86
+ "You are an expert in writing conventional commit messages that follow the format: <type>(<scope>): <description>\n" \
87
+ "Rules:\n" \
88
+ "1. ALWAYS start with a type from the list above\n" \
89
+ "2. Include a scope in parentheses when relevant\n" \
90
+ "3. Keep the message under 72 characters\n" \
91
+ "4. ALWAYS use lowercase - this is mandatory\n" \
92
+ "5. Use present tense\n" \
93
+ "6. Be descriptive but concise\n" \
94
+ "7. Do not include a period at the end"
95
+ when "detailed"
96
+ "You are an expert in writing detailed commit messages. Your message MUST follow this format:\n" \
97
+ "<summary line>\n" \
98
+ "\n" \
99
+ "<detailed description>\n" \
100
+ "\n" \
101
+ "Rules:\n" \
102
+ "1. First line is a summary under 72 characters\n" \
103
+ "2. ALWAYS use lowercase - this is mandatory\n" \
104
+ "3. ALWAYS include a blank line after the summary\n" \
105
+ "4. ALWAYS include a detailed description explaining:\n" \
106
+ " - What changes were made\n" \
107
+ " - Why the changes were necessary\n" \
108
+ " - Any technical details worth noting\n" \
109
+ "5. Use bullet points for multiple changes\n" \
110
+ "6. Use present tense\n" \
111
+ "7. You can use periods in the detailed description"
82
112
  else
83
- "You are an expert in writing clear and concise git commit messages..."
113
+ "You are an expert in writing clear and concise git commit messages.\n" \
114
+ "Rules:\n" \
115
+ "1. Keep the message under 72 characters\n" \
116
+ "2. ALWAYS use lowercase - this is mandatory\n" \
117
+ "3. Use present tense\n" \
118
+ "4. Be descriptive but concise\n" \
119
+ "5. Do not include a period at the end"
84
120
  end
85
121
 
86
122
  # Add variation for retries
@@ -115,51 +151,17 @@ module GitAuto
115
151
  end
116
152
 
117
153
  def generate_commit_message(diff, style: :conventional, scope: nil)
118
- raise EmptyDiffError if diff.nil? || diff.strip.empty?
154
+ raise EmptyDiffError, "No changes to commit" if diff.empty?
119
155
 
120
156
  # If diff is too large, use the summarized version
121
- diff = @diff_summarizer.summarize(diff) if diff.length > MAX_DIFF_SIZE
122
-
123
- if style.to_s == "minimal"
124
- message = case @settings.get(:ai_provider)
125
- when "openai"
126
- generate_openai_commit_message(diff, style)
127
- when "claude"
128
- generate_claude_commit_message(diff, style)
129
- end
130
-
131
- # Extract type and description from the message
132
- if message =~ /^(\w+):\s*(.+)$/
133
- type = ::Regexp.last_match(1)
134
- description = ::Regexp.last_match(2)
135
- return "#{type}: #{description}"
136
- end
137
-
138
- return message
139
- elsif style.to_s == "conventional" && scope.nil?
140
- # Generate both scope and message in one call
141
- message = case @settings.get(:ai_provider)
142
- when "openai"
143
- generate_openai_commit_message(diff, style)
144
- when "claude"
145
- generate_claude_commit_message(diff, style)
146
- end
147
-
148
- # Extract type and scope from the message
149
- if message =~ /^(\w+)(?:\(([\w-]+)\))?:\s*(.+)$/
150
- type = ::Regexp.last_match(1)
151
- existing_scope = ::Regexp.last_match(2)
152
- description = ::Regexp.last_match(3)
153
-
154
- # If we got a scope in the message, use it, otherwise generate one
155
- scope ||= existing_scope || infer_scope_from_diff(diff)
156
- return scope ? "#{type}(#{scope}): #{description}" : "#{type}: #{description}"
157
- end
158
-
159
- # If message doesn't match expected format, just return it as is
160
- return message
157
+ if diff.length > MAX_DIFF_SIZE
158
+ puts "\n⚠️ Diff is large, using summarized version...".yellow if @debug_mode
159
+ diff = @diff_summarizer.summarize(diff)
161
160
  end
162
161
 
162
+ # Store the commit style in settings for use in handle_response
163
+ @settings.set(:commit_style, style.to_s)
164
+
163
165
  retries = 0
164
166
  begin
165
167
  case @settings.get(:ai_provider)
@@ -211,23 +213,49 @@ module GitAuto
211
213
  "1. ALWAYS start with a type from the list above\n" \
212
214
  "2. NEVER include a scope\n" \
213
215
  "3. Keep the message under 72 characters\n" \
214
- "4. Use lowercase\n" \
216
+ "4. ALWAYS use lowercase - this is mandatory\n" \
215
217
  "5. Use present tense\n" \
216
218
  "6. Be descriptive but concise\n" \
217
219
  "7. Do not include a period at the end"
218
220
  when "conventional"
219
- "You are a commit message generator that MUST follow the conventional commit format: <type>(<scope>): <description>\n" \
220
- "Valid types are: #{commit_types}\n" \
221
+ "You are a commit message generator that MUST follow these rules EXACTLY:\n" \
222
+ "1. ONLY output a single line containing the commit message\n" \
223
+ "2. Use format: <type>(<scope>): <description>\n" \
224
+ "3. Valid types are: #{commit_types}\n" \
225
+ "4. Keep under 72 characters\n" \
226
+ "5. ALWAYS use lowercase - this is mandatory\n" \
227
+ "6. Use present tense\n" \
228
+ "7. Be descriptive but concise\n" \
229
+ "8. No period at the end\n" \
230
+ "9. NO explanations or additional text\n" \
231
+ "10. NO markdown formatting"
232
+ when "detailed"
233
+ "You are a commit message generator that MUST follow this format EXACTLY:\n" \
234
+ "<summary line>\n" \
235
+ "\n" \
236
+ "<detailed description>\n" \
237
+ "\n" \
221
238
  "Rules:\n" \
222
- "1. ALWAYS start with a type from the list above\n" \
223
- "2. ALWAYS use the exact format <type>(<scope>): <description>\n" \
224
- "3. Keep the message under 72 characters\n" \
225
- "4. Use lowercase\n" \
226
- "5. Use present tense\n" \
227
- "6. Be descriptive but concise\n" \
228
- "7. Do not include a period at the end"
239
+ "1. First line is a summary under 72 characters\n" \
240
+ "2. ALWAYS use lowercase - this is mandatory\n" \
241
+ "3. ALWAYS include a blank line after the summary\n" \
242
+ "4. ALWAYS include a detailed description explaining:\n" \
243
+ " - What changes were made\n" \
244
+ " - Why the changes were necessary\n" \
245
+ " - Any technical details worth noting\n" \
246
+ "5. Use bullet points for multiple changes\n" \
247
+ "6. Use present tense\n" \
248
+ "7. You can use periods in the detailed description\n" \
249
+ "8. NO explanations or additional text\n" \
250
+ "9. NO markdown formatting"
229
251
  else
230
- "You are an expert in writing clear and concise git commit messages..."
252
+ "You are an expert in writing clear and concise git commit messages.\n" \
253
+ "Rules:\n" \
254
+ "1. Keep the message under 72 characters\n" \
255
+ "2. ALWAYS use lowercase - this is mandatory\n" \
256
+ "3. Use present tense\n" \
257
+ "4. Be descriptive but concise\n" \
258
+ "5. Do not include a period at the end"
231
259
  end
232
260
 
233
261
  user_message = if scope
@@ -245,13 +273,14 @@ module GitAuto
245
273
  temperature: temperature
246
274
  }
247
275
 
248
- # Uncomment the following line to see the API request and response details for debugging
249
- # log_api_request("openai", payload, temperature) if ENV["DEBUG"]
276
+ log_api_request("openai", payload, temperature) if @debug_mode
250
277
 
251
278
  response = HTTP.auth("Bearer #{api_key}")
252
279
  .headers(accept: "application/json")
253
280
  .post(OPENAI_API_URL, json: payload)
254
281
 
282
+ log_api_response(response.body) if @debug_mode
283
+
255
284
  handle_response(response)
256
285
  end
257
286
 
@@ -272,23 +301,49 @@ module GitAuto
272
301
  "1. ALWAYS start with a type from the list above\n" \
273
302
  "2. NEVER include a scope\n" \
274
303
  "3. Keep the message under 72 characters\n" \
275
- "4. Use lowercase\n" \
304
+ "4. ALWAYS use lowercase - this is mandatory\n" \
276
305
  "5. Use present tense\n" \
277
306
  "6. Be descriptive but concise\n" \
278
307
  "7. Do not include a period at the end"
279
308
  when "conventional"
280
- "You are a commit message generator that MUST follow the conventional commit format: <type>(<scope>): <description>\n" \
281
- "Valid types are: #{commit_types}\n" \
309
+ "You are a commit message generator that MUST follow these rules EXACTLY:\n" \
310
+ "1. ONLY output a single line containing the commit message\n" \
311
+ "2. Use format: <type>(<scope>): <description>\n" \
312
+ "3. Valid types are: #{commit_types}\n" \
313
+ "4. Keep under 72 characters\n" \
314
+ "5. ALWAYS use lowercase - this is mandatory\n" \
315
+ "6. Use present tense\n" \
316
+ "7. Be descriptive but concise\n" \
317
+ "8. No period at the end\n" \
318
+ "9. NO explanations or additional text\n" \
319
+ "10. NO markdown formatting"
320
+ when "detailed"
321
+ "You are a commit message generator that MUST follow this format EXACTLY:\n" \
322
+ "<summary line>\n" \
323
+ "\n" \
324
+ "<detailed description>\n" \
325
+ "\n" \
282
326
  "Rules:\n" \
283
- "1. ALWAYS start with a type from the list above\n" \
284
- "2. ALWAYS use the exact format <type>(<scope>): <description>\n" \
285
- "3. Keep the message under 72 characters\n" \
286
- "4. Use lowercase\n" \
287
- "5. Use present tense\n" \
288
- "6. Be descriptive but concise\n" \
289
- "7. Do not include a period at the end"
327
+ "1. First line is a summary under 72 characters\n" \
328
+ "2. ALWAYS use lowercase - this is mandatory\n" \
329
+ "3. ALWAYS include a blank line after the summary\n" \
330
+ "4. ALWAYS include a detailed description explaining:\n" \
331
+ " - What changes were made\n" \
332
+ " - Why the changes were necessary\n" \
333
+ " - Any technical details worth noting\n" \
334
+ "5. Use bullet points for multiple changes\n" \
335
+ "6. Use present tense\n" \
336
+ "7. You can use periods in the detailed description\n" \
337
+ "8. NO explanations or additional text\n" \
338
+ "9. NO markdown formatting"
290
339
  else
291
- "You are an expert in writing clear and concise git commit messages..."
340
+ "You are an expert in writing clear and concise git commit messages.\n" \
341
+ "Rules:\n" \
342
+ "1. Keep the message under 72 characters\n" \
343
+ "2. ALWAYS use lowercase - this is mandatory\n" \
344
+ "3. Use present tense\n" \
345
+ "4. Be descriptive but concise\n" \
346
+ "5. Do not include a period at the end"
292
347
  end
293
348
 
294
349
  user_message = if scope
@@ -317,16 +372,16 @@ module GitAuto
317
372
  ]
318
373
  }
319
374
 
320
- # Uncomment the following lines to see the API request and response details for debugging
321
- # log_api_request("claude", payload, temperature)
322
- # log_api_response(response.body)
323
-
375
+ log_api_request("claude", payload, temperature) if @debug_mode
376
+
324
377
  response = HTTP.headers({
325
378
  "Content-Type" => "application/json",
326
379
  "x-api-key" => api_key,
327
380
  "anthropic-version" => "2023-06-01"
328
381
  }).post(CLAUDE_API_URL, json: payload)
329
382
 
383
+ log_api_response(response.body) if @debug_mode
384
+
330
385
  message = handle_response(response)
331
386
  message = message.downcase.strip
332
387
  message = message.sub(/\.$/, "") # Remove trailing period if present
@@ -344,6 +399,8 @@ module GitAuto
344
399
  "commit scope suggestion"
345
400
  when :minimal, "minimal"
346
401
  "minimal commit message"
402
+ when :detailed, "detailed"
403
+ "detailed commit message"
347
404
  else
348
405
  "commit message"
349
406
  end
@@ -353,33 +410,32 @@ module GitAuto
353
410
  case response.code
354
411
  when 200
355
412
  json = JSON.parse(response.body.to_s)
356
- # puts "Debug - API Response: #{json.inspect}"
413
+
357
414
  case @settings.get(:ai_provider)
358
415
  when "openai"
359
416
  message = json.dig("choices", 0, "message", "content")
360
- if message.nil? || message.empty?
361
- # puts "Debug - No content in response: #{json}"
362
- raise Error, "No message content in response"
417
+ raise Error, "No message content in response" if message.nil? || message.empty?
418
+
419
+ # For detailed style, keep the full message
420
+ if @settings.get(:commit_style) == "detailed"
421
+ message.strip
422
+ else
423
+ message.split("\n").first.strip
363
424
  end
364
425
 
365
- message.split("\n").first.strip
366
426
  when "claude"
367
427
  content = json.dig("content", 0, "text")
368
- # puts "Debug - Claude content: #{content.inspect}"
428
+ raise Error, "No message content in response" if content.nil? || content.empty?
369
429
 
370
- if content.nil? || content.empty?
371
- # puts "Debug - No content in response: #{json}"
372
- raise Error, "No message content in response"
430
+ # For detailed style, keep the full message
431
+ if @settings.get(:commit_style) == "detailed"
432
+ content.strip
433
+ else
434
+ # Extract the first actual commit message from the response
435
+ commit_message = content.scan(/(?:feat|fix|docs|style|refactor|test|chore|perf|ci|build|revert)(?:\([^)]+\))?:.*/)&.first
436
+ raise Error, "No valid commit message found in response" if commit_message.nil?
437
+ commit_message.strip
373
438
  end
374
-
375
- lines = content.split("\n").map(&:strip).reject(&:empty?)
376
- # puts "Debug - Lines: #{lines.inspect}"
377
-
378
- message = lines.first
379
-
380
- raise Error, "No valid commit message found in response" if message.nil? || !message.match?(/^[a-z]+:/)
381
-
382
- message
383
439
  end
384
440
  when 401
385
441
  raise APIKeyError, "Invalid API key" unless ENV["RACK_ENV"] == "test"
@@ -7,9 +7,14 @@ module GitAuto
7
7
  class GitService
8
8
  class Error < StandardError; end
9
9
 
10
- def get_staged_diff
10
+ def get_staged_diff(files = nil)
11
11
  validate_git_repository!
12
- execute_git_command("diff", "--cached")
12
+ if files
13
+ files = [files] unless files.is_a?(Array)
14
+ execute_git_command("diff", "--cached", "--", *files)
15
+ else
16
+ execute_git_command("diff", "--cached")
17
+ end
13
18
  end
14
19
 
15
20
  def get_staged_files
@@ -28,11 +28,15 @@ module GitAuto
28
28
 
29
29
  CONVENTIONAL_COMMIT_PATTERN = %r{
30
30
  ^(?<type>#{TYPES.keys.join("|")}) # Commit type
31
- (\((?<scope>[a-z0-9/_-]+)\))? # Optional scope in parentheses
31
+ (\((?<scope>[a-z0-9/_\.-]+)\))? # Optional scope in parentheses
32
32
  :\s # Colon and space separator
33
33
  (?<description>.+) # Commit description
34
34
  }x
35
35
 
36
+ def initialize(style = "conventional")
37
+ @style = style.to_s
38
+ end
39
+
36
40
  def validate(message)
37
41
  errors = []
38
42
  warnings = []
@@ -77,12 +81,17 @@ module GitAuto
77
81
 
78
82
  errors << "Header exceeds #{HEADER_MAX_LENGTH} characters" if header.length > HEADER_MAX_LENGTH
79
83
 
80
- # Validate header format for conventional and minimal commits
81
- minimal_pattern = MINIMAL_COMMIT_PATTERN
82
- conventional_pattern = CONVENTIONAL_COMMIT_PATTERN
83
-
84
- unless minimal_pattern.match?(header) || conventional_pattern.match?(header)
85
- errors << "Header must follow either minimal format: <type>: <description> or conventional format: <type>(<scope>): <description>"
84
+ # Validate header format based on style
85
+ case @style
86
+ when "conventional"
87
+ errors << "Header must follow conventional format: <type>(<scope>): <description>" unless CONVENTIONAL_COMMIT_PATTERN.match?(header)
88
+ when "minimal"
89
+ errors << "Header must follow minimal format: <type>: <description>" unless MINIMAL_COMMIT_PATTERN.match?(header)
90
+ when "simple", "detailed"
91
+ # No specific format required for simple and detailed styles
92
+ else
93
+ # For unknown styles, suggest using conventional format
94
+ warnings << "Unknown style '#{@style}', consider using conventional format: <type>(<scope>): <description>"
86
95
  end
87
96
 
88
97
  # Suggest using lowercase for consistency
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GitAuto
4
- VERSION = "0.2.0"
4
+ VERSION = "0.2.2"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: git_auto
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Guillermo Diaz
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-12-16 00:00:00.000000000 Z
11
+ date: 2025-03-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -212,6 +212,7 @@ description: GitAuto streamlines your git workflow by automatically generating m
212
212
  email:
213
213
  - diazgdev@gmail.com
214
214
  executables:
215
+ - git-auto
215
216
  - git_auto
216
217
  extensions: []
217
218
  extra_rdoc_files: []
@@ -219,6 +220,7 @@ files:
219
220
  - CHANGELOG.md
220
221
  - LICENSE.txt
221
222
  - README.md
223
+ - exe/git-auto
222
224
  - exe/git_auto
223
225
  - lib/git_auto.rb
224
226
  - lib/git_auto/cli.rb
@@ -261,7 +263,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
261
263
  - !ruby/object:Gem::Version
262
264
  version: '0'
263
265
  requirements: []
264
- rubygems_version: 3.5.23
266
+ rubygems_version: 3.5.22
265
267
  signing_key:
266
268
  specification_version: 4
267
269
  summary: AI-powered git commit messages using OpenAI or Anthropic APIs