Build/Test Tools: Introduce a workflow for checking built files.

There are several files generated and updated by the build process that are under version control. Including changes to these files is a common missed step for contributors regardless of experience level.

This introduces a workflow that checks for changes to versioned files as a result of other changes in pull requests and commits them back to the head branch. Because this workflow requires the `pull_request_target` event instead of `pull_request`, local references to reusable workflows should never be used.

In addition to improving the contributor experience, this also opens the door to use Dependabot for monitoring npm dependencies, many of which produce changes to built files when updating.

Props desrosj, johnbillion, joemcgill, swissspidy.
See #62221.

git-svn-id: https://develop.svn.wordpress.org/trunk@59983 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Jonathan Desrosiers 2025-03-14 18:51:49 +00:00
parent 7aae2ea200
commit e7e27142e2
2 changed files with 214 additions and 0 deletions

51
.github/workflows/check-built-files.yml vendored Normal file
View File

@ -0,0 +1,51 @@
# Checks for uncommitted changes to built files and pushes changes back.
name: Check built files
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:
branches:
- trunk
- '6.[8-9]'
- '[7-9].[0-9]'
paths:
# Any change to a CSS, JavaScript, JSON, or SASS file should run checks.
- '**.css'
- '**.js'
- '**.json'
- '**.sass'
# These files configure npm and the task runner. Changes could affect the outcome.
- 'package*.json'
- 'Gruntfile.js'
- 'webpack.config.js'
- 'tools/webpack/**'
# These files configure Composer. Changes could affect the outcome.
- 'composer.*'
# Confirm any changes to relevant workflow files.
- '.github/workflows/check-built-files.yml'
# 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_target' && 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:
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_APP_ID }}
GH_APP_PRIVATE_KEY: ${{ secrets.GH_APP_PRIVATE_KEY }}

View File

@ -0,0 +1,163 @@
name: Lint GitHub Actions workflows
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.
#
# 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.
# - Installs Composer dependencies.
# - Logs general debug information about the runner.
# - Installs npm dependencies.
# - Builds CSS file using SASS.
# - Builds Emoji files.
# - Builds bundled Root Certificate files.
# - 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.
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 - <<EOF
import jwt, time
private_key = open("private-key.pem", "r").read()
payload = {
"iat": int(time.time()),
"exp": int(time.time()) + 600, # 10-minute expiration
"iss": $GH_APP_ID
}
print(jwt.encode(payload, private_key, algorithm="RS256"))
EOF
)
# Get Installation ID
INSTALLATION_ID=$(curl -s -X GET -H "Authorization: Bearer $JWT" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/app/installations | jq -r '.[0].id')
# Request Installation Access Token
ACCESS_TOKEN=$(curl -s -X POST -H "Authorization: Bearer $JWT" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/app/installations/$INSTALLATION_ID/access_tokens" | jq -r '.token')
echo "ACCESS_TOKEN=$ACCESS_TOKEN" >> "$GITHUB_ENV"
rm -f private-key.pem
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{ github.head_ref }}
show-progress: ${{ runner.debug == '1' && 'true' || 'false' }}
token: ${{ env.ACCESS_TOKEN }}
- name: Set up Node.js
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
with:
node-version-file: '.nvmrc'
cache: npm
# This date is used to ensure that the PHPCS cache is cleared at least once every week.
# http://man7.org/linux/man-pages/man1/date.1.html
- name: "Get last Monday's date"
id: get-date
run: echo "date=$(/bin/date -u --date='last Mon' "+%F")" >> "$GITHUB_OUTPUT"
# Since Composer dependencies are installed using `composer update` and no lock file is in version control,
# passing a custom cache suffix ensures that the cache is flushed at least once per week.
- name: Install Composer dependencies
uses: ramsey/composer-install@57532f8be5bda426838819c5ee9afb8af389d51a # v3.0.0
with:
custom-cache-suffix: ${{ steps.get-date.outputs.date }}
- name: Log debug information
run: |
npm --version
node --version
curl --version
git --version
- name: Install npm Dependencies
run: npm ci
- name: Run SASS precommit tasks
run: npm run grunt precommit:css
- name: Run Emoji precommit task
run: npm run grunt precommit:emoji
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Run certificate tasks
run: npm run grunt copy:certificates
- name: Build WordPress
run: npm run build:dev
- name: Check for changes to versioned files
id: built-file-check
run: |
if git diff --quiet; then
echo "uncommitted_changes=false" >> "$GITHUB_OUTPUT"
else
echo "uncommitted_changes=true" >> "$GITHUB_OUTPUT"
fi
- name: Display changes to versioned files
if: ${{ steps.built-file-check.outputs.uncommitted_changes == 'true' }}
run: git diff
- name: Configure git user name and email
if: ${{ steps.built-file-check.outputs.uncommitted_changes == 'true' }}
run: |
git config user.name "dependabot[bot]"
git config user.email 49699333+dependabot[bot]@users.noreply.github.com
- name: Stage changes
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