From 3a51d07b9bf0b5886b7af9737b977ab0931b9edc Mon Sep 17 00:00:00 2001 From: Troy Chaplin Date: Fri, 18 Sep 2026 10:14:42 -0400 Subject: [PATCH 1/2] add lint enforcement to husky pre-commit and ci action --- .github/workflows/ci.yml | 9 ++---- .husky/pre-commit | 62 ++++++++++++++++++++-------------------- 2 files changed, 34 insertions(+), 37 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c586b1f..37d60c7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,12 +1,9 @@ name: CI on: - workflow_dispatch: - -# on: -# push: -# branches: [main] -# pull_request: + push: + branches: [main] + pull_request: jobs: php: diff --git a/.husky/pre-commit b/.husky/pre-commit index 5444066..c9463df 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,35 +1,35 @@ -# #!/usr/bin/env sh +#!/usr/bin/env sh -# # `printf` rather than `echo`: POSIX sh (dash, as on Linux/CI) does not -# # interpret \033 or \n in echo, so escapes would print literally. -# red() { -# printf '\033[0;31m%s\033[0m\n' "$1" -# } +# `printf` rather than `echo`: POSIX sh (dash, as on Linux/CI) does not +# interpret \033 or \n in echo, so escapes would print literally. +red() { + printf '\033[0;31m%s\033[0m\n' "$1" +} -# rule() { -# printf '\033[0;31m%s\033[0m\n' '--------------------------------------------------------------------------------' -# } +rule() { + printf '\033[0;31m%s\033[0m\n' '--------------------------------------------------------------------------------' +} -# # 1. Lint only staged files (CSS/JS/PHP) — fast, scoped to what's changing. -# printf '\n' -# red 'Linting staged files...' -# npx lint-staged --no-stash || { -# printf '\n' -# rule -# red 'Linting failed. Commit aborted.' -# rule -# printf '\n' -# # exit 1 -# } - -# # 2. PHPStan runs project-wide — it needs whole-codebase context, so it can't -# # be scoped to staged files like the linters above. -# red 'Running PHPStan...' -# composer phpstan || { -# printf '\n' -# rule -# red 'PHPStan failed. Commit aborted.' -# rule -# printf '\n' +# 1. Lint only staged files (CSS/JS/PHP) — fast, scoped to what's changing. +printf '\n' +red 'Linting staged files...' +npx lint-staged --no-stash || { + printf '\n' + rule + red 'Linting failed. Commit aborted.' + rule + printf '\n' # exit 1 -# } +} + +# 2. PHPStan runs project-wide — it needs whole-codebase context, so it can't +# be scoped to staged files like the linters above. +red 'Running PHPStan...' +composer phpstan || { + printf '\n' + rule + red 'PHPStan failed. Commit aborted.' + rule + printf '\n' + exit 1 +} From afb843574486a1f137a97b61030814d70d6f8147 Mon Sep 17 00:00:00 2001 From: Troy Chaplin Date: Fri, 18 Sep 2026 11:24:30 -0400 Subject: [PATCH 2/2] updated contrubutor doc to include refefence to husky pre-commit --- .husky/pre-commit | 2 +- CONTRIBUTING.md | 31 ++++++++++++++++++++++++++----- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index c9463df..290c320 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -19,7 +19,7 @@ npx lint-staged --no-stash || { red 'Linting failed. Commit aborted.' rule printf '\n' -# exit 1 + exit 1 } # 2. PHPStan runs project-wide — it needs whole-codebase context, so it can't diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d587e30..609208d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -34,8 +34,12 @@ Node version. `npm install` will refuse to run on an unsupported Node or npm ```bash nvm install && nvm use composer install && npm ci && npm run build +npx husky ``` +`npx husky` enables the [pre-commit hook](#quality-checks). You only need to +run it once per clone. + 3. **Activate the plugin:** Through WordPress admin or via WP-CLI: @@ -50,7 +54,9 @@ with the plugin mounted and debugging enabled. See the ### Quality checks -Before submitting a pull request: +The codebase is held to ESLint, Stylelint, PHPCS (WordPress Coding Standards) +and PHPStan (level 8). Before you open a pull request, run the full suite and +auto-fix what can be fixed: ```bash # Lint everything — JS, CSS, PHPCS, PHPStan @@ -60,9 +66,23 @@ npm run lint npm run format ``` -The pre-commit hook already runs `lint-staged` plus a project-wide PHPStan, so -a commit that goes through has passed most of this. CI runs the same checks -against PHP 8.1–8.4. +The same checks are enforced automatically: + +- **On commit:** the pre-commit hook lints your staged files with ESLint, + Stylelint and PHPCS, then runs PHPStan across the whole project, since it + needs the full codebase for context. If any check fails, the commit is + aborted. +- **In CI:** every pull request and every push to `main` runs PHPCS and PHPStan + against PHP 8.1–8.4, plus ESLint, Stylelint, a `package-lock.json` sync check + and the production build on the pinned Node version. + +If a rule is genuinely wrong for a specific line, suppress it for that line +only, name the rule, and give the reason, so reviewers can check it. The same +pattern works with `eslint-disable-next-line` and `stylelint-disable-next-line`: + +```php +// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- array key in a check definition, not a query arg. +``` There is no automated test suite yet. Please describe how you verified your change in the pull request's testing instructions. @@ -98,7 +118,8 @@ The following conventions must be followed for consistency and autoloading: ### Documentation standards Every class, method, and property needs a docblock with a summary line — PHPCS -runs the `WordPress-Docs` ruleset and the codebase currently passes clean. Use +runs the `WordPress-Docs` ruleset, so a missing one fails the pre-commit hook +and CI. Use explicit type hints on parameters and return values, and document array shapes with generics (e.g. `array`) so PHPStan can check them at level 8.