632ab002ed
Adopt ADR 0004: stop chasing a single global coverage number and measure what matters instead. - Omit the genuinely-interactive `cli/init.py` shell (read_tty_line prompt loops) alongside the existing `cli/tui.py`, with a rationale comment in .coveragerc. Subprocess/backend orchestration is NOT omitted — it stays visible and is scored via the integration suite. - scripts/coverage.sh runs unit + integration under one coverage measurement (the policy's yardstick) and can report the critical security/logic core held to the >=90% target. - scripts/diff_coverage.py is a stdlib-only gate (no diff-cover dep): new/changed executable lines must be >=90% covered. This is the enforced regression guard; the global number is informational. - CI gains a `coverage` job: combined report + the diff-coverage gate. - Unit-test `cli/__init__.py` dispatch/exit-code mapping (it's logic, not I/O, so it earns tests rather than an omit). Combined unit+integration coverage now reports 83% global / 87% across the critical modules; per-module ratcheting toward 90% is the ongoing work this policy frames. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NkwFXLFff9PYPy4wgVBJp9
102 lines
3.1 KiB
YAML
102 lines
3.1 KiB
YAML
# Run the project's test suite on every PR push and on push to main.
|
|
#
|
|
# The suite uses stdlib `unittest` discovery — no external Python
|
|
# dependencies are required to execute it. Tests are split by directory:
|
|
#
|
|
# tests/unit/ — pure unit tests; always run
|
|
# tests/integration/ — need a reachable Docker daemon; skip cleanly
|
|
# (via tests/_docker.py:skip_unless_docker) when
|
|
# Docker isn't available on the runner
|
|
# tests/canaries/ — upstream regression canaries; run on a separate
|
|
# schedule (see canaries.yml), not here
|
|
#
|
|
# This workflow assumes the Gitea Actions runner exposes the host Docker
|
|
# socket to the job container so `docker` commands inside the job can
|
|
# reach the daemon. If that's not yet configured on the runner the
|
|
# integration tests will skip rather than fail.
|
|
|
|
name: test
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- main
|
|
paths:
|
|
- '**.py'
|
|
pull_request:
|
|
paths:
|
|
- '**.py'
|
|
|
|
jobs:
|
|
unit:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version: "3.12"
|
|
|
|
- name: Install dev requirements
|
|
run: python3 -m pip install -r requirements-dev.txt
|
|
|
|
- name: Run unit tests
|
|
run: python3 -m coverage run -m unittest discover -t . -s tests/unit -v
|
|
|
|
- name: Report unit coverage
|
|
run: python3 -m coverage report -m
|
|
|
|
integration:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version: "3.12"
|
|
|
|
- name: Show environment
|
|
run: |
|
|
python3 --version
|
|
if command -v docker >/dev/null 2>&1; then
|
|
docker version || true
|
|
else
|
|
echo "docker not on PATH — integration tests will skip"
|
|
fi
|
|
|
|
- name: Run integration tests
|
|
run: python3 -m unittest discover -t . -s tests/integration -v
|
|
|
|
# Combined unit+integration coverage + the diff-coverage gate.
|
|
# See docs/decisions/0004-coverage-policy.md. The hard gate is diff
|
|
# coverage (new/changed lines >= 90%); the combined + critical reports
|
|
# are informational and degrade gracefully when the runner has no
|
|
# Docker (integration tests skip, those modules just read lower).
|
|
coverage:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version: "3.12"
|
|
|
|
- name: Install dev requirements
|
|
run: python3 -m pip install -r requirements-dev.txt
|
|
|
|
- name: Combined coverage (unit + integration)
|
|
run: PYTHON=python3 bash scripts/coverage.sh critical
|
|
|
|
- name: Diff-coverage gate (changed lines >= 90%)
|
|
run: |
|
|
git fetch --no-tags origin main:refs/remotes/origin/main
|
|
python3 scripts/diff_coverage.py --base origin/main --min 90
|