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 +4 -4
- data/CHANGELOG.md +43 -7
- data/exe/git-auto +7 -0
- data/lib/git_auto/commands/commit_message_command.rb +35 -28
- data/lib/git_auto/commands/config_command.rb +14 -5
- data/lib/git_auto/config/settings.rb +5 -0
- data/lib/git_auto/services/ai_service.rb +148 -92
- data/lib/git_auto/services/git_service.rb +7 -2
- data/lib/git_auto/validators/commit_message_validator.rb +16 -7
- data/lib/git_auto/version.rb +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ca7a9199ac933b3d076abc6bcd1f82c5cc096a1c95604294aca7fd15dcccd05c
|
4
|
+
data.tar.gz: 128c56d3c6bee577a8f152c22f101b98f597524fc40b3cae42d5f63baf463e23
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9fa153d36b6081843dd3966c3835faa674c78ac3d742f3bce2e72c94bf388196096112531ca1df2abdc3c7e2cce70d6930c4af0c7e5cce73d8176dc4f7a23898
|
7
|
+
data.tar.gz: c10bf42f067af9a7947cd42c34b94928fccd1f2410d1349e81117182b6dbdd13f14e9bded9ae8725a02d5aa673ae89f1e82524d0f72ec52d12fa1c401bb25901
|
data/CHANGELOG.md
CHANGED
@@ -1,16 +1,52 @@
|
|
1
|
-
|
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
|
-
-
|
5
|
-
-
|
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
|
-
-
|
9
|
-
-
|
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
|
-
-
|
13
|
-
-
|
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
@@ -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 "
|
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
|
-
|
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
|
-
|
153
|
+
return unless validation[:errors].any? || validation[:warnings].any?
|
142
154
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
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
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
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
|
-
|
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
|
-
|
62
|
-
|
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.
|
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.
|
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.
|
180
|
+
@settings.save(save_history: save_history)
|
172
181
|
puts "✓ History settings updated".green
|
173
182
|
end
|
174
183
|
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
|
-
|
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
|
-
|
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.
|
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
|
154
|
+
raise EmptyDiffError, "No changes to commit" if diff.empty?
|
119
155
|
|
120
156
|
# If diff is too large, use the summarized version
|
121
|
-
|
122
|
-
|
123
|
-
|
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.
|
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
|
220
|
-
"
|
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.
|
223
|
-
"2. ALWAYS use
|
224
|
-
"3.
|
225
|
-
"4.
|
226
|
-
"
|
227
|
-
"
|
228
|
-
"
|
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
|
-
|
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.
|
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
|
281
|
-
"
|
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.
|
284
|
-
"2. ALWAYS use
|
285
|
-
"3.
|
286
|
-
"4.
|
287
|
-
"
|
288
|
-
"
|
289
|
-
"
|
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
|
-
|
321
|
-
|
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
|
-
|
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
|
-
|
362
|
-
|
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
|
-
|
428
|
+
raise Error, "No message content in response" if content.nil? || content.empty?
|
369
429
|
|
370
|
-
|
371
|
-
|
372
|
-
|
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
|
-
|
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/_
|
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
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
errors << "Header must follow
|
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
|
data/lib/git_auto/version.rb
CHANGED
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.
|
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:
|
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.
|
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
|