diff --git a/.github/dependabot.yml b/.github/dependabot.yml index bf50ffc..991c6c3 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -9,6 +9,17 @@ updates: - scope:distribution cooldown: default-days: 7 + # Only wp-cli-tests carries a package.json, holding the pinned version of the + # Gherkin linter. This is a no-op in every other repository. + - package-ecosystem: npm + directory: "/" + schedule: + interval: daily + open-pull-requests-limit: 10 + labels: + - scope:distribution + cooldown: + default-days: 7 - package-ecosystem: github-actions directory: "/" schedule: diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index c703112..f2541f7 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -19,6 +19,16 @@ jobs: permissions: contents: read + env: + MYSQL_HOST: 127.0.0.1 + MYSQL_TCP_PORT: 3306 + WP_CLI_TEST_DBROOTUSER: root + WP_CLI_TEST_DBROOTPASS: root + WP_CLI_TEST_DBNAME: wp_cli_test + WP_CLI_TEST_DBUSER: wp_cli_test + WP_CLI_TEST_DBPASS: password1 + WP_CLI_TEST_DBHOST: 127.0.0.1:3306 + steps: - name: Checkout code uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 @@ -45,3 +55,28 @@ jobs: uses: ramsey/composer-install@65e4f84970763564f46a70b8a54b90d033b3bdda # 4.0.0 env: COMPOSER_ROOT_VERSION: dev-${{ github.event.repository.default_branch }} + + # Without a database the Behat runner silently falls back to SQLite, so the + # agent's test runs are not the ones CI will do. Mirrors the setup in + # reusable-functional.yml. + - name: Check existence of behat.yml file + id: check_behat_file + run: echo "files_exists=$(test -f behat.yml && echo true || echo false)" >> "$GITHUB_OUTPUT" + + - name: Setup MySQL Server + if: steps.check_behat_file.outputs.files_exists == 'true' + uses: shogo82148/actions-setup-mysql@62da9377d83991fce27b6ed2a397d3306121e41d # v1 + with: + mysql-version: '8.0' # Standard MySQL version for these tests + auto-start: true + root-password: ${{ env.WP_CLI_TEST_DBROOTPASS }} + user: ${{ env.WP_CLI_TEST_DBUSER }} + password: ${{ env.WP_CLI_TEST_DBPASS }} + + - name: Remove system MySQL binary + if: steps.check_behat_file.outputs.files_exists == 'true' + run: sudo rm -f /usr/bin/mysql /usr/bin/mysqldump + + - name: Prepare test database + if: steps.check_behat_file.outputs.files_exists == 'true' + run: composer prepare-tests diff --git a/.github/workflows/reusable-code-quality.yml b/.github/workflows/reusable-code-quality.yml index 59c82cf..6757409 100644 --- a/.github/workflows/reusable-code-quality.yml +++ b/.github/workflows/reusable-code-quality.yml @@ -126,15 +126,40 @@ jobs: with: node-version: 'lts/*' - # `--fail` matters here: without it curl happily writes an error page to the - # config file and the linter then runs against garbage rules. - - name: Download lint rules - run: curl --fail --silent --show-error https://raw.githubusercontent.com/wp-cli/.github/refs/heads/main/.gherkin-lintrc -o "$RUNNER_TEMP/.gherkin-lintrc" + - name: Check existence of composer.json file + id: check_composer_file + run: echo "files_exists=$(test -f composer.json && echo true || echo false)" >> "$GITHUB_OUTPUT" + + # See the note on the equivalent step in reusable-unit.yml: no lock file is + # committed, so the cache key must be rotated on a schedule. + - name: Determine the weekly Composer cache suffix + id: composer-cache-suffix + run: echo "value=$(date -u +%Y-%W)" >> "$GITHUB_OUTPUT" + + - name: Set up PHP environment + if: steps.check_composer_file.outputs.files_exists == 'true' + uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # v2 + with: + php-version: 'latest' + coverage: 'none' + env: + COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Install Composer dependencies & cache dependencies + if: steps.check_composer_file.outputs.files_exists == 'true' + uses: "ramsey/composer-install@65e4f84970763564f46a70b8a54b90d033b3bdda" # 4.0.0 + with: + custom-cache-suffix: ${{ steps.composer-cache-suffix.outputs.value }} + env: + COMPOSER_ROOT_VERSION: dev-${{ github.event.repository.default_branch }} + + # The ruleset, the pinned linter version and the invocation all live in + # wp-cli-tests, so that contributors can run the identical check locally + # with `composer lint-gherkin`. It is a no-op in a package that has no + # feature files. - name: Run linter - # Pinned: unpinned `npx` resolves and executes the newest publish at run - # time, and gherkin-lint has not been released since 2023. - run: npx --yes gherkin-lint@4.2.4 -c "$RUNNER_TEMP/.gherkin-lintrc" + if: steps.check_composer_file.outputs.files_exists == 'true' + run: composer lint-gherkin lint-spellcheck: name: Spell check diff --git a/AGENTS.md b/AGENTS.md index 1ff84f6..908c63d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -13,9 +13,27 @@ When contributing to this package, please adhere to the following guidelines: ### Building and running -Before submitting any changes, it is crucial to validate them by running the full suite of static code analysis and tests. To run the full suite of checks, execute the following command: `composer test`. +Run the narrowest check that covers your change: -This single command ensures that your changes meet all the quality gates of the project. While you can run the individual steps separately, it is highly recommended to use this single command to ensure a comprehensive validation. +| You changed | Run | +| --- | --- | +| Any PHP file | `composer phpcs -- ` and `composer phpstan` | +| Logic with unit test coverage | `composer phpunit -- --filter ` | +| One feature file | `composer behat -- features/.feature` | +| One scenario | `composer behat -- features/.feature:` | + +After a failure, `composer behat-rerun` re-runs only the scenarios that failed, and `composer behat -- --stop-on-failure` bails out at the first one instead of working through the rest. + +`composer test` runs every suite, the whole Behat suite included. In most packages that means installing WordPress from scratch once per scenario, which takes tens of minutes and needs `jq`, a MySQL or MariaDB client with a prepared test database, and network access to WordPress.org. Run it before opening a pull request when you have touched something cross-cutting. Do not run it to check a two-line change. + +Set these first, so the tools report problems compactly instead of drawing progress bars and ANSI color into output you are going to read back: + +```bash +export NO_COLOR=1 +export WP_CLI_TEST_QUIET=1 +``` + +Note that a green `composer test` is not the same as a green CI. `actionlint` and `typos` also run on every pull request and are not part of it. ### Useful Composer Commands @@ -24,6 +42,7 @@ The project uses Composer to manage dependencies and run scripts. The following * `composer install`: Install dependencies. * `composer test`: Run the full test suite, including linting, code style checks, static analysis, and unit/behavior tests. * `composer lint`: Check for syntax errors. +* `composer lint-gherkin`: Check the Behat feature files for style violations. * `composer phpcs`: Check for code style violations. * `composer phpcbf`: Automatically fix code style violations. * `composer phpstan`: Run static analysis.