Skip to content

Commit 1ae4a2a

Browse files
committed
[CI] Add workflow for preparing GPULlama3 release with version updates and changelog generation
1 parent ca30221 commit 1ae4a2a

1 file changed

Lines changed: 290 additions & 0 deletions

File tree

Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
name: Prepare GPULlama3 Release
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
version:
7+
description: 'Release version (e.g., 0.2.3)'
8+
required: true
9+
type: string
10+
previous_version:
11+
description: 'Previous version for changelog (e.g., 0.2.2)'
12+
required: true
13+
type: string
14+
dry_run:
15+
description: 'Dry run - show changes without creating PR'
16+
required: false
17+
type: boolean
18+
default: false
19+
20+
env:
21+
VERSION: ${{ inputs.version }}
22+
PREV_VERSION: ${{ inputs.previous_version }}
23+
24+
jobs:
25+
prepare-release:
26+
runs-on: [self-hosted, Linux, x64]
27+
permissions:
28+
contents: write
29+
pull-requests: write
30+
timeout-minutes: 15
31+
env:
32+
JAVA_HOME: /opt/jenkins/jdks/graal-23.1.0/jdk-21.0.3
33+
34+
steps:
35+
- name: Validate version format
36+
run: |
37+
if [[ ! "${{ inputs.version }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
38+
echo "❌ Invalid version format. Expected: X.Y.Z (e.g., 0.2.3)"
39+
exit 1
40+
fi
41+
echo "✅ Version format valid: ${{ inputs.version }}"
42+
43+
- name: Checkout main branch
44+
uses: actions/checkout@v4
45+
with:
46+
ref: main
47+
fetch-depth: 0
48+
token: ${{ secrets.GITHUB_TOKEN }}
49+
50+
- name: Setup environment
51+
run: |
52+
echo "$JAVA_HOME/bin" >> $GITHUB_PATH
53+
54+
- name: Configure Git
55+
run: |
56+
git config user.name "github-actions[bot]"
57+
git config user.email "github-actions[bot]@users.noreply.github.com"
58+
59+
- name: Create release branch
60+
run: |
61+
git checkout -b release/${{ env.VERSION }}
62+
echo "✅ Created branch: release/${{ env.VERSION }}"
63+
64+
# ============================================
65+
# VERSION UPDATES
66+
# ============================================
67+
68+
- name: Update Maven version
69+
run: |
70+
./mvnw versions:set -DnewVersion=${{ env.VERSION }} -DgenerateBackupPoms=false
71+
echo "✅ Maven version updated to ${{ env.VERSION }}"
72+
73+
- name: Update README.md
74+
run: |
75+
if [ -f "README.md" ]; then
76+
# Update version in Maven dependency example
77+
sed -i 's|<version>[0-9]\+\.[0-9]\+\.[0-9]\+</version>|<version>${{ env.VERSION }}</version>|g' README.md
78+
echo "✅ Updated README.md"
79+
fi
80+
81+
- name: Update CITATION.cff
82+
run: |
83+
if [ -f "CITATION.cff" ]; then
84+
sed -i "s/^version: .*/version: ${{ env.VERSION }}/" CITATION.cff
85+
RELEASE_DATE=$(date +"%Y-%m-%d")
86+
sed -i "s/^date-released: .*/date-released: $RELEASE_DATE/" CITATION.cff
87+
echo "✅ Updated CITATION.cff"
88+
fi
89+
90+
# ============================================
91+
# CHANGELOG GENERATION
92+
# ============================================
93+
94+
- name: Fetch merged PRs for changelog
95+
id: fetch_prs
96+
uses: actions/github-script@v7
97+
with:
98+
script: |
99+
const prevVersion = '${{ env.PREV_VERSION }}';
100+
const newVersion = '${{ env.VERSION }}';
101+
102+
let sinceDate;
103+
try {
104+
const { data: releases } = await github.rest.repos.listReleases({
105+
owner: context.repo.owner,
106+
repo: context.repo.repo,
107+
per_page: 10
108+
});
109+
110+
const prevRelease = releases.find(r =>
111+
r.tag_name === `v${prevVersion}` || r.tag_name === prevVersion
112+
);
113+
if (prevRelease) {
114+
sinceDate = prevRelease.published_at;
115+
console.log(`Found previous release ${prevVersion} from ${sinceDate}`);
116+
}
117+
} catch (e) {
118+
console.log('Could not fetch releases:', e.message);
119+
}
120+
121+
if (!sinceDate) {
122+
const date = new Date();
123+
date.setDate(date.getDate() - 90);
124+
sinceDate = date.toISOString();
125+
console.log(`Using fallback date: ${sinceDate}`);
126+
}
127+
128+
const { data: prs } = await github.rest.pulls.list({
129+
owner: context.repo.owner,
130+
repo: context.repo.repo,
131+
state: 'closed',
132+
sort: 'updated',
133+
direction: 'desc',
134+
per_page: 100
135+
});
136+
137+
const mergedPRs = prs.filter(pr =>
138+
pr.merged_at && new Date(pr.merged_at) > new Date(sinceDate)
139+
);
140+
141+
console.log(`Found ${mergedPRs.length} merged PRs since ${sinceDate}`);
142+
143+
const features = [];
144+
const bugfixes = [];
145+
const models = [];
146+
const performance = [];
147+
const other = [];
148+
149+
for (const pr of mergedPRs) {
150+
const labels = pr.labels.map(l => l.name.toLowerCase());
151+
const title = pr.title;
152+
const entry = `- ${title} ([#${pr.number}](${pr.html_url}))`;
153+
154+
if (labels.some(l => l.includes('bug') || l.includes('fix'))) {
155+
bugfixes.push(entry);
156+
} else if (labels.some(l => l.includes('model')) || title.toLowerCase().includes('model')) {
157+
models.push(entry);
158+
} else if (labels.some(l => l.includes('perf') || l.includes('optim'))) {
159+
performance.push(entry);
160+
} else if (labels.some(l => l.includes('feature') || l.includes('enhancement'))) {
161+
features.push(entry);
162+
} else {
163+
other.push(entry);
164+
}
165+
}
166+
167+
const today = new Date().toISOString().split('T')[0];
168+
let changelog = `## [${newVersion}] - ${today}\n\n`;
169+
170+
if (features.length > 0) {
171+
changelog += '### Features\n\n' + features.join('\n') + '\n\n';
172+
}
173+
if (models.length > 0) {
174+
changelog += '### Model Support\n\n' + models.join('\n') + '\n\n';
175+
}
176+
if (performance.length > 0) {
177+
changelog += '### Performance\n\n' + performance.join('\n') + '\n\n';
178+
}
179+
if (bugfixes.length > 0) {
180+
changelog += '### Bug Fixes\n\n' + bugfixes.join('\n') + '\n\n';
181+
}
182+
if (other.length > 0) {
183+
changelog += '### Other Changes\n\n' + other.join('\n') + '\n\n';
184+
}
185+
if (mergedPRs.length === 0) {
186+
changelog += '<!-- TODO: Add changes manually -->\n\n';
187+
}
188+
189+
const fs = require('fs');
190+
fs.writeFileSync('/tmp/changelog_entry.txt', changelog);
191+
core.setOutput('pr_count', mergedPRs.length);
192+
193+
- name: Update CHANGELOG.md
194+
run: |
195+
CHANGELOG_FILE="CHANGELOG.md"
196+
197+
if [ ! -f "$CHANGELOG_FILE" ]; then
198+
echo "# Changelog" > "$CHANGELOG_FILE"
199+
echo "" >> "$CHANGELOG_FILE"
200+
echo "All notable changes to GPULlama3.java will be documented in this file." >> "$CHANGELOG_FILE"
201+
echo "" >> "$CHANGELOG_FILE"
202+
fi
203+
204+
if grep -q "^## \[" "$CHANGELOG_FILE"; then
205+
FIRST_VERSION_LINE=$(grep -n "^## \[" "$CHANGELOG_FILE" | head -1 | cut -d: -f1)
206+
{
207+
head -n $((FIRST_VERSION_LINE - 1)) "$CHANGELOG_FILE"
208+
cat /tmp/changelog_entry.txt
209+
tail -n +$FIRST_VERSION_LINE "$CHANGELOG_FILE"
210+
} > /tmp/changelog_new.md
211+
mv /tmp/changelog_new.md "$CHANGELOG_FILE"
212+
else
213+
cat /tmp/changelog_entry.txt >> "$CHANGELOG_FILE"
214+
fi
215+
216+
echo "✅ Updated CHANGELOG.md"
217+
218+
- name: Show changes summary
219+
run: |
220+
echo "## 📋 Release ${{ env.VERSION }} Preparation" >> $GITHUB_STEP_SUMMARY
221+
echo "" >> $GITHUB_STEP_SUMMARY
222+
echo "### Files Modified:" >> $GITHUB_STEP_SUMMARY
223+
git diff --name-only | while read file; do
224+
echo "- \`$file\`" >> $GITHUB_STEP_SUMMARY
225+
done
226+
echo "" >> $GITHUB_STEP_SUMMARY
227+
echo "### PRs included: ${{ steps.fetch_prs.outputs.pr_count }}" >> $GITHUB_STEP_SUMMARY
228+
229+
- name: Commit and push
230+
if: ${{ inputs.dry_run == false }}
231+
run: |
232+
git add -A
233+
git commit -m "Prepare release ${{ env.VERSION }}"
234+
git push origin release/${{ env.VERSION }}
235+
236+
- name: Create Pull Request
237+
if: ${{ inputs.dry_run == false }}
238+
uses: actions/github-script@v7
239+
with:
240+
script: |
241+
const version = process.env.VERSION;
242+
const prCount = '${{ steps.fetch_prs.outputs.pr_count }}';
243+
244+
const { data: pr } = await github.rest.pulls.create({
245+
owner: context.repo.owner,
246+
repo: context.repo.repo,
247+
title: `Release ${version}`,
248+
head: `release/${version}`,
249+
base: 'main',
250+
body: `## 🚀 Release ${version}
251+
252+
### 📝 Changes
253+
- ${prCount} PRs included in changelog
254+
- Version bumped to ${version}
255+
256+
### ✅ Review Checklist
257+
- [ ] Version number correct in pom.xml
258+
- [ ] CHANGELOG.md reviewed
259+
- [ ] CI passes
260+
261+
### 🔄 After Merge
262+
1. **Finalize Release** → tag \`v${version}\` + GitHub release
263+
2. **Deploy to Maven Central** → publish artifacts
264+
`
265+
});
266+
267+
console.log(`✅ Created PR #${pr.number}: ${pr.html_url}`);
268+
269+
const reviewers = ['mikepapadim', 'orionpapadakis', 'mairooni' , 'stratika' ,'kotselidis'];
270+
try {
271+
await github.rest.pulls.requestReviewers({
272+
owner: context.repo.owner,
273+
repo: context.repo.repo,
274+
pull_number: pr.number,
275+
reviewers: reviewers
276+
});
277+
} catch (e) {
278+
console.log('Could not request reviewers:', e.message);
279+
}
280+
281+
- name: Dry run output
282+
if: ${{ inputs.dry_run == true }}
283+
run: |
284+
echo "🏃 DRY RUN MODE"
285+
echo ""
286+
echo "=== Files changed ==="
287+
git diff --stat
288+
echo ""
289+
echo "=== Changelog entry ==="
290+
cat /tmp/changelog_entry.txt

0 commit comments

Comments
 (0)