Skip to content
This repository was archived by the owner on Mar 17, 2025. It is now read-only.
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
30 changes: 21 additions & 9 deletions .github/workflows/changeset-generation.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,12 @@ Breaking changes are detected by:

## Workflow Steps

1. **Detect PR Label**: The workflow runs when a PR is labeled with 'ready-for-changeset' or when manually triggered.
1. **Detect PR Merge**: The workflow runs when a PR is merged or when manually triggered.
2. **Extract Metadata**: The workflow extracts relevant information from the PR, including title, author, and body.
3. **Generate Changeset**: A changeset file is created with the extracted metadata.
4. **Commit Changeset**: The changeset is committed to the `develop` branch.
5. **Generate Release Notes**: The `generate-release-notes.js` script processes all changesets to create formatted release notes.
4. **Commit Changeset**: The changeset is committed to the branch (typically `develop`).
5. **Generate Release Notes**: The `release:notes` script processes all changesets to create formatted release notes in a temporary file.
6. **Update/Create Release PR**: The workflow either updates an existing release PR or creates a new one with the generated release notes.
7. **Remove Label**: The 'ready-for-changeset' label is removed to prevent duplicate runs.

## Release Notes Generation

Expand Down Expand Up @@ -107,8 +106,8 @@ To identify first-time contributors, the script uses the GitHub API to check if
name: Generate Changeset

on:
pull_request:
types: [labeled]
pull_request_target:
types: [closed]
workflow_dispatch:
inputs:
pr_number:
Expand All @@ -118,20 +117,33 @@ on:

jobs:
generate-changeset:
if: github.event.label.name == 'ready-for-changeset' || github.event_name == 'workflow_dispatch'
if: (github.event_name == 'pull_request_target' && github.event.pull_request.merged == true) || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
env:
REPO_URL: "https://github.com/${{ github.repository }}"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
# Checkout code
# Setup Node.js
# Install dependencies
# Get PR details
# Generate changeset
# Commit changeset
# Generate release notes
# Generate release notes to temporary file
# Check for existing release PR
# Update/Create release PR
# Remove label
```

## Temporary Files

The workflow uses temporary files to store release notes during execution:

1. Release notes are generated to a temporary directory (`/tmp/release-notes`)
2. These files are not committed to the repository
3. The temporary files are automatically cleaned up after the workflow completes

This approach keeps the repository clean while still allowing the workflow to process and use the release notes.

## Prerequisites

1. Create a 'ready-for-changeset' label in your repository
Expand Down
127 changes: 32 additions & 95 deletions .github/workflows/generate-changeset.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ jobs:
permissions:
contents: write
pull-requests: write
needs: [debug-event]
if: (github.event_name == 'pull_request_target' && github.event.pull_request.merged == true && github.event.pull_request.base.ref != 'main') || github.event_name == 'workflow_dispatch'
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 }}
Expand Down Expand Up @@ -84,40 +84,41 @@ jobs:
echo "pr_author=${PR_AUTHOR}" >> $GITHUB_OUTPUT
echo "pr_body=${PR_BODY}" >> $GITHUB_OUTPUT

- name: Extract release notes from PR body
id: extract_notes
- name: Generate changeset for current PR
run: |
if [[ "${{ github.event_name }}" == "pull_request_target" && "${{ github.event.pull_request.base.ref }}" == "main" ]]; then
# This is a PR being merged to main, extract the body
PR_BODY="${{ github.event.pull_request.body }}"
# 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
# For other cases, get the PR body from the release PR
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=closed&head=${{ github.repository_owner }}:develop&base=main&sort=updated&direction=desc&per_page=1")

PR_NUMBER=$(echo "$PR_LIST" | jq -r '.[0].number')

if [[ -z "$PR_NUMBER" || "$PR_NUMBER" == "null" ]]; then
echo "No recent merged PR from develop to main found."
exit 1
fi

PR_DATA=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
"https://api.github.com/repos/${{ github.repository }}/pulls/${PR_NUMBER}")

PR_BODY=$(echo "$PR_DATA" | jq -r '.body')
echo "No changes to commit"
fi

# 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')
- name: Generate release notes from changesets
id: generate_notes
run: |
# Create a temporary directory for release notes
mkdir -p /tmp/release-notes

# Save to file for use in later steps
echo "$RELEASE_NOTES" > release_notes.md
# Generate release notes from all changesets to a temporary file
npm run release:notes 2>/dev/null | grep -v "^>" > /tmp/release-notes/temp_notes.md

# For debugging
echo "Extracted release notes:"
cat release_notes.md
echo "Generated release notes:"
cat /tmp/release-notes/temp_notes.md

- name: Check for existing release PR
id: check_pr
Expand Down Expand Up @@ -152,7 +153,7 @@ jobs:
# Create the PR body with proper formatting
PR_BODY="## Upcoming Changes"
PR_BODY="${PR_BODY}"$'\n\n'
PR_BODY="${PR_BODY}$(cat release_notes.md)"
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."

Expand Down Expand Up @@ -183,7 +184,7 @@ jobs:
# Create the PR body with proper formatting
PR_BODY="## Upcoming Changes"
PR_BODY="${PR_BODY}"$'\n\n'
PR_BODY="${PR_BODY}$(cat release_notes.md)"
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."

Expand Down Expand Up @@ -233,67 +234,3 @@ jobs:
else
echo "Created new release PR #${PR_NUMBER} with initial changelog"
fi

# Add a step to create a release when merging to main
- name: Create GitHub Release
if: github.event_name == 'pull_request_target' && github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'main'
run: |
# Get the latest tag
git fetch --tags
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")

# Extract version number and increment
VERSION=$(echo $LATEST_TAG | sed 's/^v//')

# Check if this is a breaking change
if grep -q "BREAKING CHANGES" release_notes.md; then
# Major version bump for breaking changes
MAJOR=$(echo $VERSION | cut -d. -f1)
NEW_VERSION="$((MAJOR + 1)).0.0"
elif grep -q "New Features" release_notes.md; then
# Minor version bump for new features
MAJOR=$(echo $VERSION | cut -d. -f1)
MINOR=$(echo $VERSION | cut -d. -f2)
NEW_VERSION="${MAJOR}.$((MINOR + 1)).0"
else
# Patch version bump for bug fixes
MAJOR=$(echo $VERSION | cut -d. -f1)
MINOR=$(echo $VERSION | cut -d. -f2)
PATCH=$(echo $VERSION | cut -d. -f3)
NEW_VERSION="${MAJOR}.${MINOR}.$((PATCH + 1))"
fi

NEW_TAG="v${NEW_VERSION}"

echo "Creating new release with tag: ${NEW_TAG}"

# Format release notes - replace "Upcoming Changes" with "Release Notes"
RELEASE_BODY=$(cat release_notes.md)

# Create the release
PAYLOAD=$(jq -n \
--arg tag_name "$NEW_TAG" \
--arg name "$NEW_TAG" \
--arg body "$RELEASE_BODY" \
--argjson draft false \
--argjson prerelease false \
'{tag_name: $tag_name, name: $name, body: $body, draft: $draft, prerelease: $prerelease}')

# For debugging
echo "Release Payload:"
echo "$PAYLOAD" | jq '.'

# Create the release
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 }}/releases" \
-d "$PAYLOAD")

# Print full response for debugging
echo "Full API Response:"
echo "$RESPONSE" | jq '.'

# Clean up temporary files
rm -f release_notes.md
Loading
Loading