Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Release
name: Apps release
on:
push:
tags:
Expand Down
191 changes: 191 additions & 0 deletions .github/workflows/release-github.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
name: Github Release
on:
workflow_dispatch:
inputs:
tag:
description: "Release tag (e.g., v1.2.3)"
required: true
type: string

permissions:
contents: write
id-token: write

jobs:
create-draft-release:
name: Create Draft Release
runs-on: ubuntu-latest
steps:
- name: Validate semver tag
run: |
TAG="${{ github.event.inputs.tag }}"

# Check if tag matches semver pattern (v followed by MAJOR.MINOR.PATCH with optional pre-release and build metadata)
# Supports: v1.2.3, v1.2.3-rc.4, v1.2.3-beta.1, v1.2.3-alpha.1+build.123
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
echo "::error::Invalid tag format: $TAG"
echo "::error::Tag must be in semver format: v<MAJOR>.<MINOR>.<PATCH>[-PRERELEASE][+BUILD]"
echo "::error::Examples: v1.2.3, v1.2.3-rc.4, v1.2.3-beta.1, v1.2.3-alpha.1+build.123"
exit 1
fi

echo "::notice::Tag validation passed: $TAG"

- name: Checkout code
uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Extract version from tag
id: extract-version
run: |
TAG="${{ github.event.inputs.tag }}"
VERSION="${TAG#v}"
echo "tag=$TAG" >> $GITHUB_OUTPUT
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "::notice::Tag: $TAG"
echo "::notice::Version: $VERSION"

- name: Find previous tag
id: prev-tag
run: |
TAG="${{ steps.extract-version.outputs.tag }}"
PREV_TAG=$(git tag -l "v*.*.*" --sort=-version:refname | grep -v "^${TAG}$" | head -n1)

if [ -z "$PREV_TAG" ]; then
echo "::notice::No previous tag found, using initial commit"
PREV_TAG=$(git rev-list --max-parents=0 HEAD)
fi

echo "prev-tag=$PREV_TAG" >> $GITHUB_OUTPUT
echo "::notice::Previous tag: $PREV_TAG"

- name: Get list of Docker images
id: get-images
run: |
# Find all apps with Dockerfiles
IMAGES=""
for app_dir in apps/*/; do
if [ -f "${app_dir}Dockerfile" ]; then
APP_NAME=$(basename "$app_dir")
IMAGE_NAME="ev-node-${APP_NAME}"
IMAGES="${IMAGES}ghcr.io/${{ github.repository_owner }}/${IMAGE_NAME}:${{ steps.extract-version.outputs.tag }}\n"
fi
done

# Remove trailing newline
IMAGES=$(echo -e "$IMAGES" | sed '/^$/d')

# Escape for GitHub Actions output
IMAGES="${IMAGES//'%'/'%25'}"
IMAGES="${IMAGES//$'\n'/'%0A'}"
IMAGES="${IMAGES//$'\r'/'%0D'}"

echo "images=$IMAGES" >> $GITHUB_OUTPUT
echo "::notice::Found Docker images"

- name: Generate changelog prompt
id: changelog-prompt
run: |
PREV_TAG="${{ steps.prev-tag.outputs.prev-tag }}"
TAG="${{ steps.extract-version.outputs.tag }}"
VERSION="${{ steps.extract-version.outputs.version }}"

cat > claude-prompt.txt << 'EOF_PROMPT'
Read the file CHANGELOG.md and find the section for version $VERSION (tag $TAG).

Generate professional release notes for GitHub based on the changes listed for this specific version.

Create release notes with the following structure:

ev-node VERSION

⚠️ This is a draft release. Please verify its content before publishing

[Brief summary paragraph about this release - what type of release it is (feature/bugfix/maintenance), upgrade recommendations]

**Tested upgrade paths**
- [List version upgrade paths that were tested, or state "TBD - to be tested before publishing"]

## ⚠️ Breaking Changes

[If there are breaking changes, list each one with clear operational steps. If no breaking changes, state "None"]

### [Breaking Change Title]
**What changed:** [Clear description of what was changed/added/removed]

**Action required:**
1. [Step-by-step instructions on what operators need to do]
2. [Include configuration changes, file modifications, etc.]
3. [Provide examples where helpful]

**Reference:** [PR number if available]

---

## Full Changelog

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).

**Images**
EOF_PROMPT

# Replace placeholders with actual values
sed -i "s/\$VERSION/${VERSION}/g" claude-prompt.txt
sed -i "s/\$TAG/${TAG}/g" claude-prompt.txt

# Add the images list
echo "${{ steps.get-images.outputs.images }}" | while IFS= read -r image; do
echo "- $image" >> claude-prompt.txt
done

cat >> claude-prompt.txt << 'EOF_PROMPT'

Guidelines:
- Replace VERSION with the actual version number
- Replace YYYY-MM-DD with the actual release date
- ONLY include BREAKING changes in the "Breaking Changes" section
- For each breaking change, provide clear operational steps that operators must follow
- Include specific configuration file changes, command modifications, or migration steps
- Use numbered lists for action steps to make them easy to follow
- Do NOT duplicate the full changelog content - just reference CHANGELOG.md
- If there are no breaking changes, clearly state "None" in that section
- Use clear, professional language focused on operational impact
- Include PR numbers for breaking changes when available
- Format as clean markdown

Output the release notes as your response.
EOF_PROMPT

{
echo 'prompt<<EOF_CLAUDE_PROMPT'
cat claude-prompt.txt
echo EOF_CLAUDE_PROMPT
} >> $GITHUB_OUTPUT

- name: Generate release notes with Claude
id: claude-release
uses: anthropics/claude-code-action@v1

Check warning

Code scanning / CodeQL

Unpinned tag for a non-immutable Action in workflow Medium

Unpinned 3rd party Action 'Github Release' step
Uses Step: claude-release
uses 'anthropics/claude-code-action' with ref 'v1', not a pinned commit hash
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
prompt: ${{ steps.changelog-prompt.outputs.prompt }}
trusted_bots: "*"
allowed_tools: "Read(CHANGELOG.md)"
claude_args: |
--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"]}'

- name: Create Draft GitHub Release
id: create-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 'Github Release' step
Uses Step: create-release
uses 'softprops/action-gh-release' with ref 'v2', not a pinned commit hash
with:
draft: true
name: ${{ steps.extract-version.outputs.tag }} (${{ fromJSON(steps.claude-release.outputs.structured_output).release_date }})
tag_name: ${{ steps.extract-version.outputs.tag }}
body: ${{ fromJSON(steps.claude-release.outputs.structured_output).release_notes }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Output release URL
run: |
RELEASE_URL="https://github.com/${{ github.repository }}/releases/tag/${{ steps.extract-version.outputs.tag }}"
echo "::notice::Draft release created: $RELEASE_URL"
117 changes: 113 additions & 4 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,80 @@

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

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

---

## GitHub Releases (Manual Workflow)

### When to Use

Create official GitHub releases with professionally formatted release notes for version tags.

### Quick Steps

```bash
# 1. Ensure CHANGELOG.md is updated for the version
# 2. Navigate to GitHub Actions
# 3. Run "Github Release" workflow
# 4. Enter tag (e.g., v1.2.3)
# 5. Review and publish the draft release
```

### How It Works

The GitHub Release workflow (`.github/workflows/release-github.yml`) automates release note generation:

1. **Validates Tag Format** - Ensures tag follows semantic versioning (e.g., `v1.2.3`, `v1.2.3-rc.4`)
2. **Extracts Version Info** - Parses version from tag and finds previous release
3. **Discovers Docker Images** - Lists all Docker images that will be included in the release
4. **Generates Release Notes** - Uses Claude AI to read CHANGELOG.md and create professional release notes
5. **Creates Draft Release** - Publishes a draft GitHub release for review

### Release Notes Structure

The workflow generates release notes with:

- **Summary** - Overview of the release type and upgrade recommendations
- **Tested Upgrade Paths** - Version compatibility information
- **Changelog Sections**:
- Added (new features, with BREAKING changes highlighted)
- Changed (modifications, with BREAKING changes highlighted)
- Removed (deprecated features, with BREAKING changes highlighted)
- Fixed (bug fixes)
- **Docker Images** - List of all available Docker images for this release

### Requirements

- Tag must follow semantic versioning: `v<MAJOR>.<MINOR>.<PATCH>[-PRERELEASE][+BUILD]`
- Valid: `v1.2.3`, `v1.2.3-rc.4`, `v1.2.3-beta.1`, `v1.2.3-alpha.1+build.123`
- CHANGELOG.md must contain a section for the version being released
- `CLAUDE_CODE_OAUTH_TOKEN` secret must be configured in repository settings

### Workflow Dispatch

To trigger the workflow:

1. Go to **GitHub → Actions → Github Release**
2. Click **Run workflow**
3. Enter the release tag (e.g., `v1.2.3`)
4. Click **Run workflow**

The workflow will create a **draft release** that you can review and edit before publishing.

### Best Practices

- ✅ Update CHANGELOG.md before running the workflow
- ✅ Use clear, descriptive changelog entries
- ✅ Mark breaking changes explicitly in CHANGELOG.md
- ✅ Review the draft release before publishing
- ✅ Test upgrade paths and update release notes accordingly
- ✅ Ensure all Docker images are built and available

---

## Docker Image Releases (Automated)

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

## Common Release Scenarios

### Scenario 1: Release Single App (Docker Only)
### Scenario 1: Create GitHub Release

```bash
# 1. Update CHANGELOG.md with version changes
# 2. Commit and push changes
git add CHANGELOG.md
git commit -m "Update changelog for v1.2.3"
git push origin main

# 3. Go to GitHub Actions → Github Release → Run workflow
# 4. Enter tag: v1.2.3
# 5. Review draft release and publish
```

### Scenario 2: Release Single App (Docker Only)

```bash
# Tag and push - automation handles the rest
git tag evm/v0.2.0
git push origin evm/v0.2.0
```

### Scenario 2: Release Multiple Apps
### Scenario 3: Release Multiple Apps

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

### Scenario 3: Full Go Module Release
### Scenario 4: Full Go Module Release

```bash
# 1. Core
Expand All @@ -216,7 +299,7 @@ git tag execution/evm/v0.3.0 && git push origin execution/evm/v0.3.0
git tag apps/evm/v0.3.0 && git push origin apps/evm/v0.3.0
```

### Scenario 4: Hotfix/Patch Release
### Scenario 5: Hotfix/Patch Release

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

## Troubleshooting

### GitHub Releases

**"Invalid tag format" error**

- Ensure tag follows semantic versioning: `v1.2.3`
- Check for typos or incorrect format
- Valid examples: `v1.2.3`, `v1.2.3-rc.4`, `v1.2.3-beta.1`

**"Version not found in CHANGELOG.md"**

- Verify CHANGELOG.md contains a section for the version
- Check version format matches exactly (e.g., `v1.2.3` vs `1.2.3`)
- Ensure CHANGELOG.md is committed and pushed

**"Claude API error"**

- Verify `CLAUDE_CODE_OAUTH_TOKEN` secret is configured
- Check repository permissions for GitHub Actions
- Review workflow logs for specific error messages

**Empty or incomplete release notes**

- Ensure CHANGELOG.md has detailed entries for the version
- Check that changelog sections (Added, Changed, Fixed, etc.) are properly formatted
- Review the draft release and manually edit if needed

### Docker Releases

**"App directory does not exist"**
Expand Down
Loading