aigc 0.6.0 → 0.8.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: 731000c9272bd0e49dccf72a563483eaf7181ad8625b700681fc19ef20920f99
4
- data.tar.gz: 9abc3262a28663be3bf20e3b3f49f053cec6db3c31f41cbfc8305407f5c4b86d
3
+ metadata.gz: 77df6281418a993b1d1a4575403579a734b80e26bae4d25782e55d51cd32b56e
4
+ data.tar.gz: 03ee82eae23ed408a3887e770125129eed42d46d39b956a8139db60d2b213bef
5
5
  SHA512:
6
- metadata.gz: 5756382d91f21ac0e15e538fe129a794dc97df50be3de1fa0f4d5be8024f473cf5bfe1e2580e4cc192eb0a79e5cd125a69bbf2444c0a537915f5a2ef137fc304
7
- data.tar.gz: fb8967522a40b62a442875a34ec40a78e73fa7d82d60ba704cec33de61615c6ccdb515e9a2297b985885275a82c81d7a0b741f6dff34d5480bf09c15d1a53310
6
+ metadata.gz: f27de3cef28a0f21abed1b1d17d0891ec2740c5ba9b502f814bd6fae540535954382ceb3670ccba8f3234c2db7c2da59b37cf48e05eb97bf1c9a8fe09434e0f5
7
+ data.tar.gz: e763ed357ac9e15d96fdc23694175c895680ffa75fe9e5e2096a900217274d1714a63ffae5631b297d7a64bd0ff604d8648aef8b05e570ae2379946f806e0074
data/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.8.0] - 2025-01-27
4
+
5
+ ### Added
6
+ - Smart ticket number extraction from branch names
7
+ - Automatically detects ticket numbers like ABC-123, PROJ-456 from branch names
8
+ - Supports common branch naming patterns: feature/ABC-123, bugfix/PROJ-456, etc.
9
+ - Includes ticket numbers in commit message scope when relevant
10
+ - Refactored commit guidelines into a constant for DRY code
11
+
12
+ ## [0.7.0] - 2025-01-27
13
+
14
+ ### Added
15
+ - `--hash` option to generate commit messages from diff between HEAD and specified commit
16
+ - Users can now run `aigc --hash abc123` to generate a message for changes between commit abc123 and HEAD
17
+ - Useful for analyzing existing commits or generating messages for uncommitted changes since a specific commit
18
+ - Added `Git.commit_diff` method to get diff between two commits
19
+
3
20
  ## [0.6.0] - 2025-01-27
4
21
 
5
22
  ### Changed
@@ -29,30 +29,36 @@ module Ai
29
29
 
30
30
  private
31
31
 
32
+ COMMIT_GUIDELINES = <<~GUIDELINES
33
+ 1. Use conventional commit format: type(scope): description
34
+ 2. Keep subject line under 50 characters
35
+ 3. Use imperative mood ("add" not "added")
36
+ 4. Separate subject from body with blank line
37
+ 5. Use 'feat' for new features, 'fix' for bug fixes, 'docs' for documentation, 'style' for formatting, 'refactor' for code refactoring, 'test' for tests, 'chore' for build/tooling
38
+ 6. Be clear and specific about what changed, not just "update"
39
+ 7. Explain the impact/benefit when relevant
40
+ 8. Include scope based on file structure (e.g., auth, bank, api, components)
41
+ 9. Reference any related components or services affected
42
+ 10. For breaking changes, start with 'BREAKING CHANGE:'
43
+ 11. Use bullet points in body for multiple changes
44
+ 12. Include ticket numbers in scope when available (e.g., auth(ABC-123): description)
45
+ 13. Match existing project commit style
46
+ GUIDELINES
47
+
32
48
  def build_prompt(diff)
33
49
  custom_prompts = Config.custom_prompts
34
50
  custom_prompt_text = custom_prompts.empty? ? '' : "\n\nAdditional context and preferences:\n#{custom_prompts.join("\n")}"
35
51
 
52
+ ticket_number = Git.extract_ticket_from_branch
53
+ ticket_context = ticket_number ? "\n\nTicket number from branch: #{ticket_number} (include in scope if relevant)" : ""
54
+
36
55
  <<~PROMPT
37
56
  You are a helpful assistant that generates conventional commit messages.
38
57
 
39
58
  Based on the following git diff, generate a conventional commit message that:
40
- 1. Use conventional commit format: type(scope): description
41
- 2. Keep subject line under 50 characters
42
- 3. Use imperative mood ("add" not "added")
43
- 4. Separate subject from body with blank line
44
- 5. Wrap body at 72 characters
45
- 6. Use 'feat' for new features, 'fix' for bug fixes, 'docs' for documentation, 'style' for formatting, 'refactor' for code refactoring, 'test' for tests, 'chore' for build/tooling
46
- 7. Be clear and specific about what changed, not just "update"
47
- 8. Explain the impact/benefit when relevant
48
- 9. Include scope based on file structure (e.g., auth, bank, api, components)
49
- 10. Reference any related components or services affected
50
- 11. For breaking changes, start with 'BREAKING CHANGE:'
51
- 12. Use bullet points in body for multiple changes
52
- 13. Reference ticket numbers when applicable
53
- 14. Match existing project commit style
59
+ #{COMMIT_GUIDELINES}
54
60
 
55
- #{custom_prompt_text}
61
+ #{custom_prompt_text}#{ticket_context}
56
62
 
57
63
  Git diff:
58
64
  #{diff}
@@ -65,28 +71,18 @@ module Ai
65
71
  custom_prompts = Config.custom_prompts
66
72
  custom_prompt_text = custom_prompts.empty? ? '' : "\n\nAdditional context and preferences:\n#{custom_prompts.join("\n")}"
67
73
 
74
+ ticket_number = Git.extract_ticket_from_branch
75
+ ticket_context = ticket_number ? "\n\nTicket number from branch: #{ticket_number} (include in scope if relevant)" : ""
76
+
68
77
  feedback_text = feedback_array.map.with_index { |feedback, i| "#{i + 1}. #{feedback}" }.join("\n")
69
78
 
70
79
  <<~PROMPT
71
80
  You are a helpful assistant that generates conventional commit messages.
72
81
 
73
82
  Based on the following git diff, generate a conventional commit message that:
74
- 1. Use conventional commit format: type(scope): description
75
- 2. Keep subject line under 50 characters
76
- 3. Use imperative mood ("add" not "added")
77
- 4. Separate subject from body with blank line
78
- 5. Wrap body at 72 characters
79
- 6. Use 'feat' for new features, 'fix' for bug fixes, 'docs' for documentation, 'style' for formatting, 'refactor' for code refactoring, 'test' for tests, 'chore' for build/tooling
80
- 7. Be clear and specific about what changed, not just "update"
81
- 8. Explain the impact/benefit when relevant
82
- 9. Include scope based on file structure (e.g., auth, bank, api, components)
83
- 10. Reference any related components or services affected
84
- 11. For breaking changes, start with 'BREAKING CHANGE:'
85
- 12. Use bullet points in body for multiple changes
86
- 13. Reference ticket numbers when applicable
87
- 14. Match existing project commit style
83
+ #{COMMIT_GUIDELINES}
88
84
 
89
- #{custom_prompt_text}
85
+ #{custom_prompt_text}#{ticket_context}
90
86
 
91
87
  IMPORTANT: The user has provided feedback on previous attempts. Please address ALL of the following feedback:
92
88
  #{feedback_text}
data/lib/ai/commit/cli.rb CHANGED
@@ -70,6 +70,7 @@ module Ai
70
70
  end
71
71
 
72
72
  desc "commit", "Generate a commit message and commit with confirmation"
73
+ option :hash, :type => :string, :desc => "Generate message from diff between HEAD and specified commit hash"
73
74
  def commit
74
75
  unless Config.api_key_configured?
75
76
  puts "āŒ No API key configured. Please run 'aigc setup' first."
@@ -81,15 +82,32 @@ module Ai
81
82
  exit 1
82
83
  end
83
84
 
84
- unless Git.has_staged_changes?
85
- puts "āŒ No staged changes found. Stage your changes with 'git add' first."
86
- exit 1
85
+ if options[:hash]
86
+ puts "šŸ¤– Generating commit message from diff between HEAD and #{options[:hash]}..."
87
+
88
+ begin
89
+ diff = Git.commit_diff(options[:hash])
90
+ rescue => e
91
+ puts "āŒ Error getting commit diff: #{e.message}"
92
+ exit 1
93
+ end
94
+ else
95
+ unless Git.has_staged_changes?
96
+ puts "āŒ No staged changes found. Stage your changes with 'git add' first."
97
+ exit 1
98
+ end
99
+
100
+ puts "šŸ¤– Generating commit message..."
101
+
102
+ begin
103
+ diff = Git.staged_diff
104
+ rescue => e
105
+ puts "āŒ Error getting staged diff: #{e.message}"
106
+ exit 1
107
+ end
87
108
  end
88
109
 
89
- puts "šŸ¤– Generating commit message..."
90
-
91
110
  begin
92
- diff = Git.staged_diff
93
111
  client = ClaudeClient.new(Config.api_key)
94
112
  message = client.generate_commit_message(diff)
95
113
 
@@ -97,25 +115,21 @@ module Ai
97
115
  puts "=" * 50
98
116
  puts message
99
117
  puts "=" * 50
100
-
101
- print "\nCommit with this message? (y/N/e to edit/r to regenerate): "
102
- response = STDIN.gets.chomp.downcase
103
-
104
- if response == 'y' || response == 'yes'
105
- puts "\nšŸš€ Committing..."
106
- result = system("git", "commit", "-m", message)
107
118
 
108
- if result
109
- puts "āœ… Successfully committed!"
119
+ if options[:hash]
120
+ print "\nCopy this message? (y/N/e to edit/r to regenerate): "
110
121
  else
111
- puts "āŒ Failed to commit"
112
- exit 1
122
+ print "\nCommit with this message? (y/N/e to edit/r to regenerate): "
113
123
  end
114
- elsif response == 'e' || response == 'edit'
115
- edited_message = edit_message(message)
116
- if edited_message && !edited_message.strip.empty?
117
- puts "\nšŸš€ Committing with edited message..."
118
- result = system("git", "commit", "-m", edited_message)
124
+ response = STDIN.gets.chomp.downcase
125
+
126
+ if response == 'y' || response == 'yes'
127
+ if options[:hash]
128
+ puts "\nšŸ“‹ Message ready to copy:"
129
+ puts message
130
+ else
131
+ puts "\nšŸš€ Committing..."
132
+ result = system("git", "commit", "-m", message)
119
133
 
120
134
  if result
121
135
  puts "āœ… Successfully committed!"
@@ -123,14 +137,36 @@ module Ai
123
137
  puts "āŒ Failed to commit"
124
138
  exit 1
125
139
  end
140
+ end
141
+ elsif response == 'e' || response == 'edit'
142
+ edited_message = edit_message(message)
143
+ if edited_message && !edited_message.strip.empty?
144
+ if options[:hash]
145
+ puts "\nšŸ“‹ Edited message ready to copy:"
146
+ puts edited_message
147
+ else
148
+ puts "\nšŸš€ Committing with edited message..."
149
+ result = system("git", "commit", "-m", edited_message)
150
+
151
+ if result
152
+ puts "āœ… Successfully committed!"
153
+ else
154
+ puts "āŒ Failed to commit"
155
+ exit 1
156
+ end
157
+ end
126
158
  else
127
- puts "āŒ Commit cancelled."
159
+ puts "āŒ Operation cancelled."
128
160
  exit 0
129
161
  end
130
162
  elsif response == 'r' || response == 'regenerate'
131
- regenerate_with_feedback(diff, client, 1, [])
163
+ regenerate_with_feedback(diff, client, 1, [], options[:hash])
132
164
  else
133
- puts "āŒ Commit cancelled."
165
+ if options[:hash]
166
+ puts "āŒ Operation cancelled."
167
+ else
168
+ puts "āŒ Commit cancelled."
169
+ end
134
170
  exit 0
135
171
  end
136
172
 
@@ -219,7 +255,7 @@ module Ai
219
255
  edited_content
220
256
  end
221
257
 
222
- def regenerate_with_feedback(diff, client, attempt = 1, accumulated_feedback = [])
258
+ def regenerate_with_feedback(diff, client, attempt = 1, accumulated_feedback = [], is_hash_mode = false)
223
259
  if attempt > 3
224
260
  puts "\nāš ļø Maximum regenerations (3) reached. Please commit with the current message or edit it manually."
225
261
  return
@@ -251,18 +287,27 @@ module Ai
251
287
  puts new_message
252
288
  puts "=" * 50
253
289
 
254
- print "\nCommit with this message? (y/N/e to edit/r to regenerate again): "
290
+ if is_hash_mode
291
+ print "\nCopy this message? (y/N/e to edit/r to regenerate again): "
292
+ else
293
+ print "\nCommit with this message? (y/N/e to edit/r to regenerate again): "
294
+ end
255
295
  response = STDIN.gets.chomp.downcase
256
296
 
257
297
  if response == 'y' || response == 'yes'
258
- puts "\nšŸš€ Committing..."
259
- result = system("git", "commit", "-m", new_message)
260
-
261
- if result
262
- puts "āœ… Successfully committed!"
298
+ if is_hash_mode
299
+ puts "\nšŸ“‹ Message ready to copy:"
300
+ puts new_message
263
301
  else
264
- puts "āŒ Failed to commit"
265
- exit 1
302
+ puts "\nšŸš€ Committing..."
303
+ result = system("git", "commit", "-m", new_message)
304
+
305
+ if result
306
+ puts "āœ… Successfully committed!"
307
+ else
308
+ puts "āŒ Failed to commit"
309
+ exit 1
310
+ end
266
311
  end
267
312
  elsif response == 'e' || response == 'edit'
268
313
  edited_message = edit_message(new_message)
@@ -281,7 +326,7 @@ module Ai
281
326
  exit 0
282
327
  end
283
328
  elsif response == 'r' || response == 'regenerate'
284
- regenerate_with_feedback(diff, client, attempt + 1, all_feedback)
329
+ regenerate_with_feedback(diff, client, attempt + 1, all_feedback, is_hash_mode)
285
330
  else
286
331
  puts "āŒ Commit cancelled."
287
332
  exit 0
data/lib/ai/commit/git.rb CHANGED
@@ -24,6 +24,48 @@ module Ai
24
24
  def self.has_staged_changes?
25
25
  !`git diff --cached --name-only`.strip.empty?
26
26
  end
27
+
28
+ def self.current_branch
29
+ result = `git branch --show-current`
30
+ result.strip if $?.exitstatus == 0
31
+ end
32
+
33
+ def self.extract_ticket_from_branch
34
+ branch_name = current_branch
35
+ return nil unless branch_name
36
+
37
+ # Common patterns: ABC-123, PROJ-456, JIRA-789, etc.
38
+ # Look for patterns like: feature/ABC-123, bugfix/PROJ-456, hotfix/JIRA-789
39
+ ticket_match = branch_name.match(/(?:feature|bugfix|hotfix|fix|feat|chore|docs|style|refactor|test|perf|revert)\/([A-Z]+-\d+)/i)
40
+
41
+ if ticket_match
42
+ return ticket_match[1]
43
+ end
44
+
45
+ # Also check for ticket numbers without prefixes
46
+ ticket_match = branch_name.match(/([A-Z]+-\d+)/)
47
+ ticket_match ? ticket_match[1] : nil
48
+ end
49
+
50
+ def self.commit_diff(commit_hash)
51
+ # Validate the commit hash exists
52
+ unless system("git rev-parse --verify #{commit_hash}", out: File::NULL, err: File::NULL)
53
+ raise Error, "Commit hash '#{commit_hash}' not found"
54
+ end
55
+
56
+ # Get the diff between HEAD and the specified commit
57
+ result = `git diff #{commit_hash}..HEAD`
58
+
59
+ if $?.exitstatus != 0
60
+ raise Error, "Failed to get diff between #{commit_hash} and HEAD"
61
+ end
62
+
63
+ if result.empty?
64
+ raise Error, "No differences found between #{commit_hash} and HEAD"
65
+ end
66
+
67
+ result
68
+ end
27
69
  end
28
70
  end
29
71
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Ai
4
4
  module Commit
5
- VERSION = "0.6.0"
5
+ VERSION = "0.8.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aigc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Behrang Mirzamani