Skip to content

Commit 95ba377

Browse files
committed
feat(gitcommit): add AI-powered release notes generation tool
- implement comprehensive AI release notes generation with multiple styles - add support for detailed, concise, changelog, and marketing note formats - create flexible tool for analyzing commit history and generating release notes - enhance git extension with new AI-powered release notes capabilities
1 parent 793ebe3 commit 95ba377

File tree

5 files changed

+709
-24
lines changed

5 files changed

+709
-24
lines changed

README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,29 @@ local success, notes = gitcommit.exports.git_tool.generate_release_notes()
248248

249249
For detailed documentation, see: `:help codecompanion-gitcommit`
250250

251+
## 🤖 AI-Powered Release Notes
252+
253+
Generate comprehensive release notes using AI analysis of your commit history:
254+
255+
```vim
256+
" In CodeCompanion chat buffer:
257+
@{ai_release_notes} style:detailed from_tag:0.0.13 to_tag:0.0.14
258+
```
259+
260+
### Supported Styles
261+
262+
- `detailed` - Comprehensive notes with technical details and migration guides
263+
- `concise` - Brief summary of key changes
264+
- `changelog` - Developer-focused changelog following Keep a Changelog format
265+
- `marketing` - User-friendly marketing release notes
266+
267+
The AI will analyze your commits to:
268+
- Group changes by type (features, fixes, breaking changes)
269+
- Generate clear descriptions from commit messages
270+
- Credit contributors automatically
271+
- Provide migration instructions for breaking changes
272+
- Create appropriate formatting for your chosen style
273+
251274
## 🔒 Safety Features
252275

253276
- **Read-only operations** (`@{git_read}`) require no confirmation

lua/codecompanion/_extensions/gitcommit/init.lua

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,19 @@ local function setup_tools(opts)
103103
}
104104
end
105105

106+
-- Add AI Release Notes tool (always available if git_read is enabled)
107+
if git_read_enabled then
108+
local AIReleaseNotes = require("codecompanion._extensions.gitcommit.tools.ai_release_notes")
109+
chat_tools["ai_release_notes"] = {
110+
description = "Generate AI-powered release notes from commit history",
111+
callback = AIReleaseNotes,
112+
opts = {
113+
auto_submit_errors = opts.git_tool_auto_submit_errors,
114+
auto_submit_success = false, -- Don't auto-submit, let AI process the prompt
115+
},
116+
}
117+
end
118+
106119
if git_bot_enabled then
107120
chat_tools.groups = chat_tools.groups or {}
108121
chat_tools.groups["git_bot"] = {
@@ -141,6 +154,7 @@ When responding:
141154
tools = {
142155
"git_read",
143156
"git_edit",
157+
"ai_release_notes",
144158
},
145159
opts = {
146160
collapse_tools = true,
Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
local M = {}
2+
3+
-- Prompt templates for different release note styles
4+
M.templates = {
5+
detailed = {
6+
intro = [[You are an expert technical writer creating comprehensive release notes.
7+
Analyze the provided git commit history and create detailed release notes that:
8+
- Explain each change thoroughly with context
9+
- Include technical implementation details
10+
- Provide migration guides for breaking changes
11+
- Credit all contributors appropriately
12+
- Add helpful examples where relevant]],
13+
14+
format = [[
15+
# Release {version}
16+
17+
## 🎯 Overview
18+
[Provide a compelling summary of this release's purpose and main achievements]
19+
20+
## ✨ What's New
21+
22+
### Features
23+
[List and explain new features with examples]
24+
25+
### Improvements
26+
[Detail enhancements to existing functionality]
27+
28+
## 🐛 Bug Fixes
29+
[Describe fixed issues and their impact]
30+
31+
## 💔 Breaking Changes
32+
[List breaking changes with migration instructions]
33+
34+
## 🔧 Technical Details
35+
[Include implementation notes for developers]
36+
37+
## 📊 Statistics
38+
- Total commits: {commit_count}
39+
- Contributors: {contributor_count}
40+
- Files changed: {files_changed}
41+
42+
## 👥 Contributors
43+
[List contributors with their contributions]
44+
45+
## 📝 Full Changelog
46+
[Link or reference to complete commit list]
47+
]],
48+
},
49+
50+
concise = {
51+
intro = [[Create brief, scannable release notes focusing on user impact.
52+
Summarize changes in one-line bullet points, highlighting only the most important updates.]],
53+
54+
format = [[
55+
# Version {version}
56+
57+
## Key Changes
58+
- [Major feature or change 1]
59+
- [Major feature or change 2]
60+
- [Important bug fix]
61+
62+
## Quick Stats
63+
- {commit_count} commits from {contributor_count} contributors
64+
]],
65+
},
66+
67+
changelog = {
68+
intro = [[Generate a developer-focused CHANGELOG following Keep a Changelog format.
69+
Group changes by type (Added, Changed, Fixed, Deprecated, Removed, Security).
70+
Use technical language and include commit references.]],
71+
72+
format = [[
73+
## [{version}] - {date}
74+
75+
### Added
76+
- New features and additions
77+
78+
### Changed
79+
- Changes in existing functionality
80+
81+
### Fixed
82+
- Bug fixes
83+
84+
### Deprecated
85+
- Soon-to-be removed features
86+
87+
### Removed
88+
- Removed features
89+
90+
### Security
91+
- Security fixes and improvements
92+
93+
[{version}]: {compare_url}
94+
]],
95+
},
96+
97+
marketing = {
98+
intro = [[Write engaging, user-friendly release notes for a general audience.
99+
Focus on benefits and value, using non-technical language.
100+
Make it exciting and highlight how these changes improve the user experience.]],
101+
102+
format = [[
103+
# 🎉 {product_name} {version} is Here!
104+
105+
## What's New
106+
107+
### 🌟 Headline Feature
108+
[Exciting description of the main feature and its benefits]
109+
110+
### ✨ More Improvements You'll Love
111+
[User-friendly descriptions of other enhancements]
112+
113+
## 🐛 Squashed Bugs
114+
[Light-hearted mentions of fixed issues]
115+
116+
## 🙏 Thank You
117+
Special thanks to our amazing contributors who made this release possible!
118+
119+
[Call-to-action: Update now, try it out, etc.]
120+
]],
121+
},
122+
}
123+
124+
-- Helper function to analyze commits for smart categorization
125+
function M.analyze_commits(commits)
126+
local analysis = {
127+
features = {},
128+
fixes = {},
129+
breaking_changes = {},
130+
performance = {},
131+
documentation = {},
132+
refactoring = {},
133+
tests = {},
134+
other = {},
135+
contributors = {},
136+
stats = {
137+
total = #commits,
138+
by_type = {},
139+
},
140+
}
141+
142+
for _, commit in ipairs(commits) do
143+
-- Track contributors
144+
analysis.contributors[commit.author] = (analysis.contributors[commit.author] or 0) + 1
145+
146+
-- Categorize by conventional commit type
147+
local category = "other"
148+
local is_breaking = commit.subject:match("!") or commit.subject:match("BREAKING")
149+
150+
if is_breaking then
151+
table.insert(analysis.breaking_changes, commit)
152+
category = "breaking"
153+
elseif commit.type == "feat" or commit.type == "feature" then
154+
table.insert(analysis.features, commit)
155+
category = "features"
156+
elseif commit.type == "fix" or commit.type == "bugfix" then
157+
table.insert(analysis.fixes, commit)
158+
category = "fixes"
159+
elseif commit.type == "perf" then
160+
table.insert(analysis.performance, commit)
161+
category = "performance"
162+
elseif commit.type == "docs" then
163+
table.insert(analysis.documentation, commit)
164+
category = "documentation"
165+
elseif commit.type == "refactor" then
166+
table.insert(analysis.refactoring, commit)
167+
category = "refactoring"
168+
elseif commit.type == "test" or commit.type == "tests" then
169+
table.insert(analysis.tests, commit)
170+
category = "tests"
171+
else
172+
table.insert(analysis.other, commit)
173+
end
174+
175+
-- Track stats by type
176+
analysis.stats.by_type[category] = (analysis.stats.by_type[category] or 0) + 1
177+
end
178+
179+
return analysis
180+
end
181+
182+
-- Generate context-aware prompts based on commit analysis
183+
function M.create_smart_prompt(commits, style, version_info)
184+
local analysis = M.analyze_commits(commits)
185+
local template = M.templates[style] or M.templates.detailed
186+
187+
local prompt_parts = {
188+
template.intro,
189+
"\n\n",
190+
"VERSION INFORMATION:\n",
191+
string.format("- Previous version: %s\n", version_info.from),
192+
string.format("- New version: %s\n", version_info.to),
193+
string.format("- Release date: %s\n", os.date("%Y-%m-%d")),
194+
"\n",
195+
}
196+
197+
-- Add commit analysis summary
198+
table.insert(prompt_parts, "COMMIT ANALYSIS:\n")
199+
table.insert(prompt_parts, string.format("- Total commits: %d\n", analysis.stats.total))
200+
201+
if #analysis.features > 0 then
202+
table.insert(prompt_parts, string.format("- New features: %d\n", #analysis.features))
203+
end
204+
if #analysis.fixes > 0 then
205+
table.insert(prompt_parts, string.format("- Bug fixes: %d\n", #analysis.fixes))
206+
end
207+
if #analysis.breaking_changes > 0 then
208+
table.insert(
209+
prompt_parts,
210+
string.format("- BREAKING CHANGES: %d (requires careful documentation)\n", #analysis.breaking_changes)
211+
)
212+
end
213+
214+
local contributor_count = 0
215+
for _ in pairs(analysis.contributors) do
216+
contributor_count = contributor_count + 1
217+
end
218+
table.insert(prompt_parts, string.format("- Contributors: %d\n\n", contributor_count))
219+
220+
-- Add categorized commits
221+
if #analysis.breaking_changes > 0 then
222+
table.insert(prompt_parts, "⚠️ BREAKING CHANGES:\n")
223+
for _, commit in ipairs(analysis.breaking_changes) do
224+
table.insert(prompt_parts, string.format("- %s (by %s)\n", commit.subject, commit.author))
225+
if commit.body then
226+
table.insert(prompt_parts, string.format(" Details: %s\n", commit.body))
227+
end
228+
end
229+
table.insert(prompt_parts, "\n")
230+
end
231+
232+
if #analysis.features > 0 then
233+
table.insert(prompt_parts, "NEW FEATURES:\n")
234+
for _, commit in ipairs(analysis.features) do
235+
table.insert(prompt_parts, string.format("- %s\n", commit.subject))
236+
end
237+
table.insert(prompt_parts, "\n")
238+
end
239+
240+
if #analysis.fixes > 0 then
241+
table.insert(prompt_parts, "BUG FIXES:\n")
242+
for _, commit in ipairs(analysis.fixes) do
243+
table.insert(prompt_parts, string.format("- %s\n", commit.subject))
244+
end
245+
table.insert(prompt_parts, "\n")
246+
end
247+
248+
-- Add other categories if present
249+
if #analysis.performance > 0 then
250+
table.insert(prompt_parts, "PERFORMANCE IMPROVEMENTS:\n")
251+
for _, commit in ipairs(analysis.performance) do
252+
table.insert(prompt_parts, string.format("- %s\n", commit.subject))
253+
end
254+
table.insert(prompt_parts, "\n")
255+
end
256+
257+
-- Add format template
258+
table.insert(prompt_parts, "\nDESIRED OUTPUT FORMAT:\n")
259+
table.insert(prompt_parts, template.format)
260+
table.insert(prompt_parts, "\n\nPlease generate the release notes following the above format and guidelines.")
261+
262+
return table.concat(prompt_parts)
263+
end
264+
265+
return M

0 commit comments

Comments
 (0)