Skip to content

Git Hooks (Husky) ​

This repository uses Husky to run Git hooks from the root .husky/ directory. Hooks run automatically at specific points in the Git workflow to keep code style and commit messages consistent across the monorepo.

Hook scripts live in .husky/ (pre-commit, commit-msg).

Setup ​

Hooks are configured when you run at the repository root:

bash
npm install

The prepare script runs automatically and points Git at .husky/.

NOTE

Husky lives in the root package.json because hooks apply to the entire monorepo. Vue lint still uses zmscitizenview; frontend ESLint uses zmsadmin, zmsstatistic, zmscalldisplay, and zmsticketprinter; docs formatting uses docs/.

After cloning, run npm install once at the repo root (also in the root README). For doc changes, install docs dependencies once: cd docs && npm install.

Hooks ​

pre-commit ​

No-op placeholder. Git always runs pre-commit before commit-msg; the real checks are in commit-msg so the commit subject is validated before Vue/docs/ESLint/PHP.

commit-msg ​

All checks run in this hook, in fail-fast order:

  1. Commit message — subject line from the message file Git passes to this hook
  2. Vue code style — Prettier check in zmscitizenview (npm run lint)
  3. Docs formatting — Prettier check in docs/ (npm run format:check)
  4. Frontend ESLint — npm run lint in staged zmsadmin, zmsstatistic, zmscalldisplay, and zmsticketprinter JS (via zms-web when that container is running, otherwise on the host)
  5. PHP code style — PHP CodeSniffer (PSR-12) across PHP modules via the zms-web container
  6. PHP Mess Detector — PHPMD with root phpmd.rules.xml (complexity, size, unused) via zms-web — same as CI php-code-quality

Container detection

ESLint and the PHP checks detect your runtime automatically:

  • Podman — if a container named zms-web is running
  • Docker — fallback when Podman is unavailable
  • ESLint fallback — if no container is running, ESLint runs on the host
  • PHP skip — if no container is running (warning only, non-blocking)

Behavior

  • Commit message, Vue, docs, and ESLint checks block the commit on failure
  • ESLint runs only when JS, eslint.config.*, or package.json / package-lock.json is staged in those four modules
  • PHP checks (PHPCS + PHPMD) run only when a .php file or phpmd.rules.xml is staged and zms-web is up; JS-only files in PHP modules do not trigger phpcs/phpmd

See also Code formatting for manual PHPCS/Prettier commands.

Commit message format (step 1):

txt
type(PROJECT-123): commit message
type(PROJECT): commit message
type(PROJECT-1 PROJECT-2): commit message
type(PROJECT-1 PROJECT-2): type(PROJECT-3): commit message

The ticket number is optional — use PROJECT-123 or just PROJECT (uppercase). Multiple tickets/projects may be space-separated in one scope; multiple type(scope): prefixes may be chained before the summary.

Merge commits

Git’s default merge subjects (for example Merge branch 'main' into feature-branch) are allowed automatically so git merge can finish without renaming the message. You can still use a conventional subject if you prefer, for example chore(ZMS): merge main into feature-branch.

Full rules, types, projects, and examples: Commit message convention.

Troubleshooting ​

Vue lint fails ​

bash
cd zmscitizenview
npm run format

Then commit again.

Docs formatting fails ​

If Prettier reports issues under docs/:

bash
cd docs
npm run format

Install dependencies first if needed: cd docs && npm install.

Frontend ESLint fails ​

Fix the staged module (replace zmsadmin as needed):

bash
podman exec -it zms-web bash -lc "cd zmsadmin && npm run fix"

Or on the host: cd zmsadmin && npm run fix. Then commit again.

PHP CodeSniffer fails ​

The hook prints a fix command for your container engine:

bash
# Podman
podman exec -it zms-web bash -lc "./cli modules loop 'vendor/bin/phpcbf --standard=psr12 src/'"

# Docker
docker exec -it zms-web bash -lc "./cli modules loop 'vendor/bin/phpcbf --standard=psr12 src/'"

PHPMD fails ​

Re-run the same command CI uses (from the repo root inside zms-web):

bash
# Podman
podman exec -it zms-web bash -lc "./cli modules loop 'vendor/bin/phpmd src/ text ../phpmd.rules.xml'"

# Docker
docker exec -it zms-web bash -lc "./cli modules loop 'vendor/bin/phpmd src/ text ../phpmd.rules.xml'"

Thresholds and rules live in phpmd.rules.xml.

Container not detected ​

If you see a warning that zms-web is not running:

bash
podman ps | grep zms-web

Start the dev environment if needed (Devcontainer and Podman, Podman and Dev Containers). PHP checks are skipped when the container is down; the commit is not blocked for PHP alone.

Invalid commit message format ​

Common mistakes:

  • Missing project: feat: add feature
  • Lowercase project: feat(zms-123): add feature
  • Missing colon: feat(ZMS-123) add feature

Correct examples:

  • feat(ZMS-123): add feature
  • chore(ZMSKVR): clean up

Merge blocked by commit-msg ​

If git merge fails with “Invalid commit message format” and a subject like Merge branch 'main' into …, update .husky/commit-msg from the latest main or feature branch (merge subjects should be accepted). As a workaround, finish the merge with a conventional message:

bash
git commit -m "chore(ZMS): merge main into your-branch"

Bypassing hooks ​

In emergencies, use Git’s --no-verify flag:

bash
git commit --no-verify -m "feat(ZMS-123): urgent fix"

CAUTION

Use --no-verify only when necessary. Bypassing hooks can hurt code quality and affect other contributors.