diff --git a/.github/workflows/detect-gutenberg-sha-change.yml b/.github/workflows/detect-gutenberg-sha-change.yml new file mode 100644 index 0000000000000..07cfc9e687471 --- /dev/null +++ b/.github/workflows/detect-gutenberg-sha-change.yml @@ -0,0 +1,59 @@ +# Generates a list of changes and a commit message when the pinned gutenberg repository hash changes. +name: Draft commit message + +on: + # This workflow was introduced in WordPress 7.0. + pull_request: + branches: + - trunk + - '[7-9].[0-9]' + paths: + - 'package.json' + +# Cancels all previous workflow runs for pull requests that have not completed. +concurrency: + # The concurrency group contains the workflow name and the branch name for pull requests + # or the commit hash for any other events. + group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.sha }} + cancel-in-progress: true + +# Disable permissions for all available scopes by default. +# Any needed permissions should be configured at the job level. +permissions: {} + +jobs: + # Detects whether the gutenberg.sha value in the package.json file has changed. + detect-hash-change: + name: Detect Gutenberg SHA change + uses: ./.github/workflows/reusable-detect-gutenberg-hash-change-v1.yml + permissions: + contents: read + + # Generates a list of changes between two specified hashes. + generate-changelog: + name: Generate a list of changes between the hashes + uses: ./.github/workflows/reusable-generate-gutenberg-changelog-v1.yml + needs: [ 'detect-hash-change' ] + if: ${{ needs.detect-hash-change.outputs.sha_changed == 'true' }} + permissions: + contents: read + with: + base-sha: ${{ needs.detect-hash-change.outputs.base_sha }} + head-sha: ${{ needs.detect-hash-change.outputs.head_sha }} + + # Drafts a commit message containing a detailed list of changes being merged. + # + # Performs the following steps: + # - Downloads the changelog artifact. + # - Builds a commit message. + # - Uploads the commit message as an artifact. + generate-commit-message: + name: Generate commit message + uses: ./.github/workflows/reusable-generate-commit-message-v1.yml + needs: [ 'detect-hash-change', 'generate-changelog' ] + if: ${{ needs.generate-changelog.outputs.has_changes == 'true' }} + permissions: + contents: read + with: + previous-hash: ${{ needs.detect-hash-change.outputs.base_sha }} + new-hash: ${{ needs.detect-hash-change.outputs.head_sha }} diff --git a/.github/workflows/pull-request-comments.yml b/.github/workflows/pull-request-comments.yml index da30e2feb7f11..314b0dc3cf8a0 100644 --- a/.github/workflows/pull-request-comments.yml +++ b/.github/workflows/pull-request-comments.yml @@ -5,7 +5,7 @@ on: pull_request_target: types: [ 'opened', 'synchronize', 'reopened', 'edited' ] workflow_run: - workflows: [ 'Test Build Processes' ] + workflows: [ 'Test Build Processes', 'Draft commit message' ] types: - completed @@ -228,3 +228,120 @@ jobs: `, } ); } + + # Adds a comment with a drafted commit message. + drafted-commit-message: + name: Manage commit message draft + runs-on: ubuntu-24.04 + permissions: + issues: write + pull-requests: write + if: ${{ github.repository == 'WordPress/wordpress-develop' && github.event_name == 'pull_request_target' && ! github.event.pull_request.draft && github.event.pull_request.state == 'open' }} + + steps: + - name: Download artifact + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + with: + script: | + const fs = require( 'fs' ); + + const artifacts = await github.rest.actions.listWorkflowRunArtifacts( { + owner: context.repo.owner, + repo: context.repo.repo, + run_id: process.env.RUN_ID, + } ); + + const matchPrNumberArtifact = artifacts.data.artifacts.filter( ( artifact ) => { + return artifact.name === 'pr-number' + } )[0]; + + if ( ! matchPrNumberArtifact ) { + core.setFailed( 'No PR number artifact found!' ); + return; + } + + const downloadPrNumber = await github.rest.actions.downloadArtifact( { + owner: context.repo.owner, + repo: context.repo.repo, + artifact_id: matchPrNumberArtifact.id, + archive_format: 'zip', + } ); + + fs.writeFileSync( '${{github.workspace}}/pr-number.zip', Buffer.from( downloadPrNumber.data ) ) + + const matchMessageArtifact = artifacts.data.artifacts.filter( ( artifact ) => { + return artifact.name === 'commit-message.md' + } )[0]; + + if ( ! matchMessageArtifact ) { + core.setFailed( 'No commit message artifact found!' ); + return; + } + + const downloadCommitMessage = await github.rest.actions.downloadArtifact( { + owner: context.repo.owner, + repo: context.repo.repo, + artifact_id: matchMessageArtifact.id, + archive_format: 'zip', + } ); + + fs.writeFileSync( '${{github.workspace}}/commit-message.zip', Buffer.from( downloadCommitMessage.data ) ) + env: + RUN_ID: ${{ github.event.workflow_run.id }} + + - name: Unzip the artifact containing the PR number + run: unzip pr-number.zip + + - name: Unzip the artifact containing the commit mesage + run: unzip commit-message.zip + + - name: Leave or update a comment with the commit message draft + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + with: + script: | + const fs = require( 'fs' ); + const issue_number = Number( fs.readFileSync( './NR' ) ); + + core.info( `Checking pull request #${issue_number}.` ); + + // Confirm that the pull request is still open before leaving a comment. + const pr = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: issue_number, + }); + + if ( pr.data.state !== 'open' ) { + core.info( 'The pull request has been closed. No comment will be left.' ); + return; + } + + // Comments are only added once and then updated on future commits. + const commentInfo = { + owner: context.repo.owner, + repo: context.repo.repo, + issue_number, + }; + + const comments = ( await github.rest.issues.listComments( commentInfo ) ).data; + const hasCommitMessageDraft = comments.find( comment => comment.user.type === 'Bot' && comment.body.includes( 'Editor: Bump pinned hash' ) ); + + // Construct comment + commentInfo.body = '## Commit Message Draft\n' + + 'This pull request changes the pinned hash for the Gutenberg repository. Here is a commit message draft containing a compiled list of changes included with additional required information:\n\n' + + ```\n' + + commitMessageContents + + '\n```\n' + + '**Always verify these commit message drafts before using. And don't forget to include props!**'; + + // Only update the comment when there are changes. + if ( hasCommitMessageDraft ) { + if ( hasCommitMessageDraft.body != commentInfo.body ) { + commentInfo.comment_id = hasCommitMessageDraft.id; + + github.rest.issues.updateComment( commentInfo ); + } + return; + } + + github.rest.issues.createComment( commentInfo ); diff --git a/.github/workflows/reusable-detect-gutenberg-hash-change-v1.yml b/.github/workflows/reusable-detect-gutenberg-hash-change-v1.yml new file mode 100644 index 0000000000000..bfb51762fd959 --- /dev/null +++ b/.github/workflows/reusable-detect-gutenberg-hash-change-v1.yml @@ -0,0 +1,64 @@ +## +# A reusable workflow that detects when the `gutenberg.sha` value changes in the `package.json` file. +## +name: Detect hash change (reusable) + +on: + workflow_call: + outputs: + sha_changed: + description: 'Whether the pinned Gutenberg hash has changed.' + value: ${{ jobs.detect-hash-change.outputs.sha_changed }} + base_sha: + description: 'The previous pinned Gutenberg hash.' + value: ${{ jobs.detect-hash-change.outputs.base_sha }} + head_sha: + description: 'The new pinned Gutenberg hash.' + value: ${{ jobs.detect-hash-change.outputs.head_sha }} + +# Disable permissions for all available scopes by default. +# Any needed permissions should be configured at the job level. +permissions: {} + +jobs: + # Detects whether the gutenberg.sha value in the package.json file has changed. + # + # Performs the following steps: + # - Checks out the repository. + # - Check if the pinned hash has changed. + detect-hash-change: + name: Detect Gutenberg SHA change + runs-on: ubuntu-24.04 + permissions: + contents: read + timeout-minutes: 5 + outputs: + sha_changed: ${{ steps.check-sha.outputs.sha_changed }} + base_sha: ${{ steps.check-sha.outputs.base_sha }} + head_sha: ${{ steps.check-sha.outputs.head_sha }} + + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + persist-credentials: false + + - name: Check if the pinned Gutenberg hash has changed + id: check-sha + run: | + BASE_GUTENBERG_SHA=$(git show ${{ github.event.pull_request.base.sha }}:package.json | jq -r '.gutenberg.sha // empty') + HEAD_GUTENBERG_SHA=$(git show ${{ github.event.pull_request.head.sha }}:package.json | jq -r '.gutenberg.sha // empty') + + echo "base_sha=$BASE_GUTENBERG_SHA" >> "$GITHUB_OUTPUT" + echo "head_sha=$HEAD_GUTENBERG_SHA" >> "$GITHUB_OUTPUT" + + if [ "$BASE_GUTENBERG_SHA" != "$HEAD_GUTENBERG_SHA" ]; then + echo "sha_changed=true" >> "$GITHUB_OUTPUT" + echo "The pinned Gutenberg Repository hash has changed." + echo " Previous SHA (base branch): $BASE_GUTENBERG_SHA" + echo " New SHA (head branch): $HEAD_GUTENBERG_SHA" + else + echo "sha_changed=false" >> "$GITHUB_OUTPUT" + echo "The pinned Gutenberg repository hash has not changed: $HEAD_GUTENBERG_SHA" + fi diff --git a/.github/workflows/reusable-generate-commit-message-v1.yml b/.github/workflows/reusable-generate-commit-message-v1.yml new file mode 100644 index 0000000000000..cf3363e789add --- /dev/null +++ b/.github/workflows/reusable-generate-commit-message-v1.yml @@ -0,0 +1,85 @@ +## +# A reusable workflow that detects when the `gutenberg.sha` value changes in the `package.json` file. +## +name: Detect hash change (reusable) + +on: + workflow_call: + inputs: + previous-hash: + description: 'The previous commit SHA value.' + required: true + type: 'string' + new-hash: + description: 'The new commit hash value.' + required: true + type: 'string' + +# Disable permissions for all available scopes by default. +# Any needed permissions should be configured at the job level. +permissions: {} + +jobs: + # Drafts a commit message containing a detailed list of changes being merged. + # + # Performs the following steps: + # - Downloads the changelog artifact. + # - Builds a commit message. + # - Uploads the commit message as an artifact. + # - Saves the pull request number to a text file. + # - Uploads the pull request number as an artifact. + generate-commit-message: + name: Generate commit message + runs-on: ubuntu-24.04 + permissions: + contents: read + + steps: + - name: Download changelog artifact + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: changelog.txt + skip-decompress: true + + - name: Build commit message + env: + BASE_SHA: ${{ inputs.previous-hash }} + HEAD_SHA: ${{ inputs.new-hash }} + run: | + { + printf 'Editor: Bump pinned hash for the Gutenberg repository.\n\n' + printf "This updates the pinned hash from the gutenberg from \`%s\` to \`%s\`.\n\n" "$BASE_SHA" "$HEAD_SHA" + + if [ "$HAS_CHANGES" = "false" ]; then + printf '> [!WARNING]\n' + printf '> No pull request references were found in the commits between the two hashes. Please verify the hash range is correct.\n\n' + else + printf 'The following changes are included:\n\n' + cat changelog.txt + printf '\n' + fi + + printf 'A full list of changes can be found on GitHub: https://github.com/WordPress/gutenberg/compare/%s...%s.\n\n' "$BASE_SHA" "$HEAD_SHA" + printf 'See #64595, #64393.\n' + } > commit-message.md + + - name: Upload commit message as an artifact + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: commit-message + path: commit-message.md + + - name: Save PR number + run: | + mkdir -p ./pr-number + echo "${EVENT_NUMBER}" > ./pr-number/NR + env: + EVENT_NUMBER: ${{ github.event.number }} + + # Uploads the PR number as an artifact for the Pull Request Commenting workflow to download and then + # leave a comment detailing how to test the PR within WordPress Playground. + - name: Upload PR number as artifact + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + with: + name: pr-number + path: pr-number/ diff --git a/.github/workflows/reusable-generate-gutenberg-changelog-v1.yml b/.github/workflows/reusable-generate-gutenberg-changelog-v1.yml new file mode 100644 index 0000000000000..7eba4483454a8 --- /dev/null +++ b/.github/workflows/reusable-generate-gutenberg-changelog-v1.yml @@ -0,0 +1,70 @@ +## +# A reusable workflow that detects when the `gutenberg.sha` value changes in the `package.json` file. +## +name: Detect hash change (reusable) + +on: + workflow_call: + inputs: + base-sha: + description: 'The previous pinned Gutenberg hash.' + type: string + required: true + head-sha: + description: 'The new pinned Gutenberg hash.' + type: string + required: true + outputs: + has_changes: + description: 'Whether any pull request-linked changes were found between the two hashes.' + value: ${{ jobs.generate-changelog.outputs.has_changes }} + +# Disable permissions for all available scopes by default. +# Any needed permissions should be configured at the job level. +permissions: {} + +jobs: + # Generates a list of changes between two specified hashes. + # + # Performs the following steps: + # - Checks out the repository. + # - Generates a list of changes. + # - Uploads the changelog as an artifact. + generate-changelog: + name: Generate a list of changes between the hashes + runs-on: ubuntu-24.04 + permissions: + contents: read + timeout-minutes: 5 + outputs: + has_changes: ${{ steps.change-list.outputs.has_changes }} + + steps: + - name: Checkout Gutenberg repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + repository: WordPress/gutenberg + filter: blob:none + fetch-depth: 0 + + - name: Generate a list of changes + id: change-list + env: + BASE_SHA: ${{ inputs.base-sha }} + HEAD_SHA: ${{ inputs.head-sha }} + run: | + git log --reverse --format="- %s" "$BASE_SHA".."$HEAD_SHA" | \ + sed 's|#\([0-9][0-9]*\)|https://github.com/WordPress/gutenberg/pull/\1|g; /github\.com\/WordPress\/gutenberg\/pull/!d' \ + > changelog.txt + + if [ -s changelog.txt ]; then + echo "has_changes=true" >> "$GITHUB_OUTPUT" + else + echo "has_changes=false" >> "$GITHUB_OUTPUT" + fi + + - name: Upload changelog as an artifact + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + path: changelog.txt + archive: false diff --git a/package.json b/package.json index 5a390aac47174..6377a1bee9ab0 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "url": "https://develop.svn.wordpress.org/trunk" }, "gutenberg": { - "sha": "8c78d87453509661a9f28f978ba2c242d515563b", + "sha": "684ad23205876b8c527471a243f3183257027b25", "ghcrRepo": "WordPress/gutenberg/gutenberg-wp-develop-build" }, "engines": {