Skip to content

Commit ad2e220

Browse files
committed
Merge remote-tracking branch 'origin/release/v11.2.1' into release/v11.2.1
2 parents 304a8d3 + a99780e commit ad2e220

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+4974
-1029
lines changed
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
name: Generate AI Changelog
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
current_tag:
7+
description: 'Current release tag (e.g., v11.2.0)'
8+
required: true
9+
type: string
10+
previous_tag:
11+
description: 'Previous tag to compare against (optional, auto-detected if not provided)'
12+
required: false
13+
type: string
14+
default: ''
15+
product_name:
16+
description: 'Product name for the changelog'
17+
required: false
18+
type: string
19+
default: 'UTMStack'
20+
product_description:
21+
description: 'Product description for context'
22+
required: false
23+
type: string
24+
default: 'Unified Threat Management and SIEM Platform'
25+
secrets:
26+
OPENAI_API_KEY:
27+
required: true
28+
outputs:
29+
changelog:
30+
description: 'Generated changelog content'
31+
value: ${{ jobs.generate-changelog.outputs.changelog }}
32+
previous_tag:
33+
description: 'The previous tag used for comparison'
34+
value: ${{ jobs.generate-changelog.outputs.previous_tag }}
35+
36+
jobs:
37+
generate-changelog:
38+
name: Generate AI Changelog
39+
runs-on: ubuntu-latest
40+
outputs:
41+
changelog: ${{ steps.generate-changelog.outputs.changelog }}
42+
previous_tag: ${{ steps.get-tags.outputs.previous_tag }}
43+
44+
steps:
45+
- name: Checkout code
46+
uses: actions/checkout@v4
47+
with:
48+
fetch-depth: 0
49+
50+
- name: Get previous tag
51+
id: get-tags
52+
run: |
53+
CURRENT_TAG="${{ inputs.current_tag }}"
54+
echo "Current release tag: $CURRENT_TAG"
55+
56+
# Use provided previous_tag or auto-detect
57+
if [ -n "${{ inputs.previous_tag }}" ]; then
58+
PREVIOUS_TAG="${{ inputs.previous_tag }}"
59+
echo "Using provided previous tag: $PREVIOUS_TAG"
60+
else
61+
# Get all tags sorted by version (newest first)
62+
ALL_TAGS=$(git tag --sort=-v:refname)
63+
FOUND_CURRENT=false
64+
PREVIOUS_TAG=""
65+
66+
for tag in $ALL_TAGS; do
67+
if [ "$FOUND_CURRENT" = true ]; then
68+
PREVIOUS_TAG="$tag"
69+
break
70+
fi
71+
if [ "$tag" = "$CURRENT_TAG" ]; then
72+
FOUND_CURRENT=true
73+
fi
74+
done
75+
76+
if [ -z "$PREVIOUS_TAG" ]; then
77+
# No previous tag found, get first commit
78+
PREVIOUS_TAG=$(git rev-list --max-parents=0 HEAD | head -1)
79+
echo "No previous tag found, using first commit: $PREVIOUS_TAG"
80+
fi
81+
fi
82+
83+
echo "Previous tag/commit: $PREVIOUS_TAG"
84+
echo "current_tag=$CURRENT_TAG" >> $GITHUB_OUTPUT
85+
echo "previous_tag=$PREVIOUS_TAG" >> $GITHUB_OUTPUT
86+
87+
- name: Get commits between tags
88+
id: get-commits
89+
run: |
90+
CURRENT_TAG="${{ steps.get-tags.outputs.current_tag }}"
91+
PREVIOUS_TAG="${{ steps.get-tags.outputs.previous_tag }}"
92+
93+
echo "Getting commits between $PREVIOUS_TAG and $CURRENT_TAG"
94+
95+
# Get commit messages with hash, author, and message
96+
COMMITS=$(git log ${PREVIOUS_TAG}..${CURRENT_TAG} --pretty=format:"- %h %s (%an)" --no-merges)
97+
98+
# Count commits
99+
COMMIT_COUNT=$(git rev-list --count ${PREVIOUS_TAG}..${CURRENT_TAG} --no-merges)
100+
101+
echo "Found $COMMIT_COUNT commits"
102+
103+
# Save commits to file (to handle multiline)
104+
echo "$COMMITS" > /tmp/commits.txt
105+
106+
# Also get changed files summary
107+
CHANGED_FILES=$(git diff --stat ${PREVIOUS_TAG}..${CURRENT_TAG} | tail -1)
108+
echo "changed_files=$CHANGED_FILES" >> $GITHUB_OUTPUT
109+
echo "commit_count=$COMMIT_COUNT" >> $GITHUB_OUTPUT
110+
111+
- name: Generate changelog with OpenAI
112+
id: generate-changelog
113+
env:
114+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
115+
PRODUCT_NAME: ${{ inputs.product_name }}
116+
PRODUCT_DESCRIPTION: ${{ inputs.product_description }}
117+
run: |
118+
COMMITS=$(cat /tmp/commits.txt)
119+
CURRENT_TAG="${{ steps.get-tags.outputs.current_tag }}"
120+
PREVIOUS_TAG="${{ steps.get-tags.outputs.previous_tag }}"
121+
COMMIT_COUNT="${{ steps.get-commits.outputs.commit_count }}"
122+
CHANGED_FILES="${{ steps.get-commits.outputs.changed_files }}"
123+
124+
# Create the prompt
125+
PROMPT="You are a product marketing writer creating release notes for end users of a software product.
126+
127+
Product: $PRODUCT_NAME - $PRODUCT_DESCRIPTION
128+
Release: $CURRENT_TAG
129+
130+
Here are the commit messages from this release:
131+
$COMMITS
132+
133+
Create user-friendly release notes in markdown format. This is for NON-TECHNICAL end users who want to know what's new and improved in the product.
134+
135+
IMPORTANT RULES:
136+
1. ONLY include changes that DIRECTLY AFFECT END USERS - things they can see, use, or benefit from
137+
2. COMPLETELY IGNORE internal/technical changes like:
138+
- CI/CD, GitHub Actions, deployment pipelines
139+
- Code refactoring, component restructuring
140+
- Database migrations, backend infrastructure
141+
- Internal API changes, gRPC, service communication
142+
- Developer tooling, linting, formatting
143+
- README updates, internal documentation
144+
3. Write in simple, non-technical language
145+
4. Focus on BENEFITS to the user, not implementation details
146+
5. Group into these categories ONLY (skip empty categories):
147+
- **What's New** - New features users can now use
148+
- **Improved** - Enhancements to existing features
149+
- **Fixed** - Bugs that were affecting users
150+
6. Start with a brief 1-2 sentence summary of the release highlights
151+
7. Use bullet points, be concise (one line per item)
152+
8. Do NOT wrap output in markdown code blocks
153+
9. Do NOT include commit hashes or author names
154+
10. If most commits are internal/technical, just summarize with 'Minor improvements and bug fixes'
155+
156+
Write the release notes directly in markdown format, ready to be used as-is."
157+
158+
# Call OpenAI API
159+
RESPONSE=$(curl -s https://api.openai.com/v1/chat/completions \
160+
-H "Content-Type: application/json" \
161+
-H "Authorization: Bearer $OPENAI_API_KEY" \
162+
-d "$(jq -n \
163+
--arg prompt "$PROMPT" \
164+
'{
165+
model: "gpt-4o-mini",
166+
messages: [
167+
{role: "system", content: "You are a technical writer specializing in software changelogs."},
168+
{role: "user", content: $prompt}
169+
],
170+
temperature: 0.3,
171+
max_tokens: 2000
172+
}')")
173+
174+
# Extract the changelog from response
175+
CHANGELOG=$(echo "$RESPONSE" | jq -r '.choices[0].message.content // empty')
176+
177+
if [ -z "$CHANGELOG" ]; then
178+
echo "Error: Failed to generate changelog"
179+
echo "Response: $RESPONSE"
180+
# Fallback to simple commit list
181+
CHANGELOG="## What's Changed
182+
183+
$COMMITS
184+
185+
**Full Changelog**: https://github.com/${{ github.repository }}/compare/${PREVIOUS_TAG}...${CURRENT_TAG}"
186+
fi
187+
188+
# Add comparison link at the end
189+
CHANGELOG="${CHANGELOG}
190+
191+
---
192+
**Full Changelog**: https://github.com/${{ github.repository }}/compare/${PREVIOUS_TAG}...${CURRENT_TAG}"
193+
194+
# Save changelog to file
195+
echo "$CHANGELOG" > /tmp/changelog.md
196+
197+
# Output changelog using multiline format
198+
echo "changelog<<EOF" >> $GITHUB_OUTPUT
199+
cat /tmp/changelog.md >> $GITHUB_OUTPUT
200+
echo "EOF" >> $GITHUB_OUTPUT
201+
202+
- name: Output changelog preview
203+
run: |
204+
echo "## Generated Changelog Preview"
205+
echo ""
206+
cat /tmp/changelog.md

0 commit comments

Comments
 (0)