#!/bin/sh # ============================================================================= # tools/git-hooks/pre-commit.sh — нативная замена lefthook-движка # ============================================================================= # Зачем: lefthook 2.1.x виснет при `git commit` на этой Windows-машine # (путь с кириллицей + пробелом: "C:\моя\проекты\портал crm\Документация"). # Сами проверки отрабатывают и проходят, но движок lefthook не завершается # и плодит node-зомби (см. CHANGELOG / memory feedback_environment q.107+). # Заменено 23.05.2026 по решению заказчика «свой простой скрипт». # # Этот скрипт зеркалит pre-commit джобы lefthook.yml, но: # - вызывает инструменты напрямую (node , не npx → нет зомби-обёрток) # - НЕ модифицирует index (нет git add / git stash / --fix) → нет конфликта # за .git/index.lock с родительским git commit (корень зависаний lefthook) # - имеет явный exit-код, ничего не висит # # Источник истины КОНФИГУРАЦИИ проверок — lefthook.yml (для CI/Linux, где # lefthook работает штатно). Этот скрипт — локальная Windows-реализация. # # Bypass (как у lefthook): LEFTHOOK=0 git commit ... # ============================================================================= [ "$LEFTHOOK" = "0" ] && exit 0 ROOT="$(git rev-parse --show-toplevel)" cd "$ROOT" || exit 1 STAGED=$(git diff --cached --name-only --diff-filter=ACM) [ -z "$STAGED" ] && exit 0 FAIL=0 note() { printf '\n[pre-commit] %s\n' "$1"; } # 1. gitleaks — секреты / ПДн / токены в staged (§5.2). Нативный exe. note "gitleaks (secrets)" ./bin/gitleaks.exe protect --staged --config .gitleaks.toml --no-banner || { note "gitleaks FAILED"; FAIL=1; } # 2+3. markdownlint + cspell на staged .md (исключая вендоренные скилы). # Без --fix: pre-commit не модифицирует файлы. Авто-fix — `npm run lint:md:fix`. MD=$(printf '%s\n' "$STAGED" | grep -E '\.md$' | grep -vE '^\.claude/skills/(mermaid|ccpm|data-scientist|marketingskills)/') if [ -n "$MD" ]; then note "markdownlint" node node_modules/markdownlint-cli2/markdownlint-cli2-bin.mjs $MD || { note "markdownlint FAILED — запусти 'npm run lint:md:fix'"; FAIL=1; } note "cspell" node node_modules/cspell/bin.mjs --no-progress --no-summary --no-gitignore $MD || { note "cspell FAILED — добавь слово в cspell-words.txt или поправь"; FAIL=1; } fi # 4. Stylelint на staged .html (CSS в прототипах). HTML=$(printf '%s\n' "$STAGED" | grep -E '\.html$') if [ -n "$HTML" ]; then note "stylelint" node node_modules/stylelint/bin/stylelint.mjs $HTML || { note "stylelint FAILED"; FAIL=1; } fi # 5. Pint (--test, без авто-fix) на staged app/**/*.php. # NB: Larastan УБРАН из pre-commit 23.05.2026 — он анализирует весь проект через # phpstan-baseline.neon, который дрейфит от параллельных Claude-сессий и устаревшего # ide-helper (ImportLog @mixin и т.п.) → блокирует несвязанные коммиты сотнями # ignore.unmatched. Larastan остаётся в lefthook.yml (CI/Linux) + ручной `composer stan` # перед push. pint (форматирование, не baseline-зависим) остаётся. PHP=$(printf '%s\n' "$STAGED" | grep -E '^app/.*\.php$') if [ -n "$PHP" ]; then PHP_REL=$(printf '%s\n' "$PHP" | sed 's#^app/##') note "pint --test" ( cd app && php vendor/bin/pint --test $PHP_REL ) || { note "pint FAILED — запусти 'cd app && composer pint'"; FAIL=1; } fi # 7. squawk на staged *.sql (миграции PostgreSQL). SQL=$(printf '%s\n' "$STAGED" | grep -E '\.sql$') if [ -n "$SQL" ]; then note "squawk" ./bin/squawk.exe $SQL || { note "squawk FAILED"; FAIL=1; } fi # 8. ESLint на staged app/resources/js/**/*.{ts,vue}. VUE=$(printf '%s\n' "$STAGED" | grep -E '^app/resources/js/.*\.(ts|vue)$') if [ -n "$VUE" ]; then VUE_REL=$(printf '%s\n' "$VUE" | sed 's#^app/##') note "eslint" ( cd app && node node_modules/eslint/bin/eslint.js $VUE_REL ) || { note "eslint FAILED"; FAIL=1; } fi if [ "$FAIL" = "1" ]; then note "ОТКЛОНЕНО — проверки не пройдены (см. выше). Обход: LEFTHOOK=0 git commit ..." exit 1 fi note "OK — все проверки пройдены" exit 0