Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
323 changes: 322 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,213 @@
on:
push:
tags:
- '**/v*.*.*' # Matches tags like evm/single/v0.2.0, testapp/v0.4.0, etc.
- "**/v*.*.*" # Matches tags like evm/single/v0.2.0, testapp/v0.4.0, etc.

permissions: {}

jobs:
create-release-branch:
name: Create Release Branch
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
outputs:
release-branch: ${{ steps.create-branch.outputs.branch-name }}
app-path: ${{ steps.parse-tag.outputs.app-path }}
prev-tag: ${{ steps.get-prev-tag.outputs.prev-tag }}
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
fetch-depth: 0 # Full history needed for changelog generation

- name: Parse tag
id: parse-tag
run: |
TAG="${{ github.ref_name }}"
# Extract app path from tag (e.g., test-evm from test-evm/v0.2.0)
APP_PATH="${TAG%/v*}"
echo "app-path=$APP_PATH" >> $GITHUB_OUTPUT
echo "::notice::Application: $APP_PATH"
- name: Get previous tag
id: get-prev-tag
run: |
# Get the previous tag from the same application
CURRENT_TAG="${{ github.ref_name }}"
if [[ ! "$CURRENT_TAG" =~ ^[a-zA-Z0-9/_.-]+$ ]]; then
echo "::error::Invalid tag format: $CURRENT_TAG"
exit 1
fi
# Extract application prefix (everything before the version)
# e.g., test-evm/v0.2.0 -> test-evm
APP_PREFIX="${CURRENT_TAG%/v*}"
echo "::notice::Application prefix: $APP_PREFIX"
# Filter by app prefix and sort by version
MATCHING_TAGS=$(git tag --sort=-version:refname | grep "^${APP_PREFIX}/v")
echo "::notice::Found tags for $APP_PREFIX:"
echo "$MATCHING_TAGS" | head -4
# Get the previous tag (the one right after the current tag in the sorted list)
PREV_TAG=$(echo "$MATCHING_TAGS" | grep -A1 "^${CURRENT_TAG}$" | tail -1)
if [ -z "$PREV_TAG" ] || [ "$PREV_TAG" = "$CURRENT_TAG" ]; then
echo "::notice::No previous tag found for $APP_PREFIX, using initial commit"
PREV_TAG=$(git rev-list --max-parents=0 HEAD)
fi
echo "prev-tag=$PREV_TAG" >> $GITHUB_OUTPUT
echo "::notice::Comparing $PREV_TAG to $CURRENT_TAG"
- name: Create release branch
id: create-branch
run: |
TAG="${{ github.ref_name }}"
BRANCH_NAME="release/$TAG"
APP_PATH="${{ steps.parse-tag.outputs.app-path }}"
PREV_TAG="${{ steps.get-prev-tag.outputs.prev-tag }}"
echo "Creating release branch: $BRANCH_NAME"
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git checkout -b "$BRANCH_NAME"
# Generate a structured changelog
APP_DIR="apps/$APP_PATH"
CHANGELOG_FILE="$APP_DIR/CHANGELOG.md"
mkdir -p "$APP_DIR"
# Start the changelog
echo "# Release $TAG" > "$CHANGELOG_FILE"
echo "" >> "$CHANGELOG_FILE"
echo "Released on $(date +%Y-%m-%d)" >> "$CHANGELOG_FILE"
echo "" >> "$CHANGELOG_FILE"
# Get commit statistics
COMMIT_COUNT=$(git rev-list --count "$PREV_TAG"..HEAD)
FILES_CHANGED=$(git diff --shortstat "$PREV_TAG"..HEAD | sed 's/^[[:space:]]*//')
echo "## Summary" >> "$CHANGELOG_FILE"
echo "" >> "$CHANGELOG_FILE"
echo "- **$COMMIT_COUNT commits** since $PREV_TAG" >> "$CHANGELOG_FILE"
if [ -n "$FILES_CHANGED" ]; then
echo "- $FILES_CHANGED" >> "$CHANGELOG_FILE"
fi
echo "" >> "$CHANGELOG_FILE"
# Group commits by conventional commit type
echo "## Changes" >> "$CHANGELOG_FILE"
echo "" >> "$CHANGELOG_FILE"
# Features
FEATURES=$(git log --oneline "$PREV_TAG"..HEAD | grep -i "^[a-f0-9]* feat" || true)
if [ -n "$FEATURES" ]; then
echo "### ✨ Features" >> "$CHANGELOG_FILE"
echo "" >> "$CHANGELOG_FILE"
echo "$FEATURES" | sed 's/^[a-f0-9]* feat[:(]*[^)]*[)]* /- /' >> "$CHANGELOG_FILE"
echo "" >> "$CHANGELOG_FILE"
fi
# Fixes
FIXES=$(git log --oneline "$PREV_TAG"..HEAD | grep -i "^[a-f0-9]* fix" || true)
if [ -n "$FIXES" ]; then
echo "### 🐛 Bug Fixes" >> "$CHANGELOG_FILE"
echo "" >> "$CHANGELOG_FILE"
echo "$FIXES" | sed 's/^[a-f0-9]* fix[:(]*[^)]*[)]* /- /' >> "$CHANGELOG_FILE"
echo "" >> "$CHANGELOG_FILE"
fi
# Chores
CHORES=$(git log --oneline "$PREV_TAG"..HEAD | grep -i "^[a-f0-9]* chore" || true)
if [ -n "$CHORES" ]; then
echo "### 🔧 Chores" >> "$CHANGELOG_FILE"
echo "" >> "$CHANGELOG_FILE"
echo "$CHORES" | sed 's/^[a-f0-9]* chore[:(]*[^)]*[)]* /- /' >> "$CHANGELOG_FILE"
echo "" >> "$CHANGELOG_FILE"
fi
# Other commits
OTHER=$(git log --oneline "$PREV_TAG"..HEAD | grep -iv "^[a-f0-9]* \(feat\|fix\|chore\)" || true)
if [ -n "$OTHER" ]; then
echo "### 📝 Other Changes" >> "$CHANGELOG_FILE"
echo "" >> "$CHANGELOG_FILE"
echo "$OTHER" | sed 's/^[a-f0-9]* /- /' >> "$CHANGELOG_FILE"
echo "" >> "$CHANGELOG_FILE"
fi
# Full commit list
echo "---" >> "$CHANGELOG_FILE"
echo "" >> "$CHANGELOG_FILE"
echo "### All Commits" >> "$CHANGELOG_FILE"
echo "" >> "$CHANGELOG_FILE"
git log --oneline "$PREV_TAG"..HEAD | sed 's/^/- /' >> "$CHANGELOG_FILE"
echo "" >> "$CHANGELOG_FILE"
# Prepend to existing changelog if it exists
if [ -f "$CHANGELOG_FILE.old" ]; then
cat "$CHANGELOG_FILE.old" >> "$CHANGELOG_FILE"
rm "$CHANGELOG_FILE.old"
fi
echo "Generated changelog:"
cat "$CHANGELOG_FILE"
# Commit the changelog
git add "$CHANGELOG_FILE"
git commit -m "chore: add changelog for $TAG" \
-m "Generated structured changelog for $TAG release."
# Push the branch
git push origin "$BRANCH_NAME"
echo "branch-name=$BRANCH_NAME" >> $GITHUB_OUTPUT
echo "::notice::Created release branch: $BRANCH_NAME with changelog"
- name: Create Pull Request
id: create-pr
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG="${{ github.ref_name }}"
BRANCH_NAME="${{ steps.create-branch.outputs.branch-name }}"
PREV_TAG="${{ steps.get-prev-tag.outputs.prev-tag }}"
APP_PATH="${{ steps.parse-tag.outputs.app-path }}"
# Create the PR using GitHub CLI
PR_URL=$(gh pr create \
--base main \
--head "$BRANCH_NAME" \
--title "Release: $TAG" \
--body "## Release $TAG
This PR was automatically created for the release of \`$TAG\`.
**Previous tag:** \`$PREV_TAG\`
### Changelog
A structured changelog has been automatically generated and committed to \`apps/$APP_PATH/CHANGELOG.md\`.
The changelog includes:
- Summary of commits and file changes
- Changes grouped by type (Features, Bug Fixes, Chores, etc.)
- Full commit list
**To enhance the changelog with Claude AI:**
Check the draft release for a ready-to-use Claude prompt that you can copy and use in your IDE.
Please review the changes and changelog before merging.")
echo "pr-url=$PR_URL" >> $GITHUB_OUTPUT
echo "::notice::Created pull request: $PR_URL"
parse-tag:
name: Parse Release Tag
runs-on: ubuntu-latest
Expand Down Expand Up @@ -85,3 +288,121 @@
tags: |
ghcr.io/${{ github.repository_owner }}/${{ needs.parse-tag.outputs.image-name }}:${{ needs.parse-tag.outputs.version }}
ghcr.io/${{ github.repository_owner }}/${{ needs.parse-tag.outputs.image-name }}:latest
create-github-release:
name: Create GitHub Release
needs: [create-release-branch, parse-tag, build-and-push]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
ref: ${{ needs.create-release-branch.outputs.release-branch }}
fetch-depth: 0

- name: Generate changelog prompt
Comment on lines +299 to +305

Check warning

Code scanning / CodeQL

Checkout of untrusted code in trusted context Medium

Potential unsafe checkout of untrusted pull request on privileged workflow.

Copilot Autofix

AI about 10 hours ago

Copilot could not generate an autofix suggestion

Copilot could not generate an autofix suggestion for this alert. Try pushing a new commit or if the problem persists contact support.

id: changelog-prompt
run: |
PREV_TAG="${{ needs.create-release-branch.outputs.prev-tag }}"
TAG="${{ github.ref_name }}"
# Generate git diff data
git diff --stat "$PREV_TAG"..HEAD > git-diff-stats.txt
git log --oneline "$PREV_TAG"..HEAD > git-commits.txt
# Create prompt file (plain text, no markdown code blocks)
cat > claude-prompt.txt << 'EOF_PROMPT'
You are a technical writer creating release notes for a blockchain node software project called ev-node.
Analyze the provided git changes and generate a clear, comprehensive changelog in markdown format.
Follow these guidelines:
- Start with a brief summary of the release
- Group changes by category: Features, Bug Fixes, Performance, Documentation, etc.
- Use clear, concise bullet points
- Highlight breaking changes prominently if any
- Include technical details that would help developers understand the changes
- Format as clean markdown suitable for a GitHub release
Generate a changelog for this release based on the following git changes:
Commits:
EOF_PROMPT
cat git-commits.txt >> claude-prompt.txt
cat >> claude-prompt.txt << 'EOF_PROMPT'
File Statistics:
EOF_PROMPT
cat git-diff-stats.txt >> claude-prompt.txt
cat >> claude-prompt.txt << 'EOF_PROMPT'
Please generate a well-formatted changelog in markdown that summarizes these changes for users and developers.
EOF_PROMPT
# Encode for GitHub (escape special characters)
{
echo 'prompt<<EOF_CLAUDE_PROMPT'
cat claude-prompt.txt
echo EOF_CLAUDE_PROMPT
} >> $GITHUB_OUTPUT
- name: Create GitHub Release
uses: softprops/action-gh-release@v2

Check warning

Code scanning / CodeQL

Unpinned tag for a non-immutable Action in workflow Medium

Unpinned 3rd party Action 'Release' step
Uses Step
uses 'softprops/action-gh-release' with ref 'v2', not a pinned commit hash
with:
draft: true
name: ${{ github.ref_name }}
tag_name: ${{ github.ref_name }}
body: |
## ${{ needs.parse-tag.outputs.image-name }} ${{ needs.parse-tag.outputs.version }}
**⚠️ This is a draft release. Please update the following before publishing:**
- [ ] Add **Upgrade Priority** (Critical/High/Medium/Low)
- [ ] Add **General Description** of the release
- [ ] Enhance the **Changelog** using Claude (see prompt below)
- [ ] Document **Tested Upgrade Paths** (which versions were tested in E2E)
- [ ] Verify Docker images are available
- [ ] Publish announcements in Slack and Telegram after publishing
---
### Changelog
A basic changelog is available in: `apps/${{ needs.create-release-branch.outputs.app-path }}/CHANGELOG.md`
**To enhance the changelog with Claude AI:**
1. Open your IDE with Claude integration
2. Copy the prompt below and send it to Claude
3. Replace the changelog in `apps/${{ needs.create-release-branch.outputs.app-path }}/CHANGELOG.md` with Claude's output
4. Commit and push the changes to the release branch: `${{ needs.create-release-branch.outputs.release-branch }}`
<details>
<summary><b>📋 Click to expand Claude Prompt</b></summary>
```
${{ steps.changelog-prompt.outputs.prompt }}
```
</details>
---
### Docker Images
```bash
docker pull ghcr.io/${{ github.repository_owner }}/${{ needs.parse-tag.outputs.image-name }}:${{ needs.parse-tag.outputs.version }}
docker pull ghcr.io/${{ github.repository_owner }}/${{ needs.parse-tag.outputs.image-name }}:latest
```
### Release Branch
A release branch has been created for your review: `${{ needs.create-release-branch.outputs.release-branch }}`
You can checkout this branch to review and enhance the changelog before merging.
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Loading
Loading