Skip to content

Commit 2510fe7

Browse files
authored
ci: release process with breaking changes (#2998)
* wip * release.md * tweak release
1 parent 432d5a7 commit 2510fe7

File tree

3 files changed

+305
-5
lines changed

3 files changed

+305
-5
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Release
1+
name: Apps release
22
on:
33
push:
44
tags:
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
name: Github Release
2+
on:
3+
workflow_dispatch:
4+
inputs:
5+
tag:
6+
description: "Release tag (e.g., v1.2.3)"
7+
required: true
8+
type: string
9+
10+
permissions:
11+
contents: write
12+
id-token: write
13+
14+
jobs:
15+
create-draft-release:
16+
name: Create Draft Release
17+
runs-on: ubuntu-latest
18+
steps:
19+
- name: Validate semver tag
20+
run: |
21+
TAG="${{ github.event.inputs.tag }}"
22+
23+
# Check if tag matches semver pattern (v followed by MAJOR.MINOR.PATCH with optional pre-release and build metadata)
24+
# Supports: v1.2.3, v1.2.3-rc.4, v1.2.3-beta.1, v1.2.3-alpha.1+build.123
25+
if ! echo "$TAG" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$'; then
26+
echo "::error::Invalid tag format: $TAG"
27+
echo "::error::Tag must be in semver format: v<MAJOR>.<MINOR>.<PATCH>[-PRERELEASE][+BUILD]"
28+
echo "::error::Examples: v1.2.3, v1.2.3-rc.4, v1.2.3-beta.1, v1.2.3-alpha.1+build.123"
29+
exit 1
30+
fi
31+
32+
echo "::notice::Tag validation passed: $TAG"
33+
34+
- name: Checkout code
35+
uses: actions/checkout@v6
36+
with:
37+
fetch-depth: 0
38+
39+
- name: Extract version from tag
40+
id: extract-version
41+
run: |
42+
TAG="${{ github.event.inputs.tag }}"
43+
VERSION="${TAG#v}"
44+
echo "tag=$TAG" >> $GITHUB_OUTPUT
45+
echo "version=$VERSION" >> $GITHUB_OUTPUT
46+
echo "::notice::Tag: $TAG"
47+
echo "::notice::Version: $VERSION"
48+
49+
- name: Find previous tag
50+
id: prev-tag
51+
run: |
52+
TAG="${{ steps.extract-version.outputs.tag }}"
53+
PREV_TAG=$(git tag -l "v*.*.*" --sort=-version:refname | grep -v "^${TAG}$" | head -n1)
54+
55+
if [ -z "$PREV_TAG" ]; then
56+
echo "::notice::No previous tag found, using initial commit"
57+
PREV_TAG=$(git rev-list --max-parents=0 HEAD)
58+
fi
59+
60+
echo "prev-tag=$PREV_TAG" >> $GITHUB_OUTPUT
61+
echo "::notice::Previous tag: $PREV_TAG"
62+
63+
- name: Get list of Docker images
64+
id: get-images
65+
run: |
66+
# Find all apps with Dockerfiles
67+
IMAGES=""
68+
for app_dir in apps/*/; do
69+
if [ -f "${app_dir}Dockerfile" ]; then
70+
APP_NAME=$(basename "$app_dir")
71+
IMAGE_NAME="ev-node-${APP_NAME}"
72+
IMAGES="${IMAGES}ghcr.io/${{ github.repository_owner }}/${IMAGE_NAME}:${{ steps.extract-version.outputs.tag }}\n"
73+
fi
74+
done
75+
76+
# Remove trailing newline
77+
IMAGES=$(echo -e "$IMAGES" | sed '/^$/d')
78+
79+
# Escape for GitHub Actions output
80+
IMAGES="${IMAGES//'%'/'%25'}"
81+
IMAGES="${IMAGES//$'\n'/'%0A'}"
82+
IMAGES="${IMAGES//$'\r'/'%0D'}"
83+
84+
echo "images=$IMAGES" >> $GITHUB_OUTPUT
85+
echo "::notice::Found Docker images"
86+
87+
- name: Generate changelog prompt
88+
id: changelog-prompt
89+
run: |
90+
PREV_TAG="${{ steps.prev-tag.outputs.prev-tag }}"
91+
TAG="${{ steps.extract-version.outputs.tag }}"
92+
VERSION="${{ steps.extract-version.outputs.version }}"
93+
94+
cat > claude-prompt.txt << 'EOF_PROMPT'
95+
Read the file CHANGELOG.md and find the section for version $VERSION (tag $TAG).
96+
97+
Generate professional release notes for GitHub based on the changes listed for this specific version.
98+
99+
Create release notes with the following structure:
100+
101+
ev-node VERSION
102+
103+
⚠️ This is a draft release. Please verify its content before publishing
104+
105+
[Brief summary paragraph about this release - what type of release it is (feature/bugfix/maintenance), upgrade recommendations]
106+
107+
**Tested upgrade paths**
108+
- [List version upgrade paths that were tested, or state "TBD - to be tested before publishing"]
109+
110+
## ⚠️ Breaking Changes
111+
112+
[If there are breaking changes, list each one with clear operational steps. If no breaking changes, state "None"]
113+
114+
### [Breaking Change Title]
115+
**What changed:** [Clear description of what was changed/added/removed]
116+
117+
**Action required:**
118+
1. [Step-by-step instructions on what operators need to do]
119+
2. [Include configuration changes, file modifications, etc.]
120+
3. [Provide examples where helpful]
121+
122+
**Reference:** [PR number if available]
123+
124+
---
125+
126+
## Full Changelog
127+
128+
For a complete list of all changes including new features, improvements, and bug fixes, see [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/$TAG/CHANGELOG.md#$VERSION).
129+
130+
**Images**
131+
EOF_PROMPT
132+
133+
# Replace placeholders with actual values
134+
sed -i "s/\$VERSION/${VERSION}/g" claude-prompt.txt
135+
sed -i "s/\$TAG/${TAG}/g" claude-prompt.txt
136+
137+
# Add the images list
138+
echo "${{ steps.get-images.outputs.images }}" | while IFS= read -r image; do
139+
echo "- $image" >> claude-prompt.txt
140+
done
141+
142+
cat >> claude-prompt.txt << 'EOF_PROMPT'
143+
144+
Guidelines:
145+
- Replace VERSION with the actual version number
146+
- Replace YYYY-MM-DD with the actual release date
147+
- ONLY include BREAKING changes in the "Breaking Changes" section
148+
- For each breaking change, provide clear operational steps that operators must follow
149+
- Include specific configuration file changes, command modifications, or migration steps
150+
- Use numbered lists for action steps to make them easy to follow
151+
- Do NOT duplicate the full changelog content - just reference CHANGELOG.md
152+
- If there are no breaking changes, clearly state "None" in that section
153+
- Use clear, professional language focused on operational impact
154+
- Include PR numbers for breaking changes when available
155+
- Format as clean markdown
156+
157+
Output the release notes as your response.
158+
EOF_PROMPT
159+
160+
{
161+
echo 'prompt<<EOF_CLAUDE_PROMPT'
162+
cat claude-prompt.txt
163+
echo EOF_CLAUDE_PROMPT
164+
} >> $GITHUB_OUTPUT
165+
166+
- name: Generate release notes with Claude
167+
id: claude-release
168+
uses: anthropics/claude-code-action@v1
169+
with:
170+
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
171+
prompt: ${{ steps.changelog-prompt.outputs.prompt }}
172+
trusted_bots: "*"
173+
allowed_tools: "Read(CHANGELOG.md)"
174+
claude_args: |
175+
--json-schema '{"type":"object","properties":{"release_notes":{"type":"string"},"release_date":{"type":"string","description":"Release date in YYYY-MM-DD format"}},"required":["release_notes","release_date"]}'
176+
177+
- name: Create Draft GitHub Release
178+
id: create-release
179+
uses: softprops/action-gh-release@v2
180+
with:
181+
draft: true
182+
name: ${{ steps.extract-version.outputs.tag }} (${{ fromJSON(steps.claude-release.outputs.structured_output).release_date }})
183+
tag_name: ${{ steps.extract-version.outputs.tag }}
184+
body: ${{ fromJSON(steps.claude-release.outputs.structured_output).release_notes }}
185+
env:
186+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
187+
188+
- name: Output release URL
189+
run: |
190+
RELEASE_URL="https://github.com/${{ github.repository }}/releases/tag/${{ steps.extract-version.outputs.tag }}"
191+
echo "::notice::Draft release created: $RELEASE_URL"

RELEASE.md

Lines changed: 113 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,80 @@
22

33
This document covers the release process for ev-node components:
44

5+
- **GitHub Releases** - Manual workflow to create draft releases with AI-generated release notes
56
- **Docker Image Releases** - Automated via GitHub workflows (for deployable applications)
67
- **Go Module Releases** - Manual process for library packages and dependencies
78

89
---
910

11+
## GitHub Releases (Manual Workflow)
12+
13+
### When to Use
14+
15+
Create official GitHub releases with professionally formatted release notes for version tags.
16+
17+
### Quick Steps
18+
19+
```bash
20+
# 1. Ensure CHANGELOG.md is updated for the version
21+
# 2. Navigate to GitHub Actions
22+
# 3. Run "Github Release" workflow
23+
# 4. Enter tag (e.g., v1.2.3)
24+
# 5. Review and publish the draft release
25+
```
26+
27+
### How It Works
28+
29+
The GitHub Release workflow (`.github/workflows/release-github.yml`) automates release note generation:
30+
31+
1. **Validates Tag Format** - Ensures tag follows semantic versioning (e.g., `v1.2.3`, `v1.2.3-rc.4`)
32+
2. **Extracts Version Info** - Parses version from tag and finds previous release
33+
3. **Discovers Docker Images** - Lists all Docker images that will be included in the release
34+
4. **Generates Release Notes** - Uses Claude AI to read CHANGELOG.md and create professional release notes
35+
5. **Creates Draft Release** - Publishes a draft GitHub release for review
36+
37+
### Release Notes Structure
38+
39+
The workflow generates release notes with:
40+
41+
- **Summary** - Overview of the release type and upgrade recommendations
42+
- **Tested Upgrade Paths** - Version compatibility information
43+
- **Changelog Sections**:
44+
- Added (new features, with BREAKING changes highlighted)
45+
- Changed (modifications, with BREAKING changes highlighted)
46+
- Removed (deprecated features, with BREAKING changes highlighted)
47+
- Fixed (bug fixes)
48+
- **Docker Images** - List of all available Docker images for this release
49+
50+
### Requirements
51+
52+
- Tag must follow semantic versioning: `v<MAJOR>.<MINOR>.<PATCH>[-PRERELEASE][+BUILD]`
53+
- Valid: `v1.2.3`, `v1.2.3-rc.4`, `v1.2.3-beta.1`, `v1.2.3-alpha.1+build.123`
54+
- CHANGELOG.md must contain a section for the version being released
55+
- `CLAUDE_CODE_OAUTH_TOKEN` secret must be configured in repository settings
56+
57+
### Workflow Dispatch
58+
59+
To trigger the workflow:
60+
61+
1. Go to **GitHub → Actions → Github Release**
62+
2. Click **Run workflow**
63+
3. Enter the release tag (e.g., `v1.2.3`)
64+
4. Click **Run workflow**
65+
66+
The workflow will create a **draft release** that you can review and edit before publishing.
67+
68+
### Best Practices
69+
70+
- ✅ Update CHANGELOG.md before running the workflow
71+
- ✅ Use clear, descriptive changelog entries
72+
- ✅ Mark breaking changes explicitly in CHANGELOG.md
73+
- ✅ Review the draft release before publishing
74+
- ✅ Test upgrade paths and update release notes accordingly
75+
- ✅ Ensure all Docker images are built and available
76+
77+
---
78+
1079
## Docker Image Releases (Automated)
1180

1281
### When to Use
@@ -182,15 +251,29 @@ go list -m github.com/evstack/ev-node/apps/evm@v0.3.0
182251

183252
## Common Release Scenarios
184253

185-
### Scenario 1: Release Single App (Docker Only)
254+
### Scenario 1: Create GitHub Release
255+
256+
```bash
257+
# 1. Update CHANGELOG.md with version changes
258+
# 2. Commit and push changes
259+
git add CHANGELOG.md
260+
git commit -m "Update changelog for v1.2.3"
261+
git push origin main
262+
263+
# 3. Go to GitHub Actions → Github Release → Run workflow
264+
# 4. Enter tag: v1.2.3
265+
# 5. Review draft release and publish
266+
```
267+
268+
### Scenario 2: Release Single App (Docker Only)
186269

187270
```bash
188271
# Tag and push - automation handles the rest
189272
git tag evm/v0.2.0
190273
git push origin evm/v0.2.0
191274
```
192275

193-
### Scenario 2: Release Multiple Apps
276+
### Scenario 3: Release Multiple Apps
194277

195278
```bash
196279
# Release apps independently
@@ -201,7 +284,7 @@ git push origin evm/single/v0.2.0 testapp/v1.0.0
201284
# Each triggers its own workflow
202285
```
203286

204-
### Scenario 3: Full Go Module Release
287+
### Scenario 4: Full Go Module Release
205288

206289
```bash
207290
# 1. Core
@@ -216,7 +299,7 @@ git tag execution/evm/v0.3.0 && git push origin execution/evm/v0.3.0
216299
git tag apps/evm/v0.3.0 && git push origin apps/evm/v0.3.0
217300
```
218301

219-
### Scenario 4: Hotfix/Patch Release
302+
### Scenario 5: Hotfix/Patch Release
220303

221304
```bash
222305
# For Docker images - delete and recreate
@@ -263,6 +346,32 @@ go get github.com/evstack/ev-node/core@v0.3.0
263346

264347
## Troubleshooting
265348

349+
### GitHub Releases
350+
351+
**"Invalid tag format" error**
352+
353+
- Ensure tag follows semantic versioning: `v1.2.3`
354+
- Check for typos or incorrect format
355+
- Valid examples: `v1.2.3`, `v1.2.3-rc.4`, `v1.2.3-beta.1`
356+
357+
**"Version not found in CHANGELOG.md"**
358+
359+
- Verify CHANGELOG.md contains a section for the version
360+
- Check version format matches exactly (e.g., `v1.2.3` vs `1.2.3`)
361+
- Ensure CHANGELOG.md is committed and pushed
362+
363+
**"Claude API error"**
364+
365+
- Verify `CLAUDE_CODE_OAUTH_TOKEN` secret is configured
366+
- Check repository permissions for GitHub Actions
367+
- Review workflow logs for specific error messages
368+
369+
**Empty or incomplete release notes**
370+
371+
- Ensure CHANGELOG.md has detailed entries for the version
372+
- Check that changelog sections (Added, Changed, Fixed, etc.) are properly formatted
373+
- Review the draft release and manually edit if needed
374+
266375
### Docker Releases
267376

268377
**"App directory does not exist"**

0 commit comments

Comments
 (0)