diff --git a/.github/workflows/changeset-generation.md b/.github/workflows/changeset-generation.md index 2fab423..8f95926 100644 --- a/.github/workflows/changeset-generation.md +++ b/.github/workflows/changeset-generation.md @@ -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 @@ -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: @@ -118,8 +117,11 @@ 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 @@ -127,11 +129,21 @@ jobs: # 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 diff --git a/.github/workflows/generate-changeset.yml b/.github/workflows/generate-changeset.yml index aac932f..574264d 100644 --- a/.github/workflows/generate-changeset.yml +++ b/.github/workflows/generate-changeset.yml @@ -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 }} @@ -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 @@ -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." @@ -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." @@ -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 diff --git a/.github/workflows/release-management.md b/.github/workflows/release-management.md index f2e0c00..2fc1ffd 100644 --- a/.github/workflows/release-management.md +++ b/.github/workflows/release-management.md @@ -8,13 +8,19 @@ The Release Management workflow is responsible for collecting changesets, determ ## Workflow Triggers +- When a PR from develop to main is merged - Manual trigger via GitHub Actions UI - Scheduled trigger (e.g., weekly/monthly) -- Optional: Tag-based trigger ## Workflow Steps -### 1. Collect and Analyze Changesets +### 1. Extract Release Notes + +- When a PR from develop to main is merged, extract release notes from the PR body +- The PR body contains formatted release notes generated by the changeset workflow +- Extract the content between "## Upcoming Changes" and the disclaimer + +### 2. Collect and Analyze Changesets - Read all changesets from the `.changesets` directory - Determine the appropriate version bump: @@ -22,10 +28,6 @@ The Release Management workflow is responsible for collecting changesets, determ - Minor: If any changeset is of type "feat" (new feature) - Patch: If all changesets are of type "fix", "docs", etc. -### 2. Create Release Branch - -- Create a new branch named `release/vX.Y.Z` based on the determined version - ### 3. Update Version Numbers - Update version in `automation-tests.php` @@ -34,7 +36,7 @@ The Release Management workflow is responsible for collecting changesets, determ ### 4. Generate Changelog -- Generate formatted changelog entries from changesets +- Use the extracted release notes or generate formatted changelog entries from changesets - Update `CHANGELOG.md` with new entries - Update `readme.txt` with new entries - Include full links to PRs (e.g., `https://github.com/username/repo/pull/123`) @@ -48,16 +50,30 @@ The Release Management workflow is responsible for collecting changesets, determ - Install npm dependencies - Run build scripts -### 6. Create Pull Request +### 6. Create GitHub Release + +- Create a new tag based on the version number +- Create a GitHub release with the tag +- Include the formatted release notes in the release body +- Upload build artifacts to the release + +### 7. Archive Changesets -- Create a PR from the release branch to `main` -- Include generated changelog in PR description +- Move processed changesets to the `.changesets/archive` directory +- Commit the archived changesets +- Update the develop branch with the archived changesets -### 7. Deploy (After PR is Merged) +## Integration with Changeset Generation -- Create GitHub release with version tag -- Deploy to WordPress.org -- Upload plugin zip to GitHub release +The Release Management workflow works in tandem with the Changeset Generation workflow: + +1. The Changeset Generation workflow creates changesets for merged PRs +2. It also creates or updates a release PR from develop to main +3. The release PR contains formatted release notes from all changesets +4. When the release PR is merged to main, the Release Management workflow is triggered +5. It extracts the release notes from the PR body and uses them for the GitHub release + +This integration ensures a smooth, automated release process with minimal manual intervention. ## GitHub Action Implementation @@ -65,6 +81,10 @@ The Release Management workflow is responsible for collecting changesets, determ name: Release Management on: + pull_request_target: + types: [closed] + branches: + - main workflow_dispatch: inputs: release_type: @@ -72,98 +92,40 @@ on: 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: Checkout code - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: '16' - - - name: Collect and analyze changesets - id: analyze - run: | - # Script to collect changesets and determine version bump - # Sets output variables for next steps - - - name: Determine new version - id: version - run: | - # Get current version from constants.php - CURRENT_VERSION=$(grep -oP "define\('AUTOMATION_TESTS_VERSION', '\K[^']+" constants.php) - - # Determine new version based on bump type - if [[ "${{ github.event.inputs.release_type }}" != "" ]]; then - BUMP_TYPE="${{ github.event.inputs.release_type }}" - else - BUMP_TYPE="${{ steps.analyze.outputs.bump_type }}" - fi - - # Calculate new version - # This would be a more complex script in practice - - echo "::set-output name=new_version::$NEW_VERSION" - echo "::set-output name=bump_type::$BUMP_TYPE" - - - name: Create release branch - run: | - git checkout -b release/v${{ steps.version.outputs.new_version }} - - - name: Update version numbers - run: | - # Update version in automation-tests.php - sed -i "s/Version: .*/Version: ${{ steps.version.outputs.new_version }}/" automation-tests.php - - # Update version in constants.php - sed -i "s/define('AUTOMATION_TESTS_VERSION', '.*')/define('AUTOMATION_TESTS_VERSION', '${{ steps.version.outputs.new_version }}')/" constants.php - - - name: Generate changelog - run: | - # Script to generate changelog from changesets - - - name: Build dependencies - run: | - # Install and build dependencies - - - name: Create pull request - uses: peter-evans/create-pull-request@v4 - with: - title: "release: v${{ steps.version.outputs.new_version }}" - body: | - ## Release v${{ steps.version.outputs.new_version }} - - This PR prepares the release of version ${{ steps.version.outputs.new_version }}. - - ### Changelog - - ${{ steps.changelog.outputs.content }} - branch: release/v${{ steps.version.outputs.new_version }} - base: main - labels: release + # Checkout code + # Setup Node.js + # Install dependencies + # Extract release notes from PR body or generate them + # Determine version bump + # Update version numbers + # Generate changelog + # Build dependencies + # Create GitHub release + # Archive changesets ``` -## Post-Merge Deployment Workflow - -After the release PR is merged to `main`, a separate workflow will handle: - -1. Creating a GitHub release -2. Deploying to WordPress.org -3. Uploading the plugin zip to the GitHub release - ## Considerations and Next Steps - Decide on the frequency of releases diff --git a/.github/workflows/release-management.yml b/.github/workflows/release-management.yml index 4fbdce6..933e0df 100644 --- a/.github/workflows/release-management.yml +++ b/.github/workflows/release-management.yml @@ -100,10 +100,22 @@ jobs: - name: Generate release notes id: release_notes run: | - # Create a temporary file for the release notes - # 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 "^>" > release_notes_temp.md + # 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 + echo "$RELEASE_NOTES" > release_notes_temp.md + else + # Create a temporary file for the release notes + # 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 "^>" > release_notes_temp.md + fi # Check if the file has content if [ ! -s release_notes_temp.md ]; then diff --git a/README.md b/README.md index 1810de0..addbbb1 100644 --- a/README.md +++ b/README.md @@ -42,19 +42,26 @@ Changelogs are formatted according to WordPress plugin repository standards: The repository implements several GitHub Actions workflows: -- **Changeset Generation**: Generates changesets when PRs are labeled with 'ready-for-changeset' +- **Changeset Generation**: Generates changesets when PRs are merged to develop + - Creates a changeset file for the PR + - Generates release notes from all changesets + - Creates or updates a release PR from develop to main + - Uses temporary files to keep the repository clean - **Release Management**: Automates version bumping and changelog updates + - Extracts release notes from PR body when merging to main + - Creates GitHub releases with proper tagging - **Deploy**: Handles deployment to various environments ## Development Process 1. Create a feature branch from `develop` 2. Make changes and submit a PR to `develop` -3. Add the 'ready-for-changeset' label to the PR to generate a changeset -4. When the PR is merged, the changeset is committed to `develop` -5. When ready for release, a release PR is created from `develop` to `main` -6. The release PR includes all changes from changesets with proper formatting -7. After merging the release PR, the plugin is tagged and released +3. When the PR is merged, a changeset is automatically generated +4. The changeset is committed to `develop` +5. A release PR is created or updated from `develop` to `main` +6. When ready for release, merge the release PR to `main` +7. The release management workflow creates a tag and GitHub release +8. The plugin is deployed to the appropriate environments ## Local Testing @@ -160,6 +167,8 @@ We've made several significant improvements to the changeset generation workflow - Cleaner GitHub workflow configuration - Better error handling and fallbacks - Direct file processing instead of relying on external scripts +- Use of temporary files to keep the repository clean +- Automatic PR creation and updating - Comprehensive documentation updates These improvements make the changeset generation process more reliable, user-friendly, and informative, enhancing the overall development workflow. diff --git a/SUMMARY.md b/SUMMARY.md index e9fafc7..4ee6bbf 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -14,14 +14,17 @@ ## GitHub Workflows - Modified `generate-changeset.yml` to: - - Use label-based trigger ('ready-for-changeset') instead of PR merge - - Improve permissions handling with Personal Access Token (PAT) - - Automatically remove label after generating changeset - - Use the new `generate-release-notes.js` script for better formatted release notes + - Use PR merge trigger instead of label-based trigger + - Improve permissions handling with GitHub token + - Generate changesets for merged PRs + - Use temporary files for release notes to keep the repository clean + - Use the `generate-release-notes.js` script for better formatted release notes + - Automatically create or update a release PR from develop to main - Improved `release-management.yml` for automating version bumping and changelog updates: + - Extract release notes from PR body when merging to main - Auto-detect version bump type from changesets - Update both CHANGELOG.md and readme.txt - - Create release PR with formatted changelog + - Create GitHub release with formatted release notes - Updated `deploy.yml` for handling deployments: - Deploy to WordPress.org SVN - Create GitHub release with assets @@ -31,7 +34,7 @@ - Updated README.md with comprehensive overview of the project - Created detailed workflow documentation: - - Changeset generation process + - Changeset generation process with temporary file handling - Release management workflow - Deployment process - Added examples and usage instructions for all scripts @@ -52,6 +55,7 @@ - **Flexibility**: Workflows can be customized without changing the core logic - **Consistency**: Ensures standardized processes for versioning and releases - **Efficiency**: Combined operations reduce duplication and potential for inconsistencies +- **Cleanliness**: Use of temporary files keeps the repository clean ## Next Steps - Test scripts with various scenarios to ensure robustness @@ -65,4 +69,5 @@ - **Environment Variables Support**: Added support for environment variables (`REPO_URL` and `GITHUB_TOKEN`) to simplify configuration and usage of the release notes script. - **Contributor Recognition**: Enhanced release notes to include a contributors section with special recognition for first-time contributors. - **GitHub Workflow Improvements**: Updated the GitHub workflow to use environment variables instead of command-line arguments, making it cleaner and more maintainable. +- **Temporary File Handling**: Improved the workflow to use temporary files for release notes, keeping the repository clean. - **Documentation Updates**: Comprehensive documentation updates to reflect new features and options. \ No newline at end of file diff --git a/release_notes.md b/release_notes.md deleted file mode 100644 index a0c8af4..0000000 --- a/release_notes.md +++ /dev/null @@ -1,6 +0,0 @@ - -> automation-tests@2.2.0 release:notes -> node scripts/generate-release-notes.js - -No changesets found. -No changes to release at this time. diff --git a/release_notes_temp.md b/release_notes_temp.md deleted file mode 100644 index 68c7e8e..0000000 --- a/release_notes_temp.md +++ /dev/null @@ -1,4 +0,0 @@ - - -No changesets found. -No changes to release at this time.