#!/bin/bash
# =============================================================================
# PRE-COMMIT HOOK — run-tests (2026-07-25)
# =============================================================================
# Distributed from pinky-workspace/core/hooks/ — do not edit in place. Declared in
# core/pre-commit/base.yaml (universal, `files: ^(src|tests)/`), NOT in the `python` extra.
#
# An earlier version of this header claimed the opposite ("extra `python` only … NOT in base.yaml —
# that one … would declare a pytest hook on studio/assets/infra/workspace, four repos with no test
# suite at all"). Both halves were false and the second one bit: **10 of the 13 repos carry a
# tests/ dir**, studio included — so the `[ -d tests ] || exit 0` guard below never fired for it,
# and every studio commit touching src/ or tests/ was blocked (2026-07-25). Keep this header in
# sync with base.yaml: a stale comment here is what justified the wrong placement in the first
# place (see core/rules/base/verify-diagnosis.md — a written cause is a hypothesis).
#
# Why this hook exists separately from generate-docs: until now the ONLY execution of the test suite
# at commit time was the one buried inside generate-docs to produce the coverage badge's data, and
# its failure printed a warning on stderr then returned 0 — a commit touching src/ with a broken
# suite passed pre-commit, the warning lost among ~20 other hooks' output. Separation of concerns:
# generate-docs does docs (non-blocking, cosmetic output), run-tests guards quality (blocking).
#
# The two runs stay INDEPENDENT rather than sharing coverage data through a file. Measured
# 2026-07-25: each suite takes 0-3s, so the double run costs ~3s at worst — far cheaper than the
# risk of an inter-hook artifact going silently stale. That exact coupling (trusting a pre-existing
# .coverage) is what froze pinky-connect's badge for six weeks; see the generate-docs header.
# =============================================================================

# Interpreter — resolved explicitly, never a bare `python`. Same ladder as generate-docs: the
# project venv first (the test suite needs the repo's own dependencies, which a system python3
# does not have), then the system fallbacks.
if [ -x .venv/bin/python ]; then PY=".venv/bin/python"                    # POSIX
elif [ -x .venv/Scripts/python.exe ]; then PY=".venv/Scripts/python.exe"  # Windows
elif command -v python3 > /dev/null 2>&1; then PY="python3"
elif command -v py > /dev/null 2>&1; then PY="py -3"
else
    echo "⚠ run-tests: aucun interpréteur Python (.venv / python3 / py) — tests non exécutés" >&2
    exit 0
fi

# Pas de suite de tests → rien à garder. Cible « template light » du chantier 0001 : un repo cloné
# sans tests ne doit pas voir ses commits bloqués par un hook qui n'a rien à exécuter.
[ -d tests ] || exit 0

# pytest indisponible → on ne bloque pas. Ce garde devient indispensable depuis que le hook est
# déclaré dans base.yaml (2026-07-25) et non plus dans le seul extra `python` : un repo qui a un
# dossier tests/ mais pas les extras dev verrait `$PY -m pytest` sortir non-zéro (« No module named
# pytest ») et se retrouverait avec TOUS ses commits bloqués. Même posture permissive que le
# fallback genbadge de generate-docs — un outil de dev absent est une machine mal équipée, pas un
# test qui échoue.
if ! $PY -c "import pytest" > /dev/null 2>&1; then
    echo "⚠ run-tests: pytest non installé — tests non exécutés" >&2
    exit 0
fi

# --no-cov : l'instrumentation coverage est le travail de generate-docs, pas le nôtre — ici on veut
# le verdict pass/fail le plus rapide possible.
# Pas de `-p no:cacheprovider` : les repos configurent déjà `cache_dir = ".cache/pytest"` en
# pyproject, donc rien ne salit l'arbre — et désactiver le plugin rend ce réglage inconnu, ce qui
# fait cracher un PytestConfigWarning à chaque commit (mesuré sur pinky-tools, 2026-07-25).
if ! $PY -m pytest -q --no-cov; then
    echo "" >&2
    echo "✖ run-tests: la suite de tests échoue — commit bloqué." >&2
    echo "  Corrige les tests, ou --no-verify si le WIP est délibéré." >&2
    exit 1
fi

exit 0
