diff --git a/.github/workflows/check-built-files.yml b/.github/workflows/check-built-files.yml index 8e4946330a..e1338f8518 100644 --- a/.github/workflows/check-built-files.yml +++ b/.github/workflows/check-built-files.yml @@ -1,12 +1,12 @@ -# Checks for uncommitted changes to built files and pushes changes back. -name: Check built files +# Checks for uncommitted changes to built files in pull requests. +name: Check Built Files (PRs) on: # Because all commits happen through SVN and should always be manually reviewed by a committer, this workflow only # runs for pull requests. # - # Other workflows that run on push will detect changes to versioned files and fail. - pull_request_target: + # Other workflows that run for the push event will detect changes to versioned files and fail. + pull_request: branches: - trunk - '6.[8-9]' @@ -31,7 +31,7 @@ on: 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_target' && github.head_ref || github.sha }} + 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. @@ -39,13 +39,8 @@ concurrency: permissions: {} jobs: - update-built-files: - name: Update built files - permissions: - contents: write - if: ${{ github.repository == 'WordPress/wordpress-develop' }} - # This should always reference a version of the workflow committed through SVN and never a local reference. - uses: WordPress/wordpress-develop/.github/workflows/reusable-check-built-files.yml@trunk - secrets: - GH_APP_ID: ${{ secrets.GH_PR_MANAGEMENT_APP_ID }} - GH_APP_PRIVATE_KEY: ${{ secrets.GH_PR_MANAGEMENT_APP_PRIVATE_KEY }} + check-for-built-file-changes: + name: Check built files + # This prevents an unnecessary second run after changes are committed back because Dependabot always rebases and force pushes. + if: ${{ github.repository == 'wordpress/wordpress-develop' && ( github.actor != 'dependabot[bot]' || github.event.commits < 2 ) }} + uses: ./.github/workflows/reusable-check-built-files.yml diff --git a/.github/workflows/commit-built-file-changes.yml b/.github/workflows/commit-built-file-changes.yml new file mode 100644 index 0000000000..bbe4b62d4f --- /dev/null +++ b/.github/workflows/commit-built-file-changes.yml @@ -0,0 +1,126 @@ +# Commits all missed changes to built files back to pull request branches. +name: Commit Built File Changes (PRs) + +on: + workflow_run: + workflows: [ 'Check Built Files (PRs)' ] + types: + - completed + +# 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 == 'workflow_run' && format( '{0}-{1}', github.event.workflow_run.head_branch, github.event.workflow_run.head_repository.name ) || github.sha }} + +# Disable permissions for all available scopes by default. +# Any needed permissions should be configured at the job level. +permissions: {} + +jobs: + # Checks a PR for uncommitted changes to built files. + # + # Performs the following steps: + # - Attempts to download the artifact containing the PR diff. + # - Checks for the existence of an artifact. + # - Unzips the artifact. + # - Checks out the repository. + # - Applies the patch file. + # - Displays the result of git diff. + # - Configures the Git author. + # - Stages changes. + # - Commits changes. + # - Pushes changes. + update-built-files: + name: Check and update built files + runs-on: ubuntu-24.04 + if: ${{ github.repository == 'wordpress/wordpress-develop' }} + timeout-minutes: 10 + permissions: + contents: write + steps: + - name: Download artifact + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + script: | + const artifacts = await github.rest.actions.listWorkflowRunArtifacts( { + owner: context.repo.owner, + repo: context.repo.repo, + run_id: process.env.RUN_ID, + } ); + + const matchArtifact = artifacts.data.artifacts.filter( ( artifact ) => { + return artifact.name === 'pr-built-file-changes' + } )[0]; + + if ( ! matchArtifact ) { + core.info( 'No artifact found!' ); + return; + } + + const download = await github.rest.actions.downloadArtifact( { + owner: context.repo.owner, + repo: context.repo.repo, + artifact_id: matchArtifact.id, + archive_format: 'zip', + } ); + + const fs = require( 'fs' ); + fs.writeFileSync( '${{ github.workspace }}/pr-built-file-changes.zip', Buffer.from( download.data ) ) + env: + RUN_ID: ${{ github.event.workflow_run.id }} + + - name: Check for artifact + id: artifact-check + run: | + if [ -f "pr-built-file-changes.zip" ]; then + echo "exists=true" >> "$GITHUB_OUTPUT" + else + echo "exists=false" >> "$GITHUB_OUTPUT" + fi + + - name: Unzip the artifact containing the PR data + if: ${{ steps.artifact-check.outputs.exists == 'true' }} + run: unzip pr-built-file-changes.zip + + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + if: ${{ steps.artifact-check.outputs.exists == 'true' }} + with: + repository: ${{ github.event.workflow_run.repository.full_name }} + ref: ${{ github.event.workflow_run.head_branch }} + path: 'pr-repo' + show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} + + - name: Apply patch + if: ${{ steps.artifact-check.outputs.exists == 'true' }} + working-directory: 'pr-repo' + run: git apply ${{ github.workspace }}/changes.diff + + - name: Display changes to versioned files + if: ${{ steps.artifact-check.outputs.exists == 'true' }} + working-directory: 'pr-repo' + run: git diff + + - name: Configure git user name and email + if: ${{ steps.artifact-check.outputs.exists == 'true' }} + working-directory: 'pr-repo' + run: | + git config user.name "WordPress Build Script Bot[bot]" + git config user.email wordpress@users.noreply.github.com + + - name: Stage changes + if: ${{ steps.artifact-check.outputs.exists == 'true' }} + working-directory: 'pr-repo' + run: git add . + + - name: Commit changes + if: ${{ steps.artifact-check.outputs.exists == 'true' }} + working-directory: 'pr-repo' + run: | + git commit -m "Automation: Updating built files with changes. [dependabot skip]" + + - name: Push changes + if: ${{ steps.artifact-check.outputs.exists == 'true' }} + working-directory: 'pr-repo' + run: git push diff --git a/.github/workflows/reusable-check-built-files.yml b/.github/workflows/reusable-check-built-files.yml index 72cc138b60..8c54ac3472 100644 --- a/.github/workflows/reusable-check-built-files.yml +++ b/.github/workflows/reusable-check-built-files.yml @@ -1,24 +1,20 @@ -name: Lint GitHub Actions workflows +## +# A reusable workflow that checks for uncommitted changes to built files in pull requests. +## +name: Check Built Files (PRs) + on: workflow_call: - secrets: - GH_APP_ID: - description: 'A GitHub App ID.' - required: true - GH_APP_PRIVATE_KEY: - description: 'A GitHub App private key.' - required: true permissions: {} jobs: # Checks a PR for uncommitted changes to built files. # - # This job uses a GitHub App instead of $GITHUB_TOKEN because Dependabot pull requests are only granted - # read-only access. + # When changes are detected, the patch is stored as an artifact for processing by the Commit Built File Changes + # workflow. # # Performs the following steps: - # - Generates a token for authenticating with the GitHub App. # - Checks out the repository. # - Sets up Node.js. # - Configures caching for Composer. @@ -31,62 +27,17 @@ jobs: # - Builds WordPress. # - Checks for changes to versioned files. # - Displays the result of git diff for debugging purposes. - # - Configures the Git author. - # - Stages changes. - # - Commits changes. - # - Pushes changes. + # - Saves the diff to a patch file. + # - Uploads the patch file as an artifact. update-built-files: name: Check and update built files runs-on: ubuntu-24.04 - # This prevents an unnecessary second run after changes are committed back because Dependabot always rebases - # updates and force pushes. - if: ${{ github.actor != 'dependabot[bot]' || github.event.commits < 2 }} timeout-minutes: 10 - permissions: - contents: write steps: - - name: Generate Installation Token - id: generate_token - env: - GH_APP_ID: ${{ secrets.GH_APP_ID }} - GH_APP_PRIVATE_KEY: ${{ secrets.GH_APP_PRIVATE_KEY }} - run: | - echo "$GH_APP_PRIVATE_KEY" > private-key.pem - - # Generate JWT - JWT=$(python3 - <> "$GITHUB_ENV" - - rm -f private-key.pem - - name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: - repository: ${{ github.event.pull_request.head.repo.full_name }} - ref: ${{ github.event.pull_request.head.ref }} show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} - token: ${{ env.ACCESS_TOKEN }} - name: Set up Node.js uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 @@ -144,21 +95,14 @@ jobs: if: ${{ steps.built-file-check.outputs.uncommitted_changes == 'true' }} run: git diff - - name: Configure git user name and email + - name: Save diff to a file if: ${{ steps.built-file-check.outputs.uncommitted_changes == 'true' }} - run: | - git config user.name "wordpress-develop-pr-bot[bot]" - git config user.email ${{ secrets.GH_APP_ID }}+wordpress-develop-pr-bot[bot]@users.noreply.github.com + run: git diff > ./changes.diff - - name: Stage changes + # Uploads the diff file as an artifact. + - name: Upload diff file as artifact + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 if: ${{ steps.built-file-check.outputs.uncommitted_changes == 'true' }} - run: git add . - - - name: Commit changes - if: ${{ steps.built-file-check.outputs.uncommitted_changes == 'true' }} - run: | - git commit -m "Automation: Updating built files with changes. [dependabot skip]" - - - name: Push changes - if: ${{ steps.built-file-check.outputs.uncommitted_changes == 'true' }} - run: git push + with: + name: pr-built-file-changes + path: changes.diff