mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
- .githooks/pre-push + scripts/pre-push-gate.mjs --hook: gate:small runs by default for issue/* branches with an executable diff; C/D-only diffs and non-issue refs are skipped, HP_PREPUSH_GATE=0 turns it off, =1 forces it. A non-HEAD push with an executable diff is rejected (the gate checks the working tree). The gate runs with every GIT_* variable removed: git gives hooks GIT_DIR (and GIT_CONFIG_PARAMETERS with the pusher's -c), and unit tests that `git init` temporary repositories otherwise write into the real one — seen on the first live run. The manual #343 mode is unchanged. - scripts/sandbox-bootstrap.sh: idempotent worktree / deps / chromium (npm @sparticuz/chromium@152.0.0 + Playwright shims) / bundle / check steps, no owner paths or credentials. - scripts/test-chunk.mjs, npm run test:chunk -- N/M: round-robin over test/*.test.mjs sorted by code point. - Tests, seven mutants, docs/DEVELOPMENT.md «Локальный контур за 5 минут», docs/TESTING.md. package.json changed → bundle rebuilt (fingerprint input). Issue: #633 User-Visible: no
105 lines
4.4 KiB
Bash
Executable File
105 lines
4.4 KiB
Bash
Executable File
#!/bin/sh
|
|
set -eu
|
|
|
|
# PROCESS.md 10.1: the blocking process gate lives here, because commits go
|
|
# straight to dev without pull requests and GitHub blocks nothing on its side.
|
|
# CI still runs the same script (10.3), but by then the code is already in dev —
|
|
# that catch-up pass reports, it does not prevent.
|
|
#
|
|
# Git feeds one line per ref on stdin:
|
|
# <local ref> <local sha> <remote ref> <remote sha>
|
|
|
|
repo_root=$(git rev-parse --show-toplevel)
|
|
gate="$repo_root/scripts/process-gate.mjs"
|
|
zero=$(printf '%040d' 0)
|
|
|
|
# The gate reasons about commits. A repository without it — an old checkout, a
|
|
# bisect, a worktree from before the script existed — must still be pushable.
|
|
if [ ! -f "$gate" ]; then
|
|
exit 0
|
|
fi
|
|
|
|
# Reading issue status needs gh, and a hook that cannot work on a train is a
|
|
# hook people disable. Offline the checks that need no network still run, and the
|
|
# strict pass happens in CI, where gh is always present.
|
|
issues_flag=""
|
|
if command -v gh >/dev/null 2>&1 && gh auth status >/dev/null 2>&1; then
|
|
issues_flag="--issues"
|
|
else
|
|
echo "process-gate: gh недоступен, проверка статуса issue пропущена — её выполнит CI" >&2
|
|
fi
|
|
|
|
status=0
|
|
gate_status=0
|
|
|
|
# Строки git читаются один раз: их нужно и локальному набору, и процессному гейту.
|
|
refs=$(cat)
|
|
|
|
while read -r local_ref local_sha remote_ref remote_sha; do
|
|
# An empty line (nothing on stdin) and deleting a remote branch push nothing to examine.
|
|
if [ -z "$local_sha" ] || [ "$local_sha" = "$zero" ]; then
|
|
continue
|
|
fi
|
|
|
|
# Tags carry no process state of their own: the commit they point at was
|
|
# already checked when it was pushed.
|
|
case "$local_ref" in
|
|
refs/tags/*) continue ;;
|
|
esac
|
|
|
|
if [ "$remote_sha" = "$zero" ]; then
|
|
# A branch that does not exist on the remote yet. Everything it adds on top
|
|
# of dev is new, so that is the range — not the whole history, which would
|
|
# drag in every violation committed before the gate existed.
|
|
base=$(git merge-base "$local_sha" refs/remotes/origin/dev 2>/dev/null || true)
|
|
if [ -z "$base" ]; then
|
|
echo "process-gate: не нашёл общего предка с origin/dev, проверяю последние 20 коммитов" >&2
|
|
base="$local_sha~20"
|
|
fi
|
|
else
|
|
base="$remote_sha"
|
|
fi
|
|
|
|
echo "process-gate: $local_ref, диапазон ${base}..${local_sha}" >&2
|
|
# shellcheck disable=SC2086
|
|
if ! node "$gate" --range "${base}..${local_sha}" --target-ref "$remote_ref" $issues_flag >&2; then
|
|
status=1
|
|
fi
|
|
done <<EOF
|
|
$refs
|
|
EOF
|
|
|
|
# Локальный набор gate:small (#633, прежде opt-in #343) — после процессного
|
|
# гейта: тот отвечает за секунды, а набор идёт минуты; прогоняются оба, чтобы
|
|
# автор узнал обо всех провалах одним кругом. По умолчанию включён для
|
|
# веток issue/* с исполняемым диффом; дифф только класса C/D (документы ревью,
|
|
# changelog, бандл) и ветки вне issue/* его не запускают. Выключение — явное:
|
|
# HP_PREPUSH_GATE=0; HP_PREPUSH_GATE=1 — прогнать для любой ветки. Документация:
|
|
# docs/TESTING.md, docs/DEVELOPMENT.md «Локальный контур за 5 минут».
|
|
if [ -f "$repo_root/scripts/pre-push-gate.mjs" ]; then
|
|
if ! printf '%s\n' "$refs" | node "$repo_root/scripts/pre-push-gate.mjs" --hook >&2; then
|
|
gate_status=1
|
|
fi
|
|
fi
|
|
|
|
if [ "$status" -ne 0 ]; then
|
|
cat >&2 <<'MSG'
|
|
|
|
Push остановлен: нарушен процесс (PROCESS.md §10.2).
|
|
|
|
Починить надо причину, а не симптом. Если нарушение уже опубликовано, его
|
|
исправляет следующий коммит плюс issue с меткой `process` — не force-push
|
|
(§12, правило 17).
|
|
|
|
Обойти проверку можно через `git push --no-verify`, и тогда то же самое найдёт
|
|
job `process-gate` в Validate — уже после того, как код окажется в dev.
|
|
MSG
|
|
fi
|
|
|
|
if [ "$gate_status" -ne 0 ]; then
|
|
echo "Push остановлен: красный локальный набор gate:small (см. вывод выше)." >&2
|
|
exit 1
|
|
fi
|
|
|
|
exit "$status"
|