#!/bin/bash

# Git exports GIT_DIR and friends to its hooks, and everything this script runs
# inherits them. The test suite shells out to `git init` and `git config`
# against temporary fixture repos passing only a working directory, which an
# ambient GIT_DIR overrides, so those writes land in the pushing developer's own
# repository instead: core.bare=true, which breaks every worktree of it, and a
# fixture user.name/user.email, which silently reattributes their next commit.
# Roughly ninety unit tests fail in the process, so the gate also reports a
# failure that has nothing to do with the change being pushed.
#
# This has to happen before the rev-parse below, which needs a working tree
# GIT_DIR alone does not supply -- from a linked worktree it failed outright,
# leaving ROOT_DIR empty and the `cd` a silent no-op.
unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE GIT_COMMON_DIR GIT_OBJECT_DIRECTORY GIT_PREFIX

ROOT_DIR=$(git rev-parse --show-toplevel) || exit 1
cd "$ROOT_DIR" || exit 1

echo "Running lint..."
if ! make lint; then
  echo "Linting failed. Please fix the issues before pushing."
  exit 1
fi

echo "Running security scan..."
if ! make security-scan; then
  echo "Security scan failed. Please fix the issues before pushing."
  exit 1
fi

# Same target, and therefore the same COVERAGE_MIN threshold, that CI's unit
# job runs. This previously re-implemented the gate here: `make coverage-json`
# followed by a hand-rolled `bc` comparison against a literal 90, reading the
# report with a bare `python` resolved from PATH rather than from uv.lock. That
# left two thresholds to keep in step and a third interpreter deciding whether
# a push was allowed.
echo "Running unit tests with coverage check..."
if ! make test-unit-cov; then
  echo "Unit tests or the coverage threshold failed. Please fix the issues before pushing."
  exit 1
fi

# The integration and functional tiers used to run here too, which put roughly
# twenty minutes between deciding to push and the push happening. A gate that
# slow gets worked around rather than waited for, and it duplicates jobs CI runs
# on every pull request anyway -- the value it added over CI was catching a
# failure a few minutes earlier, at the cost of making every push a coffee break.
#
# What stays is what is both fast and local-only in value: lint, the security
# scan, and kanon's own unit tests with the coverage gate. The vendored repo
# tree's tests are excluded for the same reason CI gates them -- they cover code
# this push almost certainly did not touch.
#
# Run `make test-integration` and `make test-functional` locally before opening a
# pull request if a change touches subprocess or filesystem behaviour. CI runs
# them on the pull request whenever the change is classified as touching code --
# not unconditionally, so a change the classifier reads as inert runs them in
# neither place.
echo "All local gates passed (lint, security scan, first-party unit tests + coverage)."
echo "Integration, functional and scenario tiers run in CI on this branch's pull request."
exit 0
