Repository navigation
141 lines (131 loc) · 5.68 KB
/
Copy pathci.yml
File metadata and controls
141 lines (131 loc) · 5.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
name: CI
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
jobs:
commit-message:
# The commits in this repository are authored solely by the repo owner.
# That rule is in CLAUDE.md and was still broken twice, so it is checked
# here rather than trusted.
#
# Scope is `origin/master..HEAD`, not `--all`. A whole-history grep counts
# trailers on the 200+ commits that are already published and are nobody's
# to rewrite; the meaningful question is only whether THIS branch adds
# one, and that is the number worth a red build.
#
# This checks the trailer form — a `Co-Authored-By:` line at the start of
# a line. A commit body that discusses the rule, or a CHANGELOG entry
# that credits a person, is not a violation and must not fail the build.
#
# A `commit-msg` hook is the stronger place for this (it fails before the
# commit exists rather than after), and one is configured in
# `.pre-commit-config.yaml`. This step is the backstop for the case the
# hook cannot cover: a contributor with no pre-commit installed, or a
# `--no-commit` push. Two mechanisms fail differently, which is the
# point — one rule enforced one way is a rule enforced once.
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
with:
# Full history, because the range check needs the merge base with
# origin/master, and `fetch-depth: 0` is what makes that base
# exist. A shallow clone has no origin/master to diff against and
# the range would silently be empty — a check that always passes
# is worse than no check, because it reads as enforcement.
fetch-depth: 0
- name: Reject a Co-Authored-By trailer on this branch
run: |
set -euo pipefail
git fetch --no-tags --depth=1 origin master || true
range=origin/master..HEAD
if ! git rev-parse --verify origin/master >/dev/null 2>&1; then
echo "::warning::origin/master unavailable; trailer check skipped"
exit 0
fi
offenders="$(
git log "$range" --format=%B \
| grep -inE '^[[:space:]]*co-authored-by[[:space:]]*:' || true
)"
if [ -n "$offenders" ]; then
echo "::error::Co-Authored-By trailer found in $range"
echo "$offenders"
echo "Remove the trailer and amend. See CLAUDE.md."
exit 1
fi
echo "no Co-Authored-By trailer in $range"
test:
runs-on: ubuntu-latest
permissions:
contents: read
# 2026-07-08: fail-fast on the first matrix failure instead of
# wasting runner minutes on the remaining Python versions when
# the suite is already red. Speed gain is per-run, not per-test.
strategy:
fail-fast: true
matrix:
python: ["3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
# Cache pip's download cache keyed on the lock-relevant
# surfaces of pyproject.toml. Skips the ~60-90s cold
# install on warm caches; the action also reuses the
# cache across matrix legs when the key matches.
cache: "pip"
cache-dependency-path: pyproject.toml
- name: Install dependencies
run: |
python -m pip install --upgrade pip
# xdist ships in the dev tree already; pin it explicitly so
# a future deps churn can't drop it without breaking CI.
# ``pytest-rerunfailures`` is used by Sprint 0 (coverage) on
# a single rare-flaky test under pytest-xdist on linux
# (thread-scheduling race in the approval-wait fixture);
# pin it for the same reason.
pip install -e ".[dev]" "pytest-xdist>=3.6" "pytest-rerunfailures>=14.0,<16.0"
- name: Run tests
# `-n auto` lets xdist pick a worker count from the runner's
# CPU count. With the transport cancellable-sleep fix the
# 5s-per-shutdown multiplier is gone, and xdist plus the
# existing respx-based mocking keeps the per-test wall clock
# near single-thread baseline (no shared state between
# workers — ``reset_runtime`` autouse fixture in conftest
# is per-process by construction under xdist).
run: pytest -n auto --durations=20
- name: Run ruff
run: ruff check src/
- name: Run mypy
run: mypy src/
coverage:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: "pip"
cache-dependency-path: pyproject.toml
- run: pip install -e ".[dev]" "pytest-xdist>=3.6" "pytest-cov>=5.0" "pytest-rerunfailures>=14.0,<16.0"
# Single Python leg for coverage — multi-version coverage
# reports don't add signal and double the runner time. 3.12
# is the modern floor for typing-only changes.
# pytest-cov starts coverage in every xdist worker and combines
# the data before producing the report. ``coverage run`` only
# traced the coordinator process, so every parallel run uploaded
# 0 hits even though all tests passed.
- run: pytest -n auto --cov=src/nullrun --cov-branch --cov-report=xml:coverage.xml --cov-report=term
- uses: codecov/codecov-action@v4
if: always()
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage.xml
fail_ci_if_error: true