This repository was archived by the owner on Mar 17, 2025. It is now read-only.
fix!: angel emoji #53
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Generate Changeset | |
# This workflow can be triggered in two ways: | |
# 1. When a pull request is merged to any branch (typically develop or main) | |
# 2. Manually via the GitHub Actions UI using the workflow_dispatch event | |
# - Go to Actions > Generate Changeset > Run workflow | |
# - Enter the PR number and click "Run workflow" | |
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: | |
- develop | |
workflow_dispatch: | |
inputs: | |
pr_number: | |
description: 'PR number to generate changeset for' | |
required: true | |
type: string | |
jobs: | |
debug-event: | |
runs-on: ubuntu-latest | |
if: github.event_name == 'pull_request_target' | |
steps: | |
- name: Debug Event | |
run: | | |
echo "Event name: ${{ github.event_name }}" | |
echo "Action: ${{ github.event.action }}" | |
echo "PR merged: ${{ github.event.pull_request.merged }}" | |
echo "Base ref: ${{ github.event.pull_request.base.ref }}" | |
echo "Head ref: ${{ github.event.pull_request.head.ref }}" | |
echo "PR number: ${{ github.event.pull_request.number }}" | |
echo "PR title: ${{ github.event.pull_request.title }}" | |
generate-changeset: | |
permissions: | |
contents: write | |
pull-requests: write | |
runs-on: ubuntu-latest | |
needs: [debug-event] | |
if: (github.event_name == 'pull_request_target' && github.event.pull_request.merged == true) || github.event_name == 'workflow_dispatch' | |
env: | |
REPO_URL: "https://github.com/${{ github.repository }}" | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v3 | |
with: | |
fetch-depth: 0 | |
ref: ${{ github.event.pull_request.base.ref || 'develop' }} | |
# Use a personal access token with repo scope for better permissions | |
token: ${{ secrets.GITHUB_TOKEN }} | |
- name: Setup Node.js | |
uses: actions/setup-node@v3 | |
with: | |
node-version: '16' | |
# Add caching for npm dependencies | |
- name: Cache npm dependencies | |
uses: actions/cache@v3 | |
id: npm-cache | |
with: | |
path: | | |
**/node_modules | |
~/.npm | |
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }} | |
restore-keys: | | |
${{ runner.os }}-npm- | |
- name: Install dependencies | |
# Only run full install if cache miss | |
if: steps.npm-cache.outputs.cache-hit != 'true' | |
run: npm ci | |
# If cache hit, just check for any missing dependencies | |
- name: Check dependencies | |
if: steps.npm-cache.outputs.cache-hit == 'true' | |
run: npm ci --prefer-offline --no-audit | |
- name: Extract PR information | |
id: pr_info | |
run: | | |
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then | |
PR_NUMBER="${{ github.event.inputs.pr_number }}" | |
else | |
PR_NUMBER="${{ github.event.pull_request.number }}" | |
fi | |
PR_DATA=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ | |
"https://api.github.com/repos/${{ github.repository }}/pulls/${PR_NUMBER}") | |
PR_TITLE=$(echo "$PR_DATA" | jq -r '.title') | |
PR_BODY=$(echo "$PR_DATA" | jq -r '.body') | |
PR_AUTHOR=$(echo "$PR_DATA" | jq -r '.user.login') | |
echo "pr_number=${PR_NUMBER}" >> $GITHUB_OUTPUT | |
echo "pr_title=${PR_TITLE}" >> $GITHUB_OUTPUT | |
echo "pr_author=${PR_AUTHOR}" >> $GITHUB_OUTPUT | |
echo "pr_body=${PR_BODY}" >> $GITHUB_OUTPUT | |
- name: Generate changeset for current PR | |
run: | | |
# Generate a changeset for the current PR | |
node scripts/generate-changeset.js \ | |
--pr="${{ steps.pr_info.outputs.pr_number }}" \ | |
--title="${{ steps.pr_info.outputs.pr_title }}" \ | |
--author="${{ steps.pr_info.outputs.pr_author }}" \ | |
--body="${{ steps.pr_info.outputs.pr_body }}" | |
# Commit and push the changeset | |
git config --global user.name "GitHub Actions" | |
git config --global user.email "actions@github.com" | |
# Check if there are changes to commit | |
if [[ -n "$(git status --porcelain)" ]]; then | |
git add .changesets/ | |
git commit -m "chore: add changeset for PR #${{ steps.pr_info.outputs.pr_number }}" | |
git push | |
echo "Changeset created and pushed for PR #${{ steps.pr_info.outputs.pr_number }}" | |
else | |
echo "No changes to commit" | |
fi | |
- name: Generate release notes from changesets | |
id: generate_notes | |
run: | | |
# Create a temporary directory for release notes | |
mkdir -p /tmp/release-notes | |
# Generate release notes directly to see the raw output | |
echo "Raw output from release:notes command:" | |
npm run release:notes | |
# Generate release notes from all changesets to a temporary file | |
# Don't filter with grep initially to see what we're getting | |
npm run release:notes > /tmp/release-notes/temp_notes_raw.md | |
# Show the raw content | |
echo "Raw content of temp_notes_raw.md:" | |
cat /tmp/release-notes/temp_notes_raw.md | |
# Now apply filtering if needed | |
cat /tmp/release-notes/temp_notes_raw.md | grep -v "^>" > /tmp/release-notes/temp_notes_filtered.md | |
# Show filtered content | |
echo "Filtered content:" | |
cat /tmp/release-notes/temp_notes_filtered.md | |
# Apply sed filtering | |
sed -n '/^Found/!p' /tmp/release-notes/temp_notes_filtered.md > /tmp/release-notes/temp_notes.md | |
# Show final content | |
echo "Final release notes content:" | |
cat /tmp/release-notes/temp_notes.md | |
# Make sure the file isn't empty | |
if [ ! -s /tmp/release-notes/temp_notes.md ]; then | |
echo "Warning: Release notes file is empty. Using fallback content." | |
echo "No changes documented yet. This will be updated when changesets are processed." > /tmp/release-notes/temp_notes.md | |
fi | |
- name: Check for existing release PR | |
id: check_pr | |
run: | | |
# Check if there's already a PR from develop to main | |
PR_LIST=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ | |
-H "Accept: application/vnd.github.v3+json" \ | |
"https://api.github.com/repos/${{ github.repository }}/pulls?state=open&head=${{ github.repository_owner }}:develop&base=main") | |
PR_COUNT=$(echo "$PR_LIST" | jq length) | |
if [[ "$PR_COUNT" -gt 0 ]]; then | |
PR_NUMBER=$(echo "$PR_LIST" | jq -r '.[0].number') | |
echo "exists=true" >> $GITHUB_OUTPUT | |
echo "number=${PR_NUMBER}" >> $GITHUB_OUTPUT | |
else | |
echo "exists=false" >> $GITHUB_OUTPUT | |
fi | |
- name: Update existing release PR | |
if: steps.check_pr.outputs.exists == 'true' | |
run: | | |
# Update the PR body with the latest changelog | |
PR_NUMBER="${{ steps.check_pr.outputs.number }}" | |
# Get current PR data | |
PR_DATA=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ | |
"https://api.github.com/repos/${{ github.repository }}/pulls/${PR_NUMBER}") | |
PR_TITLE=$(echo "$PR_DATA" | jq -r '.title') | |
# Check if release notes file exists and has content | |
if [ -s /tmp/release-notes/temp_notes.md ]; then | |
RELEASE_NOTES=$(cat /tmp/release-notes/temp_notes.md) | |
echo "Using generated release notes:" | |
echo "$RELEASE_NOTES" | |
else | |
RELEASE_NOTES="No changes documented yet. This will be updated when changesets are processed." | |
echo "Using fallback release notes" | |
fi | |
# Create the PR body with proper formatting | |
PR_BODY="## Upcoming Changes" | |
PR_BODY="${PR_BODY}"$'\n\n' | |
PR_BODY="${PR_BODY}${RELEASE_NOTES}" | |
PR_BODY="${PR_BODY}"$'\n\n' | |
PR_BODY="${PR_BODY}This PR contains all changes that will be included in the next release. It is automatically updated when new changesets are added to the develop branch." | |
# Use jq to properly escape the content | |
PAYLOAD=$(jq -n --arg body "$PR_BODY" --arg title "$PR_TITLE" '{body: $body, title: $title}') | |
# For debugging | |
echo "API Payload:" | |
echo "$PAYLOAD" | jq '.' | |
# Update the PR | |
RESPONSE=$(curl -X PATCH \ | |
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ | |
-H "Accept: application/vnd.github.v3+json" \ | |
-H "Content-Type: application/json" \ | |
"https://api.github.com/repos/${{ github.repository }}/pulls/${PR_NUMBER}" \ | |
-d "$PAYLOAD") | |
# Print full response for debugging | |
echo "Full API Response:" | |
echo "$RESPONSE" | jq '.' | |
echo "Updated existing release PR #${PR_NUMBER} with latest changelog" | |
- name: Create new release PR | |
if: steps.check_pr.outputs.exists == 'false' | |
run: | | |
# Create the PR body with proper formatting | |
PR_BODY="## Upcoming Changes" | |
PR_BODY="${PR_BODY}"$'\n\n' | |
PR_BODY="${PR_BODY}$(cat /tmp/release-notes/temp_notes.md)" | |
PR_BODY="${PR_BODY}"$'\n\n' | |
PR_BODY="${PR_BODY}This PR contains all changes that will be included in the next release. It is automatically updated when new changesets are added to the develop branch." | |
# Use jq to properly escape the content | |
PAYLOAD=$(jq -n \ | |
--arg title "release: next version 📦" \ | |
--arg head "develop" \ | |
--arg base "main" \ | |
--arg body "$PR_BODY" \ | |
'{title: $title, head: $head, base: $base, body: $body}') | |
# For debugging | |
echo "API Payload:" | |
echo "$PAYLOAD" | jq '.' | |
# Create a new PR from develop to main | |
RESPONSE=$(curl -X POST \ | |
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ | |
-H "Accept: application/vnd.github.v3+json" \ | |
-H "Content-Type: application/json" \ | |
"https://api.github.com/repos/${{ github.repository }}/pulls" \ | |
-d "$PAYLOAD") | |
# Print full response for debugging | |
echo "Full API Response:" | |
echo "$RESPONSE" | jq '.' | |
# Check for error messages | |
ERROR_MESSAGE=$(echo "$RESPONSE" | jq -r '.message // "No error message"') | |
if [[ "$ERROR_MESSAGE" != "No error message" ]]; then | |
echo "Error creating PR: $ERROR_MESSAGE" | |
# Check for more detailed errors | |
ERRORS=$(echo "$RESPONSE" | jq -r '.errors // []') | |
if [[ "$ERRORS" != "[]" ]]; then | |
echo "Detailed errors: $ERRORS" | |
fi | |
exit 1 | |
fi | |
PR_NUMBER=$(echo "$RESPONSE" | jq -r '.number') | |
if [[ -z "$PR_NUMBER" || "$PR_NUMBER" == "null" ]]; then | |
echo "Failed to create PR. No PR number returned." | |
exit 1 | |
else | |
echo "Created new release PR #${PR_NUMBER} with initial changelog" | |
fi |