mirror of
https://github.com/kuhyx/WUT_Computer_Science.git
synced 2026-11-10 19:27:10 +01:00
repo contract: CLAUDE.md commands, test_changed, CI gate; Makefile cover hook, ignore coverage output
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
7739d33532
commit
dadc2b3e6f
25
.github/workflows/repo-contract.yml
vendored
Normal file
25
.github/workflows/repo-contract.yml
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
name: repo-contract
|
||||||
|
|
||||||
|
# The local pre-commit hook can be skipped (a fresh clone has no hooks), so the
|
||||||
|
# contract is enforced on push too. Mirrors md-naming.yml.
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
pull_request:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
repo-contract:
|
||||||
|
name: repo contract
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Check out the shared gate
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: kuhyx/utils
|
||||||
|
path: .utils
|
||||||
|
|
||||||
|
- name: Enforce the repo contract
|
||||||
|
run: bash .utils/scripts/check_repo_contract.sh
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
@ -489,3 +489,7 @@ gates/runnability-ci.tsv
|
|||||||
|
|
||||||
# Per-course virtualenvs created by ./run.sh run.
|
# Per-course virtualenvs created by ./run.sh run.
|
||||||
.venv/
|
.venv/
|
||||||
|
|
||||||
|
# test coverage output
|
||||||
|
.coverage
|
||||||
|
coverage.xml
|
||||||
|
|||||||
@ -67,6 +67,12 @@ repos:
|
|||||||
|
|
||||||
- repo: local
|
- repo: local
|
||||||
hooks:
|
hooks:
|
||||||
|
- id: repo-contract
|
||||||
|
name: repo contract (CLAUDE.md Commands + test_changed)
|
||||||
|
entry: scripts/check_repo_contract.sh
|
||||||
|
language: system
|
||||||
|
pass_filenames: false
|
||||||
|
files: ^(CLAUDE\.md|AGENTS\.md|scripts/test_changed\.sh)$
|
||||||
# Coursework deliverables are allowed under the two course trees;
|
# Coursework deliverables are allowed under the two course trees;
|
||||||
# compiled output is allowed nowhere. See .binary-allowlist.
|
# compiled output is allowed nowhere. See .binary-allowlist.
|
||||||
- id: no-binaries
|
- id: no-binaries
|
||||||
|
|||||||
@ -155,3 +155,12 @@ applies.
|
|||||||
| `.binary-allowlist` | Path-scoped: deliverables allowed under the two course trees, compiled output allowed nowhere. |
|
| `.binary-allowlist` | Path-scoped: deliverables allowed under the two course trees, compiled output allowed nowhere. |
|
||||||
| `DOCS-runnability.md` | Per-course run status, recorded separately for `local` and `ci`. |
|
| `DOCS-runnability.md` | Per-course run status, recorded separately for `local` and `ci`. |
|
||||||
| `TODO-*.md` | Open decisions. Each carries the removal marker and is deleted when the work lands. |
|
| `TODO-*.md` | Open decisions. Each carries the removal marker and is deleted when the work lands. |
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
- run: n/a: coursework archive; per course use `./run.sh run <dir>`
|
||||||
|
- test: `scripts/test_suites.sh`
|
||||||
|
- test-changed: `scripts/test_changed.sh`
|
||||||
|
- lint: `ruff check .`
|
||||||
|
- coverage: `COVERAGE=1 scripts/test_suites.sh`
|
||||||
|
- coverage-gaps: `coverage-gaps coverage.xml`
|
||||||
|
|||||||
5
Makefile
Normal file
5
Makefile
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# finish gate hook: the root-level pytest cannot collect the ECRYPT sieve suite (relative CSVs), so
|
||||||
|
# the shared gate calls this target instead (see scripts/test_suites.sh).
|
||||||
|
.PHONY: cover
|
||||||
|
cover:
|
||||||
|
COVERAGE=1 scripts/test_suites.sh
|
||||||
26
scripts/check_repo_contract.sh
Executable file
26
scripts/check_repo_contract.sh
Executable file
@ -0,0 +1,26 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Fail if this repo breaks the shared repo contract.
|
||||||
|
#
|
||||||
|
# Thin delegate to the shared gate in ~/src/utils, which owns the contract
|
||||||
|
# text. Copy this file to scripts/check_repo_contract.sh in a repo; never copy
|
||||||
|
# the shared gate itself, or the shim would exec itself forever.
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
readonly SHARED_GATE="${UTILS_ROOT:-$HOME/src/utils}/scripts/check_repo_contract.sh"
|
||||||
|
|
||||||
|
main() {
|
||||||
|
if [[ ! -x "$SHARED_GATE" ]]; then
|
||||||
|
echo "Error: shared repo-contract gate not found at $SHARED_GATE" >&2
|
||||||
|
echo " Clone github.com/kuhyx/utils to ~/src/utils, or set" >&2
|
||||||
|
echo " UTILS_ROOT to where it lives." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec bash "$SHARED_GATE" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
32
scripts/test_changed.sh
Executable file
32
scripts/test_changed.sh
Executable file
@ -0,0 +1,32 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Run only the pytest suites whose directory has changes vs HEAD (staged,
|
||||||
|
# unstaged and untracked). Quiet: failures plus a one-line summary per suite.
|
||||||
|
# Changes to shared config (pyproject.toml, this repo's test scripts) run all
|
||||||
|
# suites; changes outside any suite run nothing.
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="$(git rev-parse --show-toplevel)"
|
||||||
|
readonly ROOT
|
||||||
|
readonly SUITES=(Programming/ECOTE Programming/ECRYPT_PROJECT/sieve)
|
||||||
|
|
||||||
|
changed="$(cd "$ROOT" && { git diff --name-only HEAD 2>/dev/null || true; git ls-files --others --exclude-standard; } | sort -u)"
|
||||||
|
selected=()
|
||||||
|
all=0
|
||||||
|
for s in "${SUITES[@]}"; do
|
||||||
|
grep -q "^${s}/" <<<"$changed" && selected+=("$s")
|
||||||
|
done
|
||||||
|
grep -Eq '^(pyproject\.toml|scripts/test_suites\.sh|scripts/test_changed\.sh)$' <<<"$changed" && all=1
|
||||||
|
|
||||||
|
if [[ $all -eq 1 ]]; then
|
||||||
|
echo "shared test config changed: running all suites"
|
||||||
|
exec "$ROOT/scripts/test_suites.sh"
|
||||||
|
fi
|
||||||
|
if [[ ${#selected[@]} -eq 0 ]]; then
|
||||||
|
echo "no changes in a pytest suite: nothing to test"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
SUITE_DIRS="${selected[*]}" exec "$ROOT/scripts/test_suites.sh"
|
||||||
40
scripts/test_suites.sh
Executable file
40
scripts/test_suites.sh
Executable file
@ -0,0 +1,40 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Run the pytest suites that exist in this archive, each from its own directory
|
||||||
|
# (ECRYPT sieve reads its reference CSVs by relative path, so a repo-root
|
||||||
|
# `pytest` cannot collect it). Extra args are passed to every pytest run.
|
||||||
|
# Usage: scripts/test_suites.sh [pytest args]
|
||||||
|
# COVERAGE=1 scripts/test_suites.sh # writes coverage.xml at repo root
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="$(git rev-parse --show-toplevel)"
|
||||||
|
readonly ROOT
|
||||||
|
readonly SUITES=(Programming/ECOTE Programming/ECRYPT_PROJECT/sieve)
|
||||||
|
|
||||||
|
run_suites() {
|
||||||
|
local -a suites=("$@") extra=()
|
||||||
|
[[ ${#suites[@]} -eq 0 ]] && suites=("${SUITES[@]}")
|
||||||
|
if [[ "${COVERAGE:-0}" == 1 ]]; then
|
||||||
|
export COVERAGE_FILE="$ROOT/.coverage"
|
||||||
|
rm -f "$COVERAGE_FILE" "$ROOT/coverage.xml"
|
||||||
|
fi
|
||||||
|
local rc=0 s
|
||||||
|
for s in "${suites[@]}"; do
|
||||||
|
if [[ "${COVERAGE:-0}" == 1 ]]; then
|
||||||
|
extra=(--cov="$ROOT/$s" --cov-branch --cov-append --cov-config="$ROOT/pyproject.toml")
|
||||||
|
fi
|
||||||
|
(cd "$ROOT/$s" && python3 -m pytest -q --tb=short "${extra[@]}" "${PYTEST_ARGS[@]}") || rc=$?
|
||||||
|
done
|
||||||
|
if [[ "${COVERAGE:-0}" == 1 ]]; then
|
||||||
|
(cd "$ROOT" && python3 -m coverage xml -o coverage.xml --rcfile=pyproject.toml >/dev/null)
|
||||||
|
fi
|
||||||
|
return "$rc"
|
||||||
|
}
|
||||||
|
|
||||||
|
PYTEST_ARGS=("$@")
|
||||||
|
[[ -n "${SUITE_DIRS:-}" ]] && read -r -a SELECTED <<<"$SUITE_DIRS" || SELECTED=()
|
||||||
|
run_suites "${SELECTED[@]}"
|
||||||
|
exit $?
|
||||||
Loading…
Reference in New Issue
Block a user