2ff9ccabfe
* fix(ci): enable automatic release workflow triggering - Use PAT_TOKEN instead of GITHUB_TOKEN in prepare-release.yml When GITHUB_TOKEN pushes a tag, GitHub prevents it from triggering other workflows (security feature to prevent infinite loops). PAT_TOKEN allows the tag push to trigger release.yml automatically. - Change dry_run default to false in release.yml Manual workflow triggers should create real releases by default, not dry runs. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(ci): add PAT_TOKEN validation with clear error message Addresses Sentry review feedback - fail fast with actionable error if PAT_TOKEN secret is not configured, instead of cryptic auth failure. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
252 lines
11 KiB
YAML
252 lines
11 KiB
YAML
name: Prepare Release
|
|
|
|
# Triggers when code is pushed to main (e.g., merging develop → main)
|
|
# If package.json version is newer than the latest tag:
|
|
# 1. Validates CHANGELOG.md has an entry for this version (FAILS if missing)
|
|
# 2. Extracts release notes from CHANGELOG.md
|
|
# 3. Creates a new tag which triggers release.yml
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
paths:
|
|
- 'apps/frontend/package.json'
|
|
- 'package.json'
|
|
workflow_dispatch:
|
|
inputs:
|
|
force:
|
|
description: 'Force release even if version check fails (use with caution)'
|
|
required: false
|
|
default: false
|
|
type: boolean
|
|
|
|
jobs:
|
|
check-and-tag:
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: write
|
|
outputs:
|
|
should_release: ${{ steps.check.outputs.should_release }}
|
|
new_version: ${{ steps.check.outputs.new_version }}
|
|
steps:
|
|
# Fail fast with clear error if PAT_TOKEN is not configured
|
|
- name: Validate PAT_TOKEN is configured
|
|
run: |
|
|
if [ -z "${{ secrets.PAT_TOKEN }}" ]; then
|
|
echo "::error::PAT_TOKEN secret is not configured."
|
|
echo "::error::This secret is required for automatic release triggering."
|
|
echo "::error::See https://github.com/AndyMik90/Auto-Claude/pull/1043 for setup instructions."
|
|
exit 1
|
|
fi
|
|
|
|
# IMPORTANT: Use PAT_TOKEN instead of GITHUB_TOKEN
|
|
# When GITHUB_TOKEN pushes a tag, it does NOT trigger other workflows (GitHub security feature)
|
|
# PAT_TOKEN allows the tag push to trigger release.yml automatically
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
token: ${{ secrets.PAT_TOKEN }}
|
|
|
|
- name: Get package version
|
|
id: package
|
|
run: |
|
|
VERSION=$(node -p "require('./apps/frontend/package.json').version")
|
|
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
|
echo "Package version: $VERSION"
|
|
|
|
- name: Get latest tag version
|
|
id: latest_tag
|
|
run: |
|
|
# Get the latest version tag (v*)
|
|
LATEST_TAG=$(git tag -l 'v*' --sort=-version:refname | head -n1)
|
|
if [ -z "$LATEST_TAG" ]; then
|
|
echo "No existing tags found"
|
|
echo "version=0.0.0" >> $GITHUB_OUTPUT
|
|
else
|
|
# Remove 'v' prefix
|
|
LATEST_VERSION=${LATEST_TAG#v}
|
|
echo "version=$LATEST_VERSION" >> $GITHUB_OUTPUT
|
|
echo "Latest tag: $LATEST_TAG (version: $LATEST_VERSION)"
|
|
fi
|
|
|
|
- name: Check if release needed
|
|
id: check
|
|
run: |
|
|
PACKAGE_VERSION="${{ steps.package.outputs.version }}"
|
|
LATEST_VERSION="${{ steps.latest_tag.outputs.version }}"
|
|
FORCE="${{ github.event.inputs.force }}"
|
|
|
|
echo "Comparing: package=$PACKAGE_VERSION vs latest_tag=$LATEST_VERSION"
|
|
|
|
# Use npx semver for proper semantic version comparison
|
|
# This correctly handles pre-release versions (2.7.3 > 2.7.3-beta.1)
|
|
if npx -y semver "$PACKAGE_VERSION" -r ">$LATEST_VERSION" > /dev/null 2>&1; then
|
|
echo "should_release=true" >> $GITHUB_OUTPUT
|
|
echo "new_version=$PACKAGE_VERSION" >> $GITHUB_OUTPUT
|
|
echo "✅ New release needed: v$PACKAGE_VERSION"
|
|
elif [ "$FORCE" = "true" ]; then
|
|
echo "should_release=true" >> $GITHUB_OUTPUT
|
|
echo "new_version=$PACKAGE_VERSION" >> $GITHUB_OUTPUT
|
|
echo "⚠️ Force release enabled: v$PACKAGE_VERSION"
|
|
else
|
|
echo "should_release=false" >> $GITHUB_OUTPUT
|
|
echo "⏭️ No release needed (package version not newer than latest tag)"
|
|
fi
|
|
|
|
# CRITICAL: Validate CHANGELOG.md has entry for this version BEFORE creating tag
|
|
- name: Validate and extract changelog
|
|
if: steps.check.outputs.should_release == 'true'
|
|
id: changelog
|
|
run: |
|
|
VERSION="${{ steps.check.outputs.new_version }}"
|
|
CHANGELOG_FILE="CHANGELOG.md"
|
|
|
|
echo "🔍 Validating CHANGELOG.md for version $VERSION..."
|
|
|
|
if [ ! -f "$CHANGELOG_FILE" ]; then
|
|
echo "::error::CHANGELOG.md not found! Please create CHANGELOG.md with release notes."
|
|
exit 1
|
|
fi
|
|
|
|
# Extract changelog section for this version
|
|
# Looks for "## X.Y.Z" header and captures until next "## " or "---" or end
|
|
CHANGELOG_CONTENT=$(awk -v ver="$VERSION" '
|
|
BEGIN { found=0; content="" }
|
|
/^## / {
|
|
if (found) exit
|
|
# Match version at start of header (e.g., "## 2.7.3 -" or "## 2.7.3")
|
|
if ($2 == ver || $2 ~ "^"ver"[[:space:]]*-") {
|
|
found=1
|
|
# Skip the header line itself, we will add our own
|
|
next
|
|
}
|
|
}
|
|
/^---$/ { if (found) exit }
|
|
found { content = content $0 "\n" }
|
|
END {
|
|
if (!found) {
|
|
print "NOT_FOUND"
|
|
exit 1
|
|
}
|
|
# Trim leading/trailing whitespace
|
|
gsub(/^[[:space:]]+|[[:space:]]+$/, "", content)
|
|
print content
|
|
}
|
|
' "$CHANGELOG_FILE")
|
|
|
|
if [ "$CHANGELOG_CONTENT" = "NOT_FOUND" ] || [ -z "$CHANGELOG_CONTENT" ]; then
|
|
echo ""
|
|
echo "::error::═══════════════════════════════════════════════════════════════════════"
|
|
echo "::error:: CHANGELOG VALIDATION FAILED"
|
|
echo "::error::═══════════════════════════════════════════════════════════════════════"
|
|
echo "::error::"
|
|
echo "::error:: Version $VERSION not found in CHANGELOG.md!"
|
|
echo "::error::"
|
|
echo "::error:: Before releasing, please update CHANGELOG.md with an entry like:"
|
|
echo "::error::"
|
|
echo "::error:: ## $VERSION - Your Release Title"
|
|
echo "::error::"
|
|
echo "::error:: ### ✨ New Features"
|
|
echo "::error:: - Feature description"
|
|
echo "::error::"
|
|
echo "::error:: ### 🐛 Bug Fixes"
|
|
echo "::error:: - Fix description"
|
|
echo "::error::"
|
|
echo "::error::═══════════════════════════════════════════════════════════════════════"
|
|
echo ""
|
|
|
|
# Also add to job summary for visibility
|
|
echo "## ❌ Release Blocked: Missing Changelog" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "Version **$VERSION** was not found in CHANGELOG.md." >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "### How to fix:" >> $GITHUB_STEP_SUMMARY
|
|
echo "1. Update CHANGELOG.md with release notes for version $VERSION" >> $GITHUB_STEP_SUMMARY
|
|
echo "2. Commit and push the changes" >> $GITHUB_STEP_SUMMARY
|
|
echo "3. The release will automatically retry" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "### Expected format:" >> $GITHUB_STEP_SUMMARY
|
|
echo "\`\`\`markdown" >> $GITHUB_STEP_SUMMARY
|
|
echo "## $VERSION - Release Title" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "### ✨ New Features" >> $GITHUB_STEP_SUMMARY
|
|
echo "- Feature description" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "### 🐛 Bug Fixes" >> $GITHUB_STEP_SUMMARY
|
|
echo "- Fix description" >> $GITHUB_STEP_SUMMARY
|
|
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
|
|
|
|
exit 1
|
|
fi
|
|
|
|
echo "✅ Found changelog entry for version $VERSION"
|
|
echo ""
|
|
echo "--- Extracted Release Notes ---"
|
|
echo "$CHANGELOG_CONTENT"
|
|
echo "--- End Release Notes ---"
|
|
|
|
# Save changelog to file for artifact upload
|
|
echo "$CHANGELOG_CONTENT" > changelog-extract.md
|
|
|
|
# Also save to output (for short changelogs)
|
|
# Using heredoc for multiline output
|
|
{
|
|
echo "content<<CHANGELOG_EOF"
|
|
echo "$CHANGELOG_CONTENT"
|
|
echo "CHANGELOG_EOF"
|
|
} >> $GITHUB_OUTPUT
|
|
|
|
echo "changelog_valid=true" >> $GITHUB_OUTPUT
|
|
|
|
# Upload changelog as artifact for release.yml to use
|
|
- name: Upload changelog artifact
|
|
if: steps.check.outputs.should_release == 'true' && steps.changelog.outputs.changelog_valid == 'true'
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: changelog-${{ steps.check.outputs.new_version }}
|
|
path: changelog-extract.md
|
|
retention-days: 1
|
|
|
|
- name: Create and push tag
|
|
if: steps.check.outputs.should_release == 'true' && steps.changelog.outputs.changelog_valid == 'true'
|
|
run: |
|
|
VERSION="${{ steps.check.outputs.new_version }}"
|
|
TAG="v$VERSION"
|
|
|
|
git config user.name "github-actions[bot]"
|
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
|
|
echo "Creating tag: $TAG"
|
|
git tag -a "$TAG" -m "Release $TAG"
|
|
git push origin "$TAG"
|
|
|
|
echo "✅ Tag $TAG created and pushed"
|
|
echo "🚀 This will trigger the release workflow"
|
|
|
|
- name: Summary
|
|
run: |
|
|
if [ "${{ steps.check.outputs.should_release }}" = "true" ] && [ "${{ steps.changelog.outputs.changelog_valid }}" = "true" ]; then
|
|
echo "## 🚀 Release Triggered" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "**Version:** v${{ steps.check.outputs.new_version }}" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "✅ Changelog validated and extracted from CHANGELOG.md" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "The release workflow has been triggered and will:" >> $GITHUB_STEP_SUMMARY
|
|
echo "1. Build binaries for all platforms" >> $GITHUB_STEP_SUMMARY
|
|
echo "2. Use changelog from CHANGELOG.md" >> $GITHUB_STEP_SUMMARY
|
|
echo "3. Create GitHub release" >> $GITHUB_STEP_SUMMARY
|
|
echo "4. Update README with new version" >> $GITHUB_STEP_SUMMARY
|
|
elif [ "${{ steps.check.outputs.should_release }}" = "false" ]; then
|
|
echo "## ⏭️ No Release Needed" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "**Package version:** ${{ steps.package.outputs.version }}" >> $GITHUB_STEP_SUMMARY
|
|
echo "**Latest tag:** v${{ steps.latest_tag.outputs.version }}" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "The package version is not newer than the latest tag." >> $GITHUB_STEP_SUMMARY
|
|
echo "To trigger a release, bump the version using:" >> $GITHUB_STEP_SUMMARY
|
|
echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY
|
|
echo "node scripts/bump-version.js patch # or minor/major" >> $GITHUB_STEP_SUMMARY
|
|
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
|
|
fi
|