diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000000..24e2573546f53 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,213 @@ +# Configure Dependabot scanning. +version: 2 + +updates: + # Check for updates to GitHub Actions. + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + open-pull-requests-limit: 10 + groups: + github-actions: + patterns: + - "*" + + # Check for updates to Composer packages. + - package-ecosystem: "composer" + directory: "/" + schedule: + interval: "daily" + open-pull-requests-limit: 10 + ignore: + # These dependencies do not currently need to be managed with Dependabot. + - dependency-name: "squizlabs/php_codesniffer" + - dependency-name: "wp-coding-standards/wpcs" + - dependency-name: "phpcompatibility/php-compatibility" + - dependency-name: "yoast/phpunit-polyfills" + groups: + composer-packages: + patterns: + - "composer/ca-bundle" + + # Monitor some npm dependencies for updates in groups. + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "daily" + open-pull-requests-limit: 20 + ignore: + - dependency-name: "@wordpress/*" + groups: + ## + # Groups for updating devDependencies. + ## + + # Dependencies related to Playwright testing (E2E, performance). + tests-playwright: + patterns: + - "*playwright*" + # Dependencies related to JavaScript testing with QUnit. + tests-qunit: + patterns: + - "*qunit*" + - "sinon*" + # Dependencies related to CSS and SASS building and manilupating. + dev-css-sass: + patterns: + - "autoprefixer" + # postcss and css related dependencies. + - "*css*" + - "*sass" + # Dependencies related to the Webpack build process. + dev-webpack: + patterns: + - "*webpack*" + - "react-refresh" + - "source-map-loader" + # Dependencies related to the local Docker development environment. + dev-docker: + patterns: + - "dotenv*" + - "wait-on" + # Dependencies that do not fall into a specific grouping. + dev-miscellaneous: + patterns: + - "chalk" + - "check-node-version" + - "ink-docstrap" + - "install-changed" + - "matchdep" + - "uuid" + # Dependencies related to JavaScript minification. + dev-uglify: + patterns: + - "*uglify*" + # All GruntJS related dependencies that do not relate to another group. + dev-grunt: + patterns: + - "*grunt*" + + ## + # Groups for updating production dependencies. + ## + + # Dependencies related to jQuery and its ecosystem. + external-jquery: + patterns: + - "jquery*" + # Dependencies related to React and its ecosystem. + external-react: + patterns: + - "react*" + - "!react-refresh" + # Dependencies used for bundling polyfill libraries into WordPress. + external-polyfills: + patterns: + - "core-js-url-browser" + - "element-closest" + - "formdata-polyfill" + - "imagesloaded" + - "objectFitPolyfill" + - "polyfill-library" + - "regenerator-runtime" + - "whatwg-fetch" + - "wicg-inert" + # Dependencies related to the Masonry library. + external-masonry: + patterns: + - "masonry-layout" + # Dependencies that do not fall into a specific grouping. + external-miscellaneous: + patterns: + - "backbone" + - "clipboard" + - "hoverintent" + - "json2php" + - "lodash" + - "moment" + - "underscore" + + # Monitor npm dependencies within default themes. + - package-ecosystem: "npm" + directory: "/src/wp-content/themes/twentytwentyfive" + schedule: + interval: "weekly" + open-pull-requests-limit: 20 + groups: + twentytwentyfive-css: + patterns: + - "**browserslist*" + - "*css*" + + - package-ecosystem: "npm" + directory: "/src/wp-content/themes/twentytwentytwo" + schedule: + interval: "weekly" + open-pull-requests-limit: 20 + groups: + twentytwentytwo-css: + patterns: + - "**browserslist*" + - "*css*" + + - package-ecosystem: "npm" + directory: "/src/wp-content/themes/twentytwentyone" + schedule: + interval: "weekly" + open-pull-requests-limit: 20 + groups: + twentytwentyone-sass-css: + patterns: + - "**browserslist*" + - "autoprefixer" + - "*css*" + - "*sass*" + - "!*stylelint*" + twentytwentyone-eslint: + patterns: + - "**eslint*" + twentytwentyone-stylelint: + patterns: + - "**stylelint*" + twentytwentyone-miscellaneous: + patterns: + - "chokidar-cli" + - "minimist" + - "npm-run-all" + + - package-ecosystem: "npm" + directory: "/src/wp-content/themes/twentytwenty" + schedule: + interval: "weekly" + open-pull-requests-limit: 20 + groups: + twentytwenty-css: + patterns: + - "**browserslist*" + - "autoprefixer" + - "*css*" + twentytwenty-stylelint: + patterns: + - "*stylelint*" + twentytwenty-miscellaneous: + patterns: + - "concurrently" + - "@wordpress/scripts" + + - package-ecosystem: "npm" + directory: "/src/wp-content/themes/twentynineteen" + schedule: + interval: "weekly" + open-pull-requests-limit: 20 + groups: + twentynineteen-css-sass: + patterns: + - "**browserslist*" + - "autoprefixer" + - "*css*" + - "*sass*" + twentynineteen-miscellaneous: + patterns: + - "chokidar-cli" + - "npm-run-all" diff --git a/.github/workflows/check-built-files.yml b/.github/workflows/check-built-files.yml index 01a239c4eb3b0..72a1ad4e1a0a4 100644 --- a/.github/workflows/check-built-files.yml +++ b/.github/workflows/check-built-files.yml @@ -1,4 +1,4 @@ -# Checks for uncommitted changes to built files in pull requests. +# Checks for uncommitted or unexpected changes to built files within pull requests. name: Check Built Files (PRs) on: @@ -31,6 +31,7 @@ on: # Confirm any changes to relevant workflow files. - '.github/workflows/check-built-files.yml' - '.github/workflows/reusable-check-built-files.yml' + - '.github/workflows/reusable-compare-built-files-*.yml' # Changes to the default themes should be handled by the themes workflows. - '!src/wp-content/themes/twenty**' @@ -46,9 +47,18 @@ concurrency: permissions: {} jobs: + # Checks built files for uncommitted changes. check-for-built-file-changes: - name: Check built files - if: ${{ github.repository == 'wordpress/wordpress-develop' }} + name: Check for uncommitted changes + if: ${{ github.repository == 'WordPress/wordpress-develop' || github.event_name == 'pull_request' }} uses: ./.github/workflows/reusable-check-built-files.yml permissions: contents: read + + # Compares the build directory with the WordPress/WordPress repository. + compare-with-build-server: + name: Compare built files to WordPress/WordPress + uses: ./.github/workflows/reusable-compare-built-files-v1.yml + permissions: + contents: read + #if: ${{ github.repository == 'WordPress/wordpress-develop' || github.event_name == 'pull_request' }} diff --git a/.github/workflows/pull-request-comments.yml b/.github/workflows/pull-request-comments.yml index da30e2feb7f11..8744fe7be4444 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: [ 'Check Built Files (PRs)', 'Test Build Processes' ] types: - completed @@ -22,6 +22,7 @@ permissions: {} jobs: # Comments on a pull request when the author is a first time contributor. post-welcome-message: + name: Contributor welcome message runs-on: ubuntu-24.04 permissions: issues: write @@ -79,7 +80,7 @@ jobs: # Leaves a comment on a pull request with a link to test the changes in a WordPress Playground instance. playground-details: - name: Comment on a pull request with Playground details + name: Leave Playground testing details runs-on: ubuntu-24.04 permissions: issues: write @@ -87,6 +88,7 @@ jobs: if: > github.repository == 'WordPress/wordpress-develop' && github.event.workflow_run.event == 'pull_request' && + github.event.workflow_run.name == 'Test Build Processes' && github.event.workflow_run.conclusion == 'success' steps: - name: Download artifact @@ -180,6 +182,145 @@ jobs: github.rest.issues.createComment( commentInfo ); + # Leaves a comment on a pull request noting differences between the PR and the build server. + build-server-comparison: + name: Note differences with the build server + runs-on: ubuntu-24.04 + permissions: + issues: write + pull-requests: write + if: > + github.event.workflow_run.event == 'pull_request' && + github.event.workflow_run.name == 'Check Built Files (PRs)' && + github.event.workflow_run.conclusion == 'success' + steps: + - name: Download artifact + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + env: + RUN_ID: ${{ github.event.workflow_run.id }} + 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 === 'build-server-comparison' + } )[0]; + + if ( ! matchArtifact ) { + core.setFailed( '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}}/build-server-comparison.zip', Buffer.from( download.data ) ) + + - name: Unzip the artifact containing the comparison info + run: unzip build-server-comparison.zip + + - name: Leave a comment with any differences noticed + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + with: + script: | + const fs = require( 'fs' ); + const issue_number = Number( fs.readFileSync( './NR' ) ); + const fileChanges = fs.readFileSync( './file-changes.txt', 'utf8' ); + const diffContents = fs.readFileSync( './changes.diff', 'utf8' ); + const MAX_DIFF_LENGTH = 50000; // GitHub has a 65,536 character limit for comments. + + 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 after the first successful build. Check for the presence of a comment and bail early. + const commentInfo = { + owner: context.repo.owner, + repo: context.repo.repo, + issue_number, + }; + + const comments = ( await github.rest.issues.listComments( commentInfo ) ).data; + + for ( const currentComment of comments ) { + if ( currentComment.user.type === 'Bot' && currentComment.body.includes( 'Build Server Comparison' ) ) { + commentInfo.comment_id = currentComment.id; + break; + } + }; + + commentInfo.body = "## Build Server Comparison\n\n"; + + // Post or update the comment. + if ( fileChanges.trim() === '' ) { + commentInfo.body += 'The contents of the `build` directory after running `npm run build` matches the contents of the WordPress/WordPress repository. No differences were found.'; + } else { + commentInfo.body += `The contents of the \`build\` directory after running \`npm run build\` has been compared with the contents of the WordPress/WordPress repository. + + **Review these differences carefully for any unexpected results.** + + ### List of Modified Files + + \`\`\` + ${ fileChanges } + \`\`\` + + ### Full Diff File + `; + + if ( diffContents.length > MAX_DIFF_LENGTH ) { + const cutoff = diffContents.lastIndexOf( '\n', MAX_DIFF_LENGTH ); + const truncated = diffContents.substring( 0, cutoff ); + + commentInfo.body += `
+ Click to expand (truncated) + + \`\`\`diff + ${ truncated } + \`\`\` + + ⚠️ The diff was too large to display in full. + +
`; + } else { + commentInfo.body += `
+ Click to expand + + \`\`\`diff + ${ diffContents } + \`\`\` + +
`; + } + + commentInfo.body += `\n\n[Download the complete .diff file from the workflow run](https://github.com/${ context.repo.owner }/${ context.repo.repo }/actions/runs/${ context.payload.workflow_run.id }).`; + } + + if ( commentInfo.comment_id ) { + github.rest.issues.updateComment( commentInfo ); + } else { + github.rest.issues.createComment( commentInfo ); + } + # Manages comments reminding contributors to include a Trac ticket link when opening a pull request. trac-ticket-check: name: Manage Trac ticket reminders for pull requests diff --git a/.github/workflows/reusable-check-built-files.yml b/.github/workflows/reusable-check-built-files.yml index 11d97639a30fc..30bb3ed5021b4 100644 --- a/.github/workflows/reusable-check-built-files.yml +++ b/.github/workflows/reusable-check-built-files.yml @@ -1,7 +1,7 @@ ## # A reusable workflow that checks for uncommitted changes to built files in pull requests. ## -name: Check Built Files (PRs) +name: Check for Changes to Versioned Files (reusable) on: workflow_call: @@ -9,7 +9,7 @@ on: permissions: {} jobs: - # Checks a PR for uncommitted changes to built files. + # Checks a PR for uncommitted changes to versioned files. # # When changes are detected, the patch is stored as an artifact for processing by the Commit Built File Changes # workflow. @@ -29,8 +29,8 @@ jobs: # - Displays the result of git diff for debugging purposes. # - Saves the diff to a patch file. # - Uploads the patch file as an artifact. - update-built-files: - name: Check and update built files + check-versioned-files: + name: Check for changes runs-on: ubuntu-24.04 timeout-minutes: 10 permissions: diff --git a/.github/workflows/reusable-compare-built-files-v1.yml b/.github/workflows/reusable-compare-built-files-v1.yml new file mode 100644 index 0000000000000..59fa79dc5e111 --- /dev/null +++ b/.github/workflows/reusable-compare-built-files-v1.yml @@ -0,0 +1,110 @@ +## +# A reusable workflow that compares the results of the build script with the most recent commit to WordPress/WordPress. +## +name: Compare Built Files (reusable) + +on: + workflow_call: + +# Disable permissions for all available scopes by default. +# Any needed permissions should be configured at the job level. +permissions: {} + +jobs: + # Runs the PHP coding standards checks. + # + # Violations are reported inline with annotations. + # + # Performs the following steps: + # - Checks out the repository. + # - Sets up Node.js. + # - Sets up PHP. + # - Installs Composer dependencies. + # - Logs debug information about the GitHub Action runner. + # - Installs npm dependencies. + # - Builds WordPress to run from the build directory. + # - Ensures version-controlled files are not modified or deleted. + # - Checks out the WordPress/WordPress repository. + # - Creates a directory for text files to be uploaded as an artifact. + # - Stores a list of files that differ in the build directory from WordPress/WordPress. + # - Stores a diff file comparing the build directory to WordPress/WordPress. + # - Saves the pull request number to a text file. + # - Uploads the generated files as an artifact. + compare-built-files: + name: Compare built files to WordPress/WordPress + runs-on: ubuntu-24.04 + permissions: + contents: read + timeout-minutes: 10 + + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} + persist-credentials: false + + - name: Set up Node.js + uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 + with: + node-version-file: '.nvmrc' + cache: npm + + - name: Set up PHP + uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # v2.37.0 + with: + php-version: '8.4' + coverage: none + + # 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@65e4f84970763564f46a70b8a54b90d033b3bdda # v4.0.0 + with: + custom-cache-suffix: $(/bin/date -u --date='last Mon' "+%F") + + - name: Log debug information + run: | + npm --version + node --version + git --version + + - name: Install npm Dependencies + run: npm ci + + - name: Build WordPress to run from build directory + run: npm run build + + - name: Ensure version-controlled files are not modified or deleted + run: git diff --exit-code + + - name: Checkout WordPress/WordPress + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + repository: 'WordPress/WordPress' + ref: ${{ github.base_ref == 'trunk' && 'master' || format( '{0}-branch', github.base_ref ) }} + path: ${{ github.workspace }}/build-server + show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} + persist-credentials: false + + - name: Create directory for artifacts + run: mkdir artifacts + + - name: Create a list of files that have changed + run: diff -rq ${{ github.workspace }}/build ${{ github.workspace }}/build-server | sed "s|${{ github.workspace }}/||g" > artifacts/file-changes.txt + + - name: Create a list of files that have changed + run: diff -r ${{ github.workspace }}/build ${{ github.workspace }}/build-server | sed "s|${{ github.workspace }}/||g" > artifacts/changes.diff + + - name: Save PR number + run: echo "${EVENT_NUMBER}" > ./artifacts/NR + env: + EVENT_NUMBER: ${{ github.event.number }} + + # Uploads the associated text files as an artifact. + - name: Upload comparison results as an artifact + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + if: ${{ github.repository == 'WordPress/wordpress-develop' && github.event_name == 'pull_request' }} + with: + name: build-server-comparison + path: artifacts/ diff --git a/composer.json b/composer.json index ee5c5d0c0aa03..e72f63119c3ac 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "squizlabs/php_codesniffer": "3.13.5", "wp-coding-standards/wpcs": "~3.3.0", "phpcompatibility/phpcompatibility-wp": "~2.1.3", - "phpstan/phpstan": "2.1.39", + "phpstan/phpstan": "2.1.45", "yoast/phpunit-polyfills": "^1.1.0" }, "config": {