diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 0000000..6589ba9 --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,32 @@ +#!/bin/sh +# Format and lint staged files only. Skip in an emergency: git commit --no-verify +root=$(git rev-parse --show-toplevel) || exit 1 +cd "$root" || exit 1 + +staged=$(mktemp) || exit 1 +trap 'rm -f "$staged" "$staged.lint"' EXIT + +git diff --cached --name-only --diff-filter=ACMR -z -- \ + '*.ts' '*.tsx' '*.js' '*.json' '*.scss' '*.css' '*.md' >"$staged" || exit 1 +[ -s "$staged" ] || exit 0 + +# Re-staging a partially staged file would commit its unstaged changes too. +partial=0 +while IFS= read -r file; do + if ! git diff --quiet -- "$file"; then + echo "pre-commit: $file has unstaged changes; stage or stash them first." >&2 + partial=1 + fi +done <"$staged.lint" +if [ -s "$staged.lint" ]; then + xargs -0 pnpm exec eslint --fix --no-warn-ignored <"$staged.lint" || exit 1 +fi + +xargs -0 git add -- <"$staged" diff --git a/README.md b/README.md index 8fbc41a..db8e6ef 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,11 @@ store's settings don't pin a release (`theme.twilight.version`). | `pnpm test` | Run the test suite (Vitest) | | `pnpm check:manifest` | Validate `twilight.json` | +## Git hook + +`pnpm install` sets `core.hooksPath` to `.githooks`; the pre-commit hook runs Prettier and ESLint (`--fix`) on staged files only, re-stages them, and refuses the commit on remaining lint errors. +In an emergency, skip it with `git commit --no-verify`. + ## Deployment Salla builds and publishes your theme on its own infrastructure — push to your diff --git a/package.json b/package.json index 02d4ddf..fff8f01 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,8 @@ "test:coverage": "vitest run --coverage", "lint": "eslint .", "format:check": "prettier --check .", - "knip": "knip" + "knip": "knip", + "prepare": "node scripts/install-hooks.mjs" }, "dependencies": { "@salla.sa/twilight-components-react": "^3.0.2", diff --git a/scripts/install-hooks.mjs b/scripts/install-hooks.mjs new file mode 100644 index 0000000..87c3522 --- /dev/null +++ b/scripts/install-hooks.mjs @@ -0,0 +1,7 @@ +import { existsSync } from 'node:fs'; +import { spawnSync } from 'node:child_process'; + +// Skip quietly outside a git checkout (CI tarballs, published packages). +if (existsSync('.git')) { + spawnSync('git', ['config', 'core.hooksPath', '.githooks'], { stdio: 'ignore' }); +}