Skip to content
This repository was archived by the owner on Mar 17, 2025. It is now read-only.

release: next version 📦 #14

release: next version 📦

release: next version 📦 #14

name: Release Management
on:
# Using pull_request_target instead of pull_request for security reasons:
# - Runs in the context of the BASE repository, not the fork
# - Has access to repository secrets
# - Can commit changes to protected branches
# - SECURITY NOTE: Be careful when checking out PR code with this event type
pull_request_target:
types: [closed]
branches:
- main
workflow_dispatch:
inputs:
release_type:
description: 'Force a specific release type (leave empty for auto-detection)'
required: false
type: choice
options:
- auto
- major
- minor
- patch
default: 'auto'
target_branch:
description: 'Target branch for manual release (usually develop)'
required: false
default: 'develop'
schedule:
# Run on the 1st and 15th of each month
- cron: '0 0 1,15 * *'
jobs:
prepare-release:
# Only run if:
# 1. PR from develop to main is merged, OR
# 2. Manually triggered, OR
# 3. Scheduled run
if: (github.event_name == 'pull_request_target' && github.event.pull_request.merged == true && github.event.pull_request.head.ref == 'develop') || github.event_name == 'workflow_dispatch' || github.event_name == 'schedule'
runs-on: ubuntu-latest
steps:
- name: Set checkout ref
id: set_ref
run: |
if [[ "${{ github.event_name }}" == "pull_request_target" ]]; then
echo "ref=main" >> $GITHUB_OUTPUT
else
echo "ref=${{ github.event.inputs.target_branch || 'develop' }}" >> $GITHUB_OUTPUT
fi
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
# For PR events, check out the main branch
# For manual/scheduled events, check out the specified target branch or develop
ref: ${{ steps.set_ref.outputs.ref }}
# Use a personal access token with repo scope for better permissions
token: ${{ secrets.REPO_PAT }}
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '16'
- name: Install dependencies
run: npm ci
- name: Check for changesets
id: check_changesets
run: |
if [ -d ".changesets" ] && [ "$(ls -A .changesets)" ]; then
echo "has_changesets=true" >> $GITHUB_OUTPUT
else
echo "has_changesets=false" >> $GITHUB_OUTPUT
echo "No changesets found. Exiting."
exit 1
fi
- name: Determine version bump
id: version_bump
run: |
if [[ "${{ github.event.inputs.release_type }}" != "auto" && "${{ github.event.inputs.release_type }}" != "" ]]; then
# Use the specified release type
npm run version:bump -- --type=${{ github.event.inputs.release_type }}
else
# Auto-detect release type from changesets
npm run version:bump
fi
# Get the new version after bump
NEW_VERSION=$(grep -oP "define\('AUTOMATION_TESTS_VERSION', '\K[^']+" constants.php)
echo "version=${NEW_VERSION}" >> $GITHUB_OUTPUT
- name: Update changelogs
run: |
# First, check if this is a breaking change release by using our new script
# This will automatically update the upgrade notice section if breaking changes are found
npm run upgrade-notice:update -- --version=${{ steps.version_bump.outputs.version }} --notes-file=/tmp/release-notes/release_notes.md
# Now update the changelogs as usual
npm run changelogs:update -- --version=${{ steps.version_bump.outputs.version }}
# Generate release notes BEFORE archiving changesets
- name: Generate release notes
id: release_notes
run: |
# Create a temporary directory outside the repository
mkdir -p /tmp/release-notes
# Check if this is a PR from develop to main
if [[ "${{ github.event_name }}" == "pull_request_target" && "${{ github.event.pull_request.head.ref }}" == "develop" ]]; then
# Extract release notes from the PR body
PR_BODY="${{ github.event.pull_request.body }}"
# Extract the content between "## Upcoming Changes" and the disclaimer
RELEASE_NOTES=$(echo "$PR_BODY" | sed -n '/## Upcoming Changes/,/This PR contains all changes/p' | sed '1d;$d')
# Save to file for use in later steps (in temporary directory)
echo "$RELEASE_NOTES" > /tmp/release-notes/release_notes.md
else
# Generate release notes in markdown format for release body
# Skip the npm command output by redirecting stderr to /dev/null and grep out the command line
npm run release:notes 2>/dev/null | grep -v "^>" > /tmp/release-notes/release_notes.md
fi
# Check if the file has content
if [ ! -s /tmp/release-notes/release_notes.md ]; then
# If empty, provide a default message
echo "## Release Notes" > /tmp/release-notes/release_notes.md
echo "" >> /tmp/release-notes/release_notes.md
echo "No changesets found. No changes to release at this time." >> /tmp/release-notes/release_notes.md
else
# If there is content, replace "Upcoming Changes" with "Release Notes" if present
sed -i 's/## Upcoming Changes/## Release Notes/g' /tmp/release-notes/release_notes.md
# Remove the note about PR updates if present
sed -i '/This PR contains all changes that will be included in the next release/d' /tmp/release-notes/release_notes.md
fi
# For debugging
echo "Generated release notes:"
cat /tmp/release-notes/release_notes.md
# Set the content for GitHub Actions output
# Properly escape the content for GitHub Actions
RELEASE_NOTES=$(cat /tmp/release-notes/release_notes.md)
RELEASE_NOTES="${RELEASE_NOTES//'%'/'%25'}"
RELEASE_NOTES="${RELEASE_NOTES//$'\n'/'%0A'}"
RELEASE_NOTES="${RELEASE_NOTES//$'\r'/'%0D'}"
echo "content<<EOF" >> $GITHUB_OUTPUT
echo "$RELEASE_NOTES" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Commit changes to develop
if: github.event_name != 'pull_request_target'
uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: "release: prepare v${{ steps.version_bump.outputs.version }}"
file_pattern: "*.php *.md *.txt package.json"
# For manual/scheduled events, commit to the specified target branch or develop
branch: ${{ github.event.inputs.target_branch || 'develop' }}
env:
GITHUB_TOKEN: ${{ secrets.REPO_PAT }}
- name: Commit changes to main
if: github.event_name == 'pull_request_target'
run: |
git config --global user.name "GitHub Actions"
git config --global user.email "actions@github.com"
# Check if there are any changes to commit
if [[ -n "$(git status --porcelain)" ]]; then
echo "Changes detected, committing to main branch"
git add *.php *.md *.txt package.json
git commit -m "release: prepare v${{ steps.version_bump.outputs.version }}"
git push origin main
else
echo "No changes to commit"
fi
- name: Create and push tag
if: github.event_name == 'pull_request_target'
run: |
git config --global user.name "GitHub Actions"
git config --global user.email "actions@github.com"
# Check if tag already exists
if git rev-parse "v${{ steps.version_bump.outputs.version }}" >/dev/null 2>&1; then
echo "Tag v${{ steps.version_bump.outputs.version }} already exists. Skipping tag creation."
else
# Create an annotated tag with the changelog as the message
git tag -a "v${{ steps.version_bump.outputs.version }}" -m "Release v${{ steps.version_bump.outputs.version }}"
# Push the tag
git push origin "v${{ steps.version_bump.outputs.version }}"
fi
- name: Create GitHub Release
if: github.event_name == 'pull_request_target'
uses: actions/create-release@v1
id: create_release
continue-on-error: true
env:
GITHUB_TOKEN: ${{ secrets.REPO_PAT }}
with:
tag_name: v${{ steps.version_bump.outputs.version }}
release_name: Release v${{ steps.version_bump.outputs.version }}
body_path: /tmp/release-notes/release_notes.md
draft: false
prerelease: false
- name: Handle release creation failure
if: github.event_name == 'pull_request_target' && steps.create_release.outcome == 'failure'
run: |
echo "Failed to create release. This could be because the tag already exists."
echo "Checking if release exists..."
RELEASE_EXISTS=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: token ${{ secrets.REPO_PAT }}" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/${{ github.repository }}/releases/tags/v${{ steps.version_bump.outputs.version }}")
if [[ "$RELEASE_EXISTS" == "200" ]]; then
echo "Release for v${{ steps.version_bump.outputs.version }} already exists. Skipping release creation."
else
echo "Release creation failed for an unknown reason."
exit 1
fi
- name: Delete processed changesets
if: github.event_name == 'pull_request_target'
run: |
# Configure Git
git config --global user.name "GitHub Actions"
git config --global user.email "actions@github.com"
# Check if there are any changesets to delete
if [ -d ".changesets" ] && [ "$(find .changesets -maxdepth 1 -name "*.md" -type f)" ]; then
# List all changesets before deleting
echo "Changesets to delete:"
find .changesets -maxdepth 1 -name "*.md" -type f -exec basename {} \;
# Delete all changesets using find to ensure all files are removed
find .changesets -maxdepth 1 -name "*.md" -type f -exec git rm {} \;
# Commit the deleted changesets
git commit -m "chore: delete changesets after release v${{ steps.version_bump.outputs.version }}"
git push origin main
echo "Deleted changesets for v${{ steps.version_bump.outputs.version }}"
else
echo "No changesets found to delete"
fi
- name: Update develop branch
if: github.event_name == 'pull_request_target'
run: |
# Configure Git
git config --global user.name "GitHub Actions"
git config --global user.email "actions@github.com"
# Fetch all branches
git fetch --unshallow || git fetch
# Checkout develop branch
git checkout develop
git pull
# Merge main into develop with a descriptive message
git merge --no-ff origin/main -m "chore: sync main back to develop after release v${{ steps.version_bump.outputs.version }} [skip ci]"
# Push changes to develop
git push origin develop
echo "Successfully synced main back to develop branch"