---
title: Quality gates
---

This repository's PHP gate is `composer test`. JavaScript CI runs `npm run lint:js` and `npm run build`. Commit hooks run a narrower version of the same tools.

## PHP

`composer test` runs `lint`, then `phpunit`. `lint` is `php-lint`, `phpcs`, `fixer:test`, and `phpstan`.

<!-- wp:docspress/terminal-session {"title":"Every PHP gate, then the unit suite","shell":"bash","prompt":"$","command":"composer test","output":""} /-->

<!-- wp:docspress/fields {"title":"PHP tools","description":"From composer.json scripts-descriptions, phpstan.neon, phpcs.xml.dist, and phpunit.xml.","fields":[{"name":"php-lint","type":"string","required":false,"defaultValue":"","description":"Syntax lint only (parallel-lint). Excludes vendor, wordpress, node_modules, blocks/node_modules, build, blocks/build, and overlays.","values":"","deprecated":false},{"name":"phpcs","type":"string","required":false,"defaultValue":"","description":"Linchpin coding standards with project overrides. Scans plugin-scaffold.php, uninstall.php, includes, tests, and dev. Excludes overlays.","values":"","deprecated":false},{"name":"phpstan","type":"string","required":false,"defaultValue":"","description":"Level 5 with szepeviktor/phpstan-wordpress. Paths: plugin-scaffold.php, uninstall.php, includes. Excludes overlays.","values":"","deprecated":false},{"name":"fixer:test","type":"string","required":false,"defaultValue":"","description":"php-cs-fixer dry-run. Rules are short array syntax; WordPress sniffs stay in PHPCS.","values":"","deprecated":false},{"name":"phpunit","type":"string","required":false,"defaultValue":"","description":"Unit suite. No database. tests/bootstrap.php defines ABSPATH and WPINC and does not load WordPress.","values":"","deprecated":false}],"searchable":true,"compact":false} /-->

The unit suite asserts that `Bootstrap` exists, that `Files::glob_recursive()` finds `Install.php`, and that `plugin_scaffold_version()` returns `PLUGIN_SCAFFOLD_VERSION`. The test bootstrap sets that constant to `0.1.0-tests` when it is not already defined.

`check-branch-cs` and `check-staged-cs` are the line-scoped PHPCS entry points `linchpin/actions` and the Husky pre-commit hook use.

CI: `.github/workflows/php.yml` calls `linchpin/actions` `php-checks.yml@v4` on PHP 8.3 with `run_phpstan: true` and `composer_scripts: fixer:test`. It skips `release-please--` branches.

## JavaScript

<!-- wp:docspress/terminal-session {"title":"JavaScript lint used in CI","shell":"bash","prompt":"$","command":"npm run lint:js","output":""} /-->

`.github/workflows/js.yml` runs `npm ci`, `npm run lint:js`, and `npm run build` on changes under `src/`, the root package manifests, `webpack.config.js`, `.nvmrc`, and the workflow file. It ignores `blocks/` and `overlays/` in `eslint.config.js`.

`npm run lint:css` exists in `package.json` but is not a job in `js.yml`.

## Git hooks

`package.json` `prepare` is `husky`.

- `.husky/pre-commit` runs `npx lint-staged --concurrent false`
- `.husky/commit-msg` runs commitlint with `@linchpinagency/commitlint-config`

lint-staged:

- JS/TS: `npx wp-scripts format`
- CSS/SCSS: `npx wp-scripts lint-style --fix`
- PHP: `scripts/phpcbf-staged.sh` then `scripts/phpcs-staged.sh`

`phpcbf-staged.sh` treats php-cs-fixer-style exit codes 1 and 2 as success so auto-fixes can be restaged. Only exit status 3 or higher fails the hook. `phpcs-staged.sh` calls `composer check-staged-cs` and drops the file list lint-staged appends.

## Other workflows on this repository

| Workflow | What it runs |
| --- | --- |
| `.github/workflows/plugin-check.yml` | `bash scripts/build.sh`, then Plugin Check on `./build/plugin-scaffold` |
| `.github/workflows/release-please.yml` | release-please on `main`, then Plugin Check, then attach `build/plugin-scaffold.zip` |
| `.github/workflows/wp-version-checker.yml` | Daily `linchpin/actions` WordPress version checker |
| `.github/workflows/sync-docs.yml` | Manual DocsPress dry-run to docs.linchpin.com |

Renovate extends `github>linchpin/renovatebot-config`.

<!-- wp:docspress/result {"status":"success","title":"Gates are green when","content":"<p><code>composer test</code> exits 0 and <code>npm run lint:js</code> plus <code>npm run build</code> exit 0. That is what the PHP and JavaScript workflows require.</p>","meta":"composer.json, js.yml"} /-->
