diff --git a/.github/RELEASE_NOTES_SETUP.md b/.github/RELEASE_NOTES_SETUP.md index 02093381..89369cc3 100644 --- a/.github/RELEASE_NOTES_SETUP.md +++ b/.github/RELEASE_NOTES_SETUP.md @@ -1,434 +1,472 @@ -# AI-Generated Release Notes Setup - -This repository uses Claude AI to automatically generate comprehensive release notes when you create a new release. - -## How It Works - -The workflow triggers when: -- You push a new tag (e.g., `v1.0.0`) -- You create a GitHub release -- You manually trigger it via workflow dispatch - -Claude AI analyzes: -- Commit messages since the last release -- Merged pull requests -- File changes by component (frontend, backend, docs) -- Contributors - -Then generates structured release notes with: -- Overview and key changes -- Feature additions, improvements, and bug fixes -- Technical changes by component -- Statistics and contributor acknowledgments -- Breaking changes (important for beta!) - -## Testing Locally First (Recommended!) - -Before setting up the GitHub Action, you can test the release notes generation locally: - -### Prerequisites - -```bash -# Install required tools (if not already installed) -sudo apt install jq curl # Linux -# or -brew install jq curl # macOS - -# Install GitHub CLI (optional, for PR detection) -# See: https://github.com/cli/cli#installation -``` - -### Run Local Test - -```bash -# 1. Export your Anthropic API key -export ANTHROPIC_API_KEY="sk-ant-api03-..." - -# 2. Run the test script - -# Compare origin/stable vs main branches (default - shows unreleased changes) -./.github/test-release-notes.sh - -# Or specify branches explicitly (automatically handles remote branches) -./.github/test-release-notes.sh stable main # Will use origin/stable if no local stable -./.github/test-release-notes.sh origin/stable main # Explicit remote branch - -# Or use range syntax -./.github/test-release-notes.sh stable..main - -# Or compare tags for a release -./.github/test-release-notes.sh v1.0.0 v2.0.0 - -# Or test a single tag (compares with previous tag) -./.github/test-release-notes.sh v0.1.0 -``` - -### What the Local Test Does - -1. **Gathers git data**: Commits, file changes, and PRs (if gh CLI available) -2. **Calls Claude API**: Generates release notes using the same prompt as the workflow -3. **Saves output**: Creates `release-notes-.md` in current directory -4. **Shows preview**: Displays the generated notes in your terminal - -### Example Output - -```bash -$ ./.github/test-release-notes.sh v0.2.0 - -🤖 Local Release Notes Generator Test -========================================== - -Current tag: v0.2.0 -Previous tag: v0.1.0 - -📝 Gathering commits... -Found 42 commits - -📊 Analyzing file changes... -Files summary: 28 files changed, 1547 insertions(+), 423 deletions(-) - -🔀 Looking for merged PRs... -Found 8 merged PRs - -🤖 Generating release notes with Claude... -✅ Release notes generated successfully! - -📄 Output saved to: release-notes-v0.2.0.md - -========================================== -Preview: -========================================== -[Generated release notes appear here] -========================================== -✅ Done! -``` - -### Testing Different Scenarios - -```bash -# 🔥 MOST COMMON: See what's new in main vs stable (unreleased changes) -./.github/test-release-notes.sh -# Output: release-notes-origin-stable..main.md - -# Or with explicit arguments -./.github/test-release-notes.sh stable main -# Output: release-notes-origin-stable..main.md (auto-resolves to origin/stable) - -# Test your first release (compares with initial commit) -./.github/test-release-notes.sh v0.1.0 - -# Test a release between two specific tags -./.github/test-release-notes.sh v1.0.0 v2.0.0 - -# Test what would be in next release (current branch vs stable) -git checkout main -./.github/test-release-notes.sh stable main -``` - -### Typical Workflow: Stable vs Main - -For projects with separate `stable` (production) and `main` (development) branches: - -```bash -# 1. See what's ready to release (compare branches) -export ANTHROPIC_API_KEY="sk-ant-..." -./.github/test-release-notes.sh stable main -# Or explicitly use remote branch: ./.github/test-release-notes.sh origin/stable main - -# 2. Review the generated notes -cat release-notes-origin-stable..main.md - -# 3. When ready to release, fetch latest and merge main to stable -git fetch origin -git checkout -b stable origin/stable # Create local tracking branch if needed -git merge main -git push origin stable - -# 4. Create a release tag -git tag v1.0.0 -git push origin v1.0.0 - -# 5. The GitHub Action will automatically generate release notes -# (You can also manually create the release with the generated notes) -gh release create v1.0.0 --title "Release v1.0.0" --notes-file release-notes-origin-stable..main.md -``` - -## Setup Instructions - -### 1. Create Anthropic API Key - -1. Go to [Anthropic Console](https://console.anthropic.com/) -2. Create a new API key -3. Copy the key (starts with `sk-ant-...`) - -### 2. Add GitHub Secret - -1. Go to your repository's Settings -2. Navigate to **Secrets and variables** → **Actions** -3. Click **New repository secret** -4. Name: `ANTHROPIC_API_KEY` -5. Value: Paste your Anthropic API key -6. Click **Add secret** - -### 3. Test the Workflow - -#### Option A: Create a Release via GitHub UI - -1. Go to **Releases** in your repository -2. Click **Draft a new release** -3. Choose or create a tag (e.g., `v0.1.0`) -4. Click **Publish release** -5. The workflow will automatically run and update the release notes - -#### Option B: Push a Tag via Git - -```bash -# Create and push a new tag -git tag v0.1.0 -git push origin v0.1.0 - -# The workflow will automatically create a release with AI-generated notes -``` - -#### Option C: Manual Trigger - -1. Go to **Actions** tab -2. Select "AI-Generated Release Notes" workflow -3. Click **Run workflow** -4. Enter the tag name (e.g., `v0.1.0`) -5. Click **Run workflow** - -## Usage Examples - -### Creating Your First Release - -```bash -# Tag your current state -git tag v0.1.0-beta - -# Push the tag -git push origin v0.1.0-beta - -# Check Actions tab - release notes will be generated automatically -``` - -### Creating Subsequent Releases - -```bash -# Make your changes and commits -git add . -git commit -m "feat: Add AI-powered search feature" -git push - -# When ready to release -git tag v0.2.0-beta -git push origin v0.2.0-beta - -# Release notes will compare v0.2.0-beta with v0.1.0-beta -``` - -## What Gets Generated - -The AI generates release notes in this structure: - -```markdown -# 🚀 Release v0.2.0 - -## 📝 Overview -[Summary of the release] - -## ✨ What's New - -### Major Features -- [New features] - -### Improvements -- [Enhancements] - -### Bug Fixes -- [Fixes] - -## 🔧 Technical Changes - -### Backend (Python/FastAPI) -- [Backend changes] - -### Frontend (React/TypeScript) -- [Frontend changes] - -### Infrastructure -- [Infrastructure updates] - -## 📊 Statistics -- Commits: X -- Pull Requests: Y -- Files Changed: Z -- Contributors: N - -## 🙏 Contributors -[List of contributors] - -## ⚠️ Breaking Changes -[Any breaking changes] - -## 🔗 Links -- Full Changelog: [link] -``` - -## Customization - -### Modify the Prompt - -Edit `.github/workflows/release-notes.yml` and change the prompt in the "Generate release notes with Claude" step to adjust: -- Tone and style -- Structure -- Focus areas -- Level of detail - -### Change Claude Model - -In the workflow file, you can change the model: - -```yaml -"model": "claude-sonnet-4-20250514" # Latest Sonnet -# or -"model": "claude-3-7-sonnet-20250219" # Sonnet 3.7 -# or -"model": "claude-opus-4-20250514" # Opus 4 (more detailed) -``` - -### Adjust Token Limit - -Increase `max_tokens` for longer release notes: - -```yaml -"max_tokens": 4096 # Default -# or -"max_tokens": 8192 # For more detailed notes -``` - -## Troubleshooting - -### Workflow Fails with "ANTHROPIC_API_KEY not found" - -- Ensure you've added the secret in repository settings -- Secret name must be exactly `ANTHROPIC_API_KEY` -- Secret must be a valid Anthropic API key - -### Empty or Incomplete Release Notes - -- Check if commits exist between tags -- Verify git history is complete (workflow uses `fetch-depth: 0`) -- Check Actions logs for API errors - -### API Rate Limits - -- Anthropic has generous rate limits for API keys -- For very frequent releases, consider caching or batching - -## Cost Estimation - -Claude API pricing (as of 2025): -- Sonnet 4: ~$0.003 per release (assuming ~4K tokens) -- Each release generation costs less than a penny - -For a project with monthly releases: ~$0.036/year - -## Best Practices - -### Write Good Commit Messages - -The AI works better with clear commits: - -```bash -# ✅ Good -git commit -m "feat: Add vector search with pgvector" -git commit -m "fix: Resolve race condition in crawling service" -git commit -m "docs: Update API documentation" - -# ❌ Less helpful -git commit -m "updates" -git commit -m "fix stuff" -git commit -m "wip" -``` - -### Use Conventional Commits - -The workflow benefits from conventional commit format: -- `feat:` - New features -- `fix:` - Bug fixes -- `docs:` - Documentation -- `refactor:` - Code refactoring -- `test:` - Tests -- `chore:` - Maintenance - -### Tag Semantically - -Use semantic versioning: -- `v1.0.0` - Major release -- `v1.1.0` - Minor release (new features) -- `v1.1.1` - Patch release (bug fixes) -- `v0.1.0-beta` - Beta releases - -## Manual Editing - -You can always edit the generated release notes: - -1. Go to the release page -2. Click **Edit release** -3. Modify the notes as needed -4. Click **Update release** - -## Workflow Outputs - -The workflow provides: -- Updated GitHub release with AI-generated notes -- Artifact with release notes (kept for 90 days) -- Comments on related PRs linking to the release -- Summary in Actions tab - -## Advanced: Using with Pre-releases - -```bash -# Create a pre-release -git tag v0.2.0-rc.1 -git push origin v0.2.0-rc.1 - -# Mark as pre-release in GitHub UI or via gh CLI -gh release create v0.2.0-rc.1 --prerelease -``` - -## Integration with Other Tools - -### Notify Slack/Discord - -Add a notification step after release creation: - -```yaml -- name: Notify team - run: | - curl -X POST YOUR_WEBHOOK_URL \ - -H 'Content-Type: application/json' \ - -d '{"text":"Release ${{ steps.get_tag.outputs.tag }} published!"}' -``` - -### Update Changelog File - -Append to CHANGELOG.md: - -```yaml -- name: Update changelog - run: | - cat release_notes.md >> CHANGELOG.md - git add CHANGELOG.md - git commit -m "docs: Update changelog for ${{ steps.get_tag.outputs.tag }}" - git push -``` - -## Support - -If you encounter issues: -1. Check the workflow logs in Actions tab -2. Verify your API key is valid -3. Ensure git history is available -4. Open an issue with workflow logs attached +# AI-Generated Release Notes Setup + +This repository uses Claude AI to automatically generate comprehensive release notes when you create a new release. + +## How It Works + +The workflow triggers when: +- You push a new tag (e.g., `v1.0.0`) +- You create a GitHub release +- You manually trigger it via workflow dispatch + +Claude AI analyzes: +- Commit messages since the last release +- Merged pull requests +- File changes by component (frontend, backend, docs) +- Contributors + +Then generates structured release notes with: +- Overview and key changes +- Feature additions, improvements, and bug fixes +- Technical changes by component +- Statistics and contributor acknowledgments +- Breaking changes (important for beta!) + +## Testing Locally First (Recommended!) + +Before setting up the GitHub Action, you can test the release notes generation locally: + +### Prerequisites + +```bash +# Install required tools (if not already installed) +sudo apt install jq curl # Linux +# or +brew install jq curl # macOS + +# Install GitHub CLI (optional, for PR detection) +# See: https://github.com/cli/cli#installation +``` + +### Run Local Test + +```bash +# 1. Export your Anthropic API key +export ANTHROPIC_API_KEY="sk-ant-api03-..." + +# 2. Run the test script + +# Compare origin/stable vs main branches (default - shows unreleased changes) +./.github/test-release-notes.sh + +# Or specify branches explicitly (automatically handles remote branches) +./.github/test-release-notes.sh stable main # Will use origin/stable if no local stable +./.github/test-release-notes.sh origin/stable main # Explicit remote branch + +# Or use range syntax +./.github/test-release-notes.sh stable..main + +# Or compare tags for a release +./.github/test-release-notes.sh v1.0.0 v2.0.0 + +# Or test a single tag (compares with previous tag) +./.github/test-release-notes.sh v0.1.0 +``` + +### What the Local Test Does + +1. **Gathers git data**: Commits, file changes, and PRs (if gh CLI available) +2. **Calls Claude API**: Generates release notes using the same prompt as the workflow +3. **Saves output**: Creates `release-notes-.md` in current directory +4. **Shows preview**: Displays the generated notes in your terminal + +### Example Output + +```bash +$ ./.github/test-release-notes.sh v0.2.0 + +🤖 Local Release Notes Generator Test +========================================== + +Current tag: v0.2.0 +Previous tag: v0.1.0 + +📝 Gathering commits... +Found 42 commits + +📊 Analyzing file changes... +Files summary: 28 files changed, 1547 insertions(+), 423 deletions(-) + +🔀 Looking for merged PRs... +Found 8 merged PRs + +🤖 Generating release notes with Claude... +✅ Release notes generated successfully! + +📄 Output saved to: release-notes-v0.2.0.md + +========================================== +Preview: +========================================== +[Generated release notes appear here] +========================================== +✅ Done! +``` + +### Testing Different Scenarios + +```bash +# 🔥 MOST COMMON: See what's new in main vs stable (unreleased changes) +./.github/test-release-notes.sh +# Output: release-notes-origin-stable..main.md + +# Or with explicit arguments +./.github/test-release-notes.sh stable main +# Output: release-notes-origin-stable..main.md (auto-resolves to origin/stable) + +# Test your first release (compares with initial commit) +./.github/test-release-notes.sh v0.1.0 + +# Test a release between two specific tags +./.github/test-release-notes.sh v1.0.0 v2.0.0 + +# Test what would be in next release (current branch vs stable) +git checkout main +./.github/test-release-notes.sh stable main +``` + +### Typical Workflow: Stable vs Main + +For projects with separate `stable` (production) and `main` (development) branches: + +```bash +# 1. See what's ready to release (compare branches) +export ANTHROPIC_API_KEY="sk-ant-..." +./.github/test-release-notes.sh stable main +# Or explicitly use remote branch: ./.github/test-release-notes.sh origin/stable main + +# 2. Review the generated notes +cat release-notes-origin-stable..main.md + +# 3. When ready to release, fetch latest and merge main to stable +git fetch origin +git checkout -b stable origin/stable # Create local tracking branch if needed +git merge main +git push origin stable + +# 4. Create a release tag +git tag v1.0.0 +git push origin v1.0.0 + +# 5. The GitHub Action will automatically generate release notes +# (You can also manually create the release with the generated notes) +gh release create v1.0.0 --title "Release v1.0.0" --notes-file release-notes-origin-stable..main.md +``` + +## Setup Instructions + +### 1. Get Claude Code OAuth Token + +The GitHub Action uses Claude Code OAuth token (same as the `claude-review` workflow): + +1. Go to [Claude Code OAuth Setup](https://docs.anthropic.com/claude-code/oauth) +2. Follow the instructions to get your OAuth token +3. Copy the token + +### 2. Add GitHub Secret + +1. Go to your repository's Settings +2. Navigate to **Secrets and variables** → **Actions** +3. Click **New repository secret** +4. Name: `CLAUDE_CODE_OAUTH_TOKEN` +5. Value: Paste your Claude Code OAuth token +6. Click **Add secret** + +> **Note:** If you already have `CLAUDE_CODE_OAUTH_TOKEN` set up for `claude-review` workflow, you're all set! The same token is used for both workflows. + +### 3. (Optional) Get Anthropic API Key for Local Testing + +For local testing, you'll need an API key: + +1. Go to [Anthropic Console](https://console.anthropic.com/) +2. Create a new API key +3. Copy the key (starts with `sk-ant-...`) +4. Export it: `export ANTHROPIC_API_KEY="sk-ant-..."` + +> **Note:** The GitHub Action uses OAuth token, but local testing uses API key for simplicity. + +### 4. Test the Workflow + +#### Option A: Create a Release via GitHub UI + +1. Go to **Releases** in your repository +2. Click **Draft a new release** +3. Choose or create a tag (e.g., `v0.1.0`) +4. Click **Publish release** +5. The workflow will automatically run and update the release notes + +#### Option B: Push a Tag via Git + +```bash +# Create and push a new tag +git tag v0.1.0 +git push origin v0.1.0 + +# The workflow will automatically create a release with AI-generated notes +``` + +#### Option C: Manual Trigger + +1. Go to **Actions** tab +2. Select "AI-Generated Release Notes" workflow +3. Click **Run workflow** +4. Enter the tag name (e.g., `v0.1.0`) +5. Click **Run workflow** + +## Usage Examples + +### Creating Your First Release + +```bash +# Tag your current state +git tag v0.1.0-beta + +# Push the tag +git push origin v0.1.0-beta + +# Check Actions tab - release notes will be generated automatically +``` + +### Creating Subsequent Releases + +```bash +# Make your changes and commits +git add . +git commit -m "feat: Add AI-powered search feature" +git push + +# When ready to release +git tag v0.2.0-beta +git push origin v0.2.0-beta + +# Release notes will compare v0.2.0-beta with v0.1.0-beta +``` + +## What Gets Generated + +The AI generates release notes in this structure: + +```markdown +# 🚀 Release v0.2.0 + +## 📝 Overview +[Summary of the release] + +## ✨ What's New + +### Major Features +- [New features] + +### Improvements +- [Enhancements] + +### Bug Fixes +- [Fixes] + +## 🔧 Technical Changes + +### Backend (Python/FastAPI) +- [Backend changes] + +### Frontend (React/TypeScript) +- [Frontend changes] + +### Infrastructure +- [Infrastructure updates] + +## 📊 Statistics +- Commits: X +- Pull Requests: Y +- Files Changed: Z +- Contributors: N + +## 🙏 Contributors +[List of contributors] + +## ⚠️ Breaking Changes +[Any breaking changes] + +## 🔗 Links +- Full Changelog: [link] +``` + +## Customization + +### Modify the Prompt + +Edit `.github/workflows/release-notes.yml` and change the prompt in the "Generate release notes with Claude" step to adjust: +- Tone and style +- Structure +- Focus areas +- Level of detail + +### Change Claude Model + +In the workflow file, you can change the model: + +```yaml +"model": "claude-sonnet-4-20250514" # Latest Sonnet +# or +"model": "claude-3-7-sonnet-20250219" # Sonnet 3.7 +# or +"model": "claude-opus-4-20250514" # Opus 4 (more detailed) +``` + +### Adjust Token Limit + +Increase `max_tokens` for longer release notes: + +```yaml +"max_tokens": 4096 # Default +# or +"max_tokens": 8192 # For more detailed notes +``` + +## Troubleshooting + +### Workflow Fails with "ANTHROPIC_API_KEY not found" + +- Ensure you've added the secret in repository settings +- Secret name must be exactly `ANTHROPIC_API_KEY` +- Secret must be a valid Anthropic API key + +### Empty or Incomplete Release Notes + +- Check if commits exist between tags +- Verify git history is complete (workflow uses `fetch-depth: 0`) +- Check Actions logs for API errors + +### API Rate Limits + +- Anthropic has generous rate limits for API keys +- For very frequent releases, consider caching or batching + +## Authentication: GitHub Action vs Local Testing + +### GitHub Action (Claude Code OAuth) +- Uses `CLAUDE_CODE_OAUTH_TOKEN` secret +- Same authentication as `claude-review` workflow +- Integrated with GitHub through Claude Code Action +- No direct API costs (usage included with Claude Code) + +### Local Testing (API Key) +- Uses `ANTHROPIC_API_KEY` environment variable +- Direct API calls to Claude +- Simpler for local testing and debugging +- Cost: ~$0.003 per release (less than a penny) + +### Why Two Methods? + +- **GitHub Action**: Uses Claude Code Action for better GitHub integration and consistency with other workflows +- **Local Testing**: Uses direct API for simplicity and faster iteration during development + +## Cost Estimation + +### Local Testing (API Key) +Claude API pricing (as of 2025): +- Sonnet 4: ~$0.003 per release (assuming ~4K tokens) +- Each release generation costs less than a penny +- For a project with monthly releases: ~$0.036/year + +### GitHub Action (OAuth Token) +- No additional costs beyond your Claude Code subscription +- Usage included in Claude Code plan + +## Best Practices + +### Write Good Commit Messages + +The AI works better with clear commits: + +```bash +# ✅ Good +git commit -m "feat: Add vector search with pgvector" +git commit -m "fix: Resolve race condition in crawling service" +git commit -m "docs: Update API documentation" + +# ❌ Less helpful +git commit -m "updates" +git commit -m "fix stuff" +git commit -m "wip" +``` + +### Use Conventional Commits + +The workflow benefits from conventional commit format: +- `feat:` - New features +- `fix:` - Bug fixes +- `docs:` - Documentation +- `refactor:` - Code refactoring +- `test:` - Tests +- `chore:` - Maintenance + +### Tag Semantically + +Use semantic versioning: +- `v1.0.0` - Major release +- `v1.1.0` - Minor release (new features) +- `v1.1.1` - Patch release (bug fixes) +- `v0.1.0-beta` - Beta releases + +## Manual Editing + +You can always edit the generated release notes: + +1. Go to the release page +2. Click **Edit release** +3. Modify the notes as needed +4. Click **Update release** + +## Workflow Outputs + +The workflow provides: +- Updated GitHub release with AI-generated notes +- Artifact with release notes (kept for 90 days) +- Comments on related PRs linking to the release +- Summary in Actions tab + +## Advanced: Using with Pre-releases + +```bash +# Create a pre-release +git tag v0.2.0-rc.1 +git push origin v0.2.0-rc.1 + +# Mark as pre-release in GitHub UI or via gh CLI +gh release create v0.2.0-rc.1 --prerelease +``` + +## Integration with Other Tools + +### Notify Slack/Discord + +Add a notification step after release creation: + +```yaml +- name: Notify team + run: | + curl -X POST YOUR_WEBHOOK_URL \ + -H 'Content-Type: application/json' \ + -d '{"text":"Release ${{ steps.get_tag.outputs.tag }} published!"}' +``` + +### Update Changelog File + +Append to CHANGELOG.md: + +```yaml +- name: Update changelog + run: | + cat release_notes.md >> CHANGELOG.md + git add CHANGELOG.md + git commit -m "docs: Update changelog for ${{ steps.get_tag.outputs.tag }}" + git push +``` + +## Support + +If you encounter issues: +1. Check the workflow logs in Actions tab +2. Verify your API key is valid +3. Ensure git history is available +4. Open an issue with workflow logs attached diff --git a/.github/workflows/release-notes.yml b/.github/workflows/release-notes.yml index 5b89afc5..0c8fa247 100644 --- a/.github/workflows/release-notes.yml +++ b/.github/workflows/release-notes.yml @@ -1,314 +1,323 @@ -name: AI-Generated Release Notes - -on: - release: - types: [created, published] - push: - tags: - - 'v*.*.*' - workflow_dispatch: - inputs: - tag_name: - description: 'Tag name (e.g., v1.0.0)' - required: true - type: string - -permissions: - contents: write - pull-requests: read - -jobs: - generate-release-notes: - name: Generate Release Notes with Claude - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 # Full git history - - - name: Get release tag - id: get_tag - run: | - if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then - echo "tag=${{ inputs.tag_name }}" >> $GITHUB_OUTPUT - elif [ "${{ github.event_name }}" == "release" ]; then - echo "tag=${{ github.event.release.tag_name }}" >> $GITHUB_OUTPUT - else - echo "tag=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT - fi - - - name: Get previous tag - id: prev_tag - run: | - CURRENT_TAG="${{ steps.get_tag.outputs.tag }}" - PREVIOUS_TAG=$(git tag --sort=-v:refname | grep -A1 "^${CURRENT_TAG}$" | tail -1) - - if [ -z "$PREVIOUS_TAG" ] || [ "$PREVIOUS_TAG" == "$CURRENT_TAG" ]; then - # First release or no previous tag - use initial commit - PREVIOUS_TAG=$(git rev-list --max-parents=0 HEAD) - echo "previous_tag=$PREVIOUS_TAG" >> $GITHUB_OUTPUT - echo "is_first_release=true" >> $GITHUB_OUTPUT - else - echo "previous_tag=$PREVIOUS_TAG" >> $GITHUB_OUTPUT - echo "is_first_release=false" >> $GITHUB_OUTPUT - fi - - - name: Get commit messages - id: commits - run: | - CURRENT_TAG="${{ steps.get_tag.outputs.tag }}" - PREVIOUS_TAG="${{ steps.prev_tag.outputs.previous_tag }}" - - # Get commit history - COMMITS=$(git log ${PREVIOUS_TAG}..${CURRENT_TAG} --pretty=format:"- %s (%h) by %an" --no-merges) - - # Save to file to preserve formatting - echo "$COMMITS" > commits.txt - - # Get stats - COMMIT_COUNT=$(echo "$COMMITS" | wc -l) - echo "commit_count=$COMMIT_COUNT" >> $GITHUB_OUTPUT - - - name: Get changed files summary - id: files - run: | - CURRENT_TAG="${{ steps.get_tag.outputs.tag }}" - PREVIOUS_TAG="${{ steps.prev_tag.outputs.previous_tag }}" - - # Get file change statistics - FILES_CHANGED=$(git diff ${PREVIOUS_TAG}..${CURRENT_TAG} --stat | tail -1) - echo "files_summary=$FILES_CHANGED" >> $GITHUB_OUTPUT - - # Get detailed changes by component - echo "### File Changes by Component" > changes.txt - echo "" >> changes.txt - echo "**Frontend:**" >> changes.txt - git diff ${PREVIOUS_TAG}..${CURRENT_TAG} --stat -- archon-ui-main/ | head -20 >> changes.txt - echo "" >> changes.txt - echo "**Backend:**" >> changes.txt - git diff ${PREVIOUS_TAG}..${CURRENT_TAG} --stat -- python/ | head -20 >> changes.txt - echo "" >> changes.txt - echo "**Documentation:**" >> changes.txt - git diff ${PREVIOUS_TAG}..${CURRENT_TAG} --stat -- '*.md' PRPs/ | head -10 >> changes.txt - - - name: Get closed PRs - id: prs - env: - GH_TOKEN: ${{ github.token }} - run: | - CURRENT_TAG="${{ steps.get_tag.outputs.tag }}" - PREVIOUS_TAG="${{ steps.prev_tag.outputs.previous_tag }}" - - # Get date of previous tag - PREV_DATE=$(git log -1 --format=%ai ${PREVIOUS_TAG}) - - # Get merged PRs since previous tag - gh pr list \ - --state merged \ - --limit 100 \ - --json number,title,mergedAt,author,url \ - --jq --arg date "$PREV_DATE" \ - '.[] | select(.mergedAt >= $date) | "- #\(.number): \(.title) by @\(.author.login) - \(.url)"' \ - > prs.txt || echo "No PRs found" > prs.txt - - - name: Generate release notes with Claude - id: claude - env: - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - run: | - # Read all gathered information - COMMITS=$(cat commits.txt) - FILE_CHANGES=$(cat changes.txt) - PRS=$(cat prs.txt) - - # Build the prompt content - PROMPT_CONTENT="You are writing release notes for Archon V2 Beta, a local-first AI knowledge management system. - - ## Release Information - - **Version:** ${{ steps.get_tag.outputs.tag }} - **Previous Version:** ${{ steps.prev_tag.outputs.previous_tag }} - **Commits:** ${{ steps.commits.outputs.commit_count }} - **Is First Release:** ${{ steps.prev_tag.outputs.is_first_release }} - - ## Commits - - \`\`\` - ${COMMITS} - \`\`\` - - ## Pull Requests Merged - - \`\`\` - ${PRS} - \`\`\` - - ## File Changes - - \`\`\` - ${FILE_CHANGES} - \`\`\` - - ## Instructions - - Generate comprehensive release notes following this structure: - - # 🚀 Release ${{ steps.get_tag.outputs.tag }} - - ## 📝 Overview - [2-3 sentence summary of this release] - - ## ✨ What's New - - ### Major Features - - [List major new features with brief descriptions] - - ### Improvements - - [List improvements and enhancements] - - ### Bug Fixes - - [List bug fixes] - - ## 🔧 Technical Changes - - ### Backend (Python/FastAPI) - - [Notable backend changes] - - ### Frontend (React/TypeScript) - - [Notable frontend changes] - - ### Infrastructure - - [Docker, CI/CD, deployment changes] - - ## 📊 Statistics - - **Commits:** ${{ steps.commits.outputs.commit_count }} - - **Pull Requests:** [Count from PRs list] - - **Files Changed:** [From file stats] - - **Contributors:** [Unique authors from commits] - - ## 🙏 Contributors - - Thanks to everyone who contributed to this release: - [List unique contributors with @ mentions] - - ## 📚 Documentation - - [If documentation changes, list them] - - ## ⚠️ Breaking Changes - - [List any breaking changes - this is beta software, so breaking changes are expected] - - ## 🔗 Links - - - **Full Changelog:** https://github.com/${{ github.repository }}/compare/${{ steps.prev_tag.outputs.previous_tag }}...${{ steps.get_tag.outputs.tag }} - - **Installation Guide:** [Link to docs] - - --- - - **Note:** This is a beta release. Features may change rapidly. Report issues at: https://github.com/${{ github.repository }}/issues - - --- - - Write in a professional yet enthusiastic tone. Focus on user-facing changes. Be specific but concise." - - # Create the request using jq to properly escape JSON - jq -n \ - --arg model "claude-sonnet-4-20250514" \ - --arg content "$PROMPT_CONTENT" \ - '{ - model: $model, - max_tokens: 4096, - temperature: 0.7, - messages: [ - { - role: "user", - content: $content - } - ] - }' > request.json - - # Call Claude API - RESPONSE=$(curl -s https://api.anthropic.com/v1/messages \ - -H "Content-Type: application/json" \ - -H "x-api-key: $ANTHROPIC_API_KEY" \ - -H "anthropic-version: 2023-06-01" \ - -d @request.json) - - # Extract release notes from response - echo "$RESPONSE" | jq -r '.content[0].text' > release_notes.md - - # Check if generation was successful - if [ ! -s release_notes.md ] || grep -q "error" release_notes.md; then - echo "❌ Failed to generate release notes" - echo "Response: $RESPONSE" - exit 1 - fi - - echo "✅ Release notes generated successfully" - - - name: Create or update GitHub release - env: - GH_TOKEN: ${{ github.token }} - run: | - TAG="${{ steps.get_tag.outputs.tag }}" - NOTES=$(cat release_notes.md) - - # Check if release already exists - if gh release view "$TAG" &>/dev/null; then - echo "Release $TAG exists, updating notes..." - gh release edit "$TAG" --notes-file release_notes.md - else - echo "Creating new release $TAG..." - gh release create "$TAG" \ - --title "Release $TAG" \ - --notes-file release_notes.md \ - --draft=false \ - --latest - fi - - - name: Upload release notes as artifact - uses: actions/upload-artifact@v4 - with: - name: release-notes-${{ steps.get_tag.outputs.tag }} - path: release_notes.md - retention-days: 90 - - - name: Comment on related PRs - if: steps.prev_tag.outputs.is_first_release == 'false' - env: - GH_TOKEN: ${{ github.token }} - run: | - TAG="${{ steps.get_tag.outputs.tag }}" - - # Get PR numbers from commits in this release - CURRENT_TAG="${{ steps.get_tag.outputs.tag }}" - PREVIOUS_TAG="${{ steps.prev_tag.outputs.previous_tag }}" - - # Extract PR numbers from commit messages - PR_NUMBERS=$(git log ${PREVIOUS_TAG}..${CURRENT_TAG} --oneline | - grep -oP '#\K\d+' || true) - - if [ -n "$PR_NUMBERS" ]; then - for PR in $PR_NUMBERS; do - echo "Adding release comment to PR #$PR" - gh pr comment "$PR" \ - --body "🎉 This pull request has been included in release [$TAG](https://github.com/${{ github.repository }}/releases/tag/$TAG)!" \ - || echo "Could not comment on PR #$PR (might be closed)" - done - fi - - - name: Create summary - if: always() - run: | - echo "# 🎉 Release Notes Generation Summary" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "**Release Tag:** ${{ steps.get_tag.outputs.tag }}" >> $GITHUB_STEP_SUMMARY - echo "**Previous Tag:** ${{ steps.prev_tag.outputs.previous_tag }}" >> $GITHUB_STEP_SUMMARY - echo "**Commits:** ${{ steps.commits.outputs.commit_count }}" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "## Generated Release Notes" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - cat release_notes.md >> $GITHUB_STEP_SUMMARY +name: AI-Generated Release Notes + +on: + release: + types: [created, published] + push: + tags: + - 'v*.*.*' + workflow_dispatch: + inputs: + tag_name: + description: 'Tag name (e.g., v1.0.0)' + required: true + type: string + +permissions: + contents: write + pull-requests: read + id-token: write # Required for OIDC authentication + +jobs: + generate-release-notes: + name: Generate Release Notes with Claude + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Full git history + + - name: Get release tag + id: get_tag + run: | + if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then + echo "tag=${{ inputs.tag_name }}" >> $GITHUB_OUTPUT + elif [ "${{ github.event_name }}" == "release" ]; then + echo "tag=${{ github.event.release.tag_name }}" >> $GITHUB_OUTPUT + else + echo "tag=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT + fi + + - name: Get previous tag + id: prev_tag + run: | + CURRENT_TAG="${{ steps.get_tag.outputs.tag }}" + PREVIOUS_TAG=$(git tag --sort=-v:refname | grep -A1 "^${CURRENT_TAG}$" | tail -1) + + if [ -z "$PREVIOUS_TAG" ] || [ "$PREVIOUS_TAG" == "$CURRENT_TAG" ]; then + # First release or no previous tag - use initial commit + PREVIOUS_TAG=$(git rev-list --max-parents=0 HEAD) + echo "previous_tag=$PREVIOUS_TAG" >> $GITHUB_OUTPUT + echo "is_first_release=true" >> $GITHUB_OUTPUT + else + echo "previous_tag=$PREVIOUS_TAG" >> $GITHUB_OUTPUT + echo "is_first_release=false" >> $GITHUB_OUTPUT + fi + + - name: Get commit messages + id: commits + run: | + CURRENT_TAG="${{ steps.get_tag.outputs.tag }}" + PREVIOUS_TAG="${{ steps.prev_tag.outputs.previous_tag }}" + + # Get commit history + COMMITS=$(git log ${PREVIOUS_TAG}..${CURRENT_TAG} --pretty=format:"- %s (%h) by %an" --no-merges) + + # Save to file to preserve formatting + echo "$COMMITS" > commits.txt + + # Get stats + COMMIT_COUNT=$(echo "$COMMITS" | wc -l) + echo "commit_count=$COMMIT_COUNT" >> $GITHUB_OUTPUT + + - name: Get changed files summary + id: files + run: | + CURRENT_TAG="${{ steps.get_tag.outputs.tag }}" + PREVIOUS_TAG="${{ steps.prev_tag.outputs.previous_tag }}" + + # Get file change statistics + FILES_CHANGED=$(git diff ${PREVIOUS_TAG}..${CURRENT_TAG} --stat | tail -1) + echo "files_summary=$FILES_CHANGED" >> $GITHUB_OUTPUT + + # Get detailed changes by component + echo "### File Changes by Component" > changes.txt + echo "" >> changes.txt + echo "**Frontend:**" >> changes.txt + git diff ${PREVIOUS_TAG}..${CURRENT_TAG} --stat -- archon-ui-main/ | head -20 >> changes.txt + echo "" >> changes.txt + echo "**Backend:**" >> changes.txt + git diff ${PREVIOUS_TAG}..${CURRENT_TAG} --stat -- python/ | head -20 >> changes.txt + echo "" >> changes.txt + echo "**Documentation:**" >> changes.txt + git diff ${PREVIOUS_TAG}..${CURRENT_TAG} --stat -- '*.md' PRPs/ | head -10 >> changes.txt + + - name: Get closed PRs + id: prs + env: + GH_TOKEN: ${{ github.token }} + run: | + CURRENT_TAG="${{ steps.get_tag.outputs.tag }}" + PREVIOUS_TAG="${{ steps.prev_tag.outputs.previous_tag }}" + + # Get date of previous tag + PREV_DATE=$(git log -1 --format=%ai ${PREVIOUS_TAG}) + + # Get merged PRs since previous tag + gh pr list \ + --state merged \ + --limit 100 \ + --json number,title,mergedAt,author,url \ + --jq --arg date "$PREV_DATE" \ + '.[] | select(.mergedAt >= $date) | "- #\(.number): \(.title) by @\(.author.login) - \(.url)"' \ + > prs.txt || echo "No PRs found" > prs.txt + + - name: Prepare release notes context + id: context + run: | + # Create a context file with all the information + cat > release-context.md <<'EOF' + # Release Notes Generation Task + + You are writing release notes for Archon V2 Beta, a local-first AI knowledge management system. + + ## Release Information + + **Version:** ${{ steps.get_tag.outputs.tag }} + **Previous Version:** ${{ steps.prev_tag.outputs.previous_tag }} + **Commits:** ${{ steps.commits.outputs.commit_count }} + **Is First Release:** ${{ steps.prev_tag.outputs.is_first_release }} + + ## Commits + + ``` + EOF + cat commits.txt >> release-context.md + cat >> release-context.md <<'EOF' + ``` + + ## Pull Requests Merged + + ``` + EOF + cat prs.txt >> release-context.md + cat >> release-context.md <<'EOF' + ``` + + ## File Changes + + ``` + EOF + cat changes.txt >> release-context.md + cat >> release-context.md <<'EOF' + ``` + + ## Instructions + + Generate comprehensive release notes following this structure: + + # 🚀 Release ${{ steps.get_tag.outputs.tag }} + + ## 📝 Overview + [2-3 sentence summary of this release] + + ## ✨ What's New + + ### Major Features + - [List major new features with brief descriptions] + + ### Improvements + - [List improvements and enhancements] + + ### Bug Fixes + - [List bug fixes] + + ## 🔧 Technical Changes + + ### Backend (Python/FastAPI) + - [Notable backend changes] + + ### Frontend (React/TypeScript) + - [Notable frontend changes] + + ### Infrastructure + - [Docker, CI/CD, deployment changes] + + ## 📊 Statistics + - **Commits:** ${{ steps.commits.outputs.commit_count }} + - **Pull Requests:** [Count from PRs list] + - **Files Changed:** [From file stats] + - **Contributors:** [Unique authors from commits] + + ## 🙏 Contributors + + Thanks to everyone who contributed to this release: + [List unique contributors with @ mentions] + + ## 📚 Documentation + + [If documentation changes, list them] + + ## ⚠️ Breaking Changes + + [List any breaking changes - this is beta software, so breaking changes are expected] + + ## 🔗 Links + + - **Full Changelog:** https://github.com/${{ github.repository }}/compare/${{ steps.prev_tag.outputs.previous_tag }}...${{ steps.get_tag.outputs.tag }} + - **Installation Guide:** [Link to docs] + + --- + + **Note:** This is a beta release. Features may change rapidly. Report issues at: https://github.com/${{ github.repository }}/issues + + --- + + Write in a professional yet enthusiastic tone. Focus on user-facing changes. Be specific but concise. + + IMPORTANT: Output ONLY the release notes in markdown format. Do not include any preamble, explanation, or commentary - just the release notes themselves starting with the header. + EOF + + - name: Generate release notes with Claude Code + id: claude + uses: anthropics/claude-code-action@beta + timeout-minutes: 10 + with: + claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + + custom_instructions: | + Read the file release-context.md which contains all the information about this release. + + Generate comprehensive release notes following the structure and instructions in that file. + + Output ONLY the release notes in markdown format - no preamble, no commentary, just the release notes. + + Write to a file called release_notes.md with the generated release notes. + + - name: Verify release notes were generated + run: | + if [ ! -f release_notes.md ]; then + echo "❌ release_notes.md was not created" + echo "Checking for any .md files in current directory:" + ls -la *.md || echo "No .md files found" + exit 1 + fi + + if [ ! -s release_notes.md ]; then + echo "❌ release_notes.md is empty" + exit 1 + fi + + echo "✅ Release notes generated successfully" + echo "" + echo "Preview (first 50 lines):" + head -50 release_notes.md + + - name: Create or update GitHub release + env: + GH_TOKEN: ${{ github.token }} + run: | + TAG="${{ steps.get_tag.outputs.tag }}" + + # Check if release already exists + if gh release view "$TAG" &>/dev/null; then + echo "Release $TAG exists, updating notes..." + gh release edit "$TAG" --notes-file release_notes.md + else + echo "Creating new release $TAG..." + gh release create "$TAG" \ + --title "Release $TAG" \ + --notes-file release_notes.md \ + --draft=false \ + --latest + fi + + - name: Upload release notes as artifact + uses: actions/upload-artifact@v4 + with: + name: release-notes-${{ steps.get_tag.outputs.tag }} + path: release_notes.md + retention-days: 90 + + - name: Comment on related PRs + if: steps.prev_tag.outputs.is_first_release == 'false' + env: + GH_TOKEN: ${{ github.token }} + run: | + TAG="${{ steps.get_tag.outputs.tag }}" + + # Get PR numbers from commits in this release + CURRENT_TAG="${{ steps.get_tag.outputs.tag }}" + PREVIOUS_TAG="${{ steps.prev_tag.outputs.previous_tag }}" + + # Extract PR numbers from commit messages + PR_NUMBERS=$(git log ${PREVIOUS_TAG}..${CURRENT_TAG} --oneline | + grep -oP '#\K\d+' || true) + + if [ -n "$PR_NUMBERS" ]; then + for PR in $PR_NUMBERS; do + echo "Adding release comment to PR #$PR" + gh pr comment "$PR" \ + --body "🎉 This pull request has been included in release [$TAG](https://github.com/${{ github.repository }}/releases/tag/$TAG)!" \ + || echo "Could not comment on PR #$PR (might be closed)" + done + fi + + - name: Create summary + if: always() + run: | + echo "# 🎉 Release Notes Generation Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Release Tag:** ${{ steps.get_tag.outputs.tag }}" >> $GITHUB_STEP_SUMMARY + echo "**Previous Tag:** ${{ steps.prev_tag.outputs.previous_tag }}" >> $GITHUB_STEP_SUMMARY + echo "**Commits:** ${{ steps.commits.outputs.commit_count }}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "## Generated Release Notes" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + if [ -f release_notes.md ]; then + cat release_notes.md >> $GITHUB_STEP_SUMMARY + else + echo "⚠️ Release notes file not found" >> $GITHUB_STEP_SUMMARY + fi