utils/repo_contract/templates/python.sh
Krzysztof kuhy Rudnicki 6c71d531bb repo contract + coverage_gaps gates, test_changed, dependency bumps
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-04 16:27:28 +02:00

51 lines
1.8 KiB
Bash
Executable File

#!/bin/bash
# ============================================================================
# Run only the tests related to files changed vs HEAD (staged, unstaged and
# untracked). Quiet: failures plus a one-line summary. Falls back to the full
# suite when a change cannot be mapped to tests. Generated by repo_contract.
# ============================================================================
set -euo pipefail
cd "$(git rev-parse --show-toplevel)"
CHANGED=()
while IFS= read -r f; do
[[ -n "$f" && -e "$f" ]] && CHANGED+=("$f")
done < <({ git diff --name-only HEAD 2>/dev/null || true; git ls-files --others --exclude-standard; } | sort -u)
pytest_run() {
if [[ -f uv.lock ]]; then uv run pytest "$@"
elif [[ -f poetry.lock ]]; then poetry run pytest "$@"
else python3 -m pytest "$@"; fi
}
if grep -qs testmon pyproject.toml requirements*.txt; then
pytest_run --testmon -q --tb=short; exit $?
fi
full=0
tests=()
for f in "${CHANGED[@]}"; do
case "$f" in
*/conftest.py | conftest.py | pyproject.toml | requirements*.txt | pytest.ini | setup.cfg) full=1 ;;
*.py)
base="$(basename "$f" .py)"
if [[ "$base" == test_* || "$base" == *_test ]]; then
tests+=("$f")
else
while IFS= read -r t; do tests+=("$t"); done \
< <(git ls-files "*test_${base}.py" "*${base}_test.py")
fi
;;
esac
done
if [[ $full -eq 0 && ${#CHANGED[@]} -eq 0 ]]; then echo "no changes vs HEAD: nothing to test"; exit 0; fi
if [[ $full -eq 0 && ${#tests[@]} -gt 0 ]]; then pytest_run -q --tb=short "${tests[@]}"; exit $?; fi
if [[ $full -eq 0 ]] && ! printf '%s\n' "${CHANGED[@]}" | grep -q '\.py$'; then
echo "no python changes: nothing to test"; exit 0
fi
echo "no mapped tests: running full suite"
pytest_run -q --tb=short