This add-on installs a local code quality tool suite for Drupal projects and IDE usage, starting from Drupal.org GitLab CI template defaults. It provides DDEV commands and host shims so developers can run the same checks locally that GitLab CI runs on Drupal.org.
DDEV add-on that installs local code quality tooling based on Drupal.org GitLab CI template defaults (PHPStan, PHPCS, ESLint, Stylelint, Prettier, CSpell) for local CLI and IDE usage.
Tools covered:
- PHPStan
- PHPCS / PHPCBF
- ESLint
- Stylelint
- Prettier
- CSpell
- Composer validate
- php-parallel-lint (when installed)
# Install from GitHub (current)
ddev add-on get UltraBob/ddev-drupal-code-quality
# If/when published to the add-on registry:
# ddev add-on get ddev-drupal-code-quality
# Or, for local development
ddev add-on get /path/to/ddev-drupal-code-quality
ddev restartcommands/: DDEV web commands copied into project.ddev/commands.drupal-code-quality/: project-root configs and.ddevshims copied by the installer.dcq-install.sh: conflict-aware installer invoked byinstall.yaml.install.yaml: DDEV add-on install definition.
During installation, the add-on copies Drupal.org GitLab CI template default config files into the project root. If conflicts are detected, you can choose to back up and replace, skip, or abort. Skipping a config may diverge from the Drupal.org GitLab CI template defaults. The installer will prompt for:
- Accept recommended settings (default: no). Choosing yes applies the recommended defaults without further prompts.
- Conflict handling (default: skip unless you choose replace/abort).
- PHP tooling dependencies (install
drupal/core-devor runddev composer install). - PHPStan default level (keep GitLab CI template level 0 or choose a local level 0-10; recommend 3).
- Node toolchain install in the project root and package manager selection.
- Missing Drupal JS dependencies when a root
package.jsonexists. - Optional
.gitignoreupdate fordcq-reports/. - IDE settings (merge/overwrite/skip when templates are available). The installer runs in bash so it does not require host PHP.
Recommended settings apply these defaults without further prompts:
replace conflicts (with backups), install PHP dev tools, install JS deps in the
project root, set PHPStan level 3, merge IDE settings, and add dcq-reports/
to .gitignore. Non-interactive runs with no overrides apply the recommended
settings automatically.
If PHPStan/PHPCS/PHPCBF binaries are missing, the installer prompts to add
drupal/core-dev (or to run ddev composer install if it is already required).
It uses ddev composer require --with-all-dependencies to avoid lockfile
conflicts.
For CLI usage, prefer the DDEV commands:
ddev phpstan
ddev phpcs
ddev phpcbf
ddev eslint
ddev stylelint
ddev prettier
ddev cspell
ddev composer-validate
ddev checksHost shims are installed under .ddev/drupal-code-quality/tooling/bin. These are intended for
IDE tool paths or tools that require a local binary path:
./.ddev/drupal-code-quality/tooling/bin/phpstan
./.ddev/drupal-code-quality/tooling/bin/phpcs
./.ddev/drupal-code-quality/tooling/bin/eslint
./.ddev/drupal-code-quality/tooling/bin/stylelint
./.ddev/drupal-code-quality/tooling/bin/prettier
./.ddev/drupal-code-quality/tooling/bin/cspell
./.ddev/drupal-code-quality/tooling/bin/checksddev eslint-fix, ddev prettier-fix, and ddev stylelint-fix apply formatting changes directly, matching the behavior of their underlying tools (eslint --fix, prettier --write, stylelint --fix). All three commands support an optional --preview flag that builds a patch preview (saved to dcq-reports/), displays it, and prompts Apply these changes? [y/N] before applying. Use --preview when you want to review changes before committing them.
Starter settings live in .ddev/drupal-code-quality/ide-settings/vscode. During install, you can
choose to merge them into .vscode/settings.json and
.vscode/extensions.json, back up and overwrite, or skip and handle them
manually.
The template points PHP tooling at .ddev/drupal-code-quality/tooling/bin and JS tooling at local
node_modules. Override the paths if you prefer a different location.
- DDEV project with Drupal core in the configured docroot (default
web/). The installer records the docroot in.ddev/.dcq-docrootfor wrappers. - Composer dependencies installed (
ddev composer install). - Node toolchain for JS linting (npm or yarn; the installer selects based on
lockfiles and can create a root
package.jsonfrom Drupal core when missing).- If you use yarn, enable corepack in DDEV.
- Reports:
dcq-reports/is created at the project root when runningchecksor the*-fixcommands (logs + patch previews).- Add
dcq-reports/to.gitignoreif you do not want to track it.
- ESLint toolchain selection:
ESLINT_TOOLCHAIN=auto(default) prefers root toolchain when root configs exist.ESLINT_TOOLCHAIN=coreforces Drupal core JS toolchain.ESLINT_TOOLCHAIN=rootforces project root toolchain.
- ESLint config mode:
ESLINT_CONFIG_MODE=nearest(default) groups by nearest config file.ESLINT_CONFIG_MODE=fixedforces.eslintrc.passing.json.
- CSpell parity:
- Run
ddev exec php /mnt/ddev_config/drupal-code-quality/tooling/scripts/prepare-cspell.php -s .preparedonce and replace.cspell.jsonafter reviewing the diff. ddev cspellruns from the repo root (.) by default; scope is controlled by.cspell.jsonignorePaths. Narrow the scan by passing explicit paths..cspell-project-words.txtis created by the installer (empty) and updated byddev cspell-suggestwhen you accept suggested words.
- Run
- PHPStan baseline:
- Generate a baseline with
ddev phpstan --generate-baseline. - This writes
phpstan-baseline.neonat the project root; the wrapper will include it automatically when present. - Use a baseline to suppress known issues in legacy code or core defaults
(for example, the shipped
settings.phpfiles), then work it down over time. Avoid using it to hide new regressions.
- Generate a baseline with
- PHPStan config fallback:
- If no project
phpstan.neon*exists, the wrapper uses the GitLab template config shipped with the add-on.
- If no project
- PHPStan level:
- GitLab CI template defaults use level 0. The installer can set a local default level (0-10).
DCQ_INSTALL_MODE:replace,skip, orabortfor conflict handling.DCQ_NONINTERACTIVE=true: disable prompts; if no overrides are set, applies the recommended settings automatically.DCQ_PHPSTAN_LEVEL: setphpstan.neonlevel (0-10) without prompting.DCQ_INSTALL_DEPS:install/trueto auto-install missingdrupal/core-dev,skip/falseto skip, or unset to prompt when interactive.DCQ_INSTALL_NODE_DEPS:rootto install JS deps in the project root (creates a rootpackage.jsonfrom core if missing; name uses the DDEV project name, and prompts to add missing Drupal deps when a rootpackage.jsonalready exists),install/trueto auto-install in the project root,skip/falseto skip, or unset to prompt (default: install in the project root). The installer selects npm/yarn based on existing lockfiles.DCQ_INSTALL_GITIGNORE:add/trueto adddcq-reports/to.gitignorewithout prompting,skip/falseto skip, or unset to prompt when interactive.DCQ_INSTALL_IDE_SETTINGS:mergeto add missing VS Code settings and extension recommendations,overwriteto back up and replace,skipto handle manually, or unset to prompt.
Removing the add-on cleans up the .ddev payload (commands, shims, assets,
manifest, and dcq-install.sh); project-root configs remain in place
intentionally. Remove them manually if desired.
Contributed and maintained by @UltraBob