@@ -10,72 +10,21 @@ concurrency:
1010 group : ${{ github.head_ref || github.run_id }}
1111 cancel-in-progress : true
1212
13- permissions :
14- contents : read
15-
1613jobs :
1714 lint :
1815 runs-on : ubuntu-latest
19- timeout-minutes : 10
2016 steps :
2117 - uses : actions/checkout@v4
2218 - uses : extractions/setup-just@v2
2319 - uses : astral-sh/setup-uv@v3
2420 with :
2521 enable-cache : true
2622 cache-dependency-glob : " **/pyproject.toml"
27- - run : uv python install 3.10
23+ - run : uv python install 3.11
2824 - run : just install lint-ci
29- - name : Validate templates/semvertag.yml shape
30- # GitLab CI Catalog component descriptor — no published JSON Schema
31- # exists upstream (verified 2026-05-30: not in check-jsonschema's
32- # vendor.* builtins, not on schemastore.org). Fall back to a
33- # structural sanity check via the shared helper in
34- # tests/_descriptor_gate.py — the same module is exercised by
35- # tests/test_ci_descriptor_gate.py so the gate and its regression
36- # tests cannot drift. Upgrade path: switch to a real schema
37- # validator if/when GitLab publishes a Catalog component schema.
38- run : uv run --with pyyaml python -m tests._descriptor_gate templates/semvertag.yml
39- - name : Descriptor gate regression tests
40- # tests/test_ci_descriptor_gate.py uses pytest.importorskip("yaml") so
41- # it skips in the main `uv run pytest` job; this step exercises the
42- # full positive + negative-mutation suite against the shared helper.
43- run : uv run --with pyyaml pytest tests/test_ci_descriptor_gate.py -q
44- - run : uv build
45- - run : uv run --with-requirements docs/requirements.txt -- mkdocs build --strict
46- - id : loc_gate
47- name : LOC gate (NFR21)
48- run : |
49- # Non-blank, non-comment, non-docstring SLOC under semvertag/**/*.py.
50- # Docstring bodies are excluded per NFR21 wording ("non-blank non-comment").
51- # Recognises """-delimited docstrings only — this codebase doesn't use '''.
52- LOC=$(find semvertag -name '*.py' -type f -not -path '*/__pycache__/*' -print0 \
53- | xargs -0 awk '
54- BEGIN { total = 0 }
55- FNR == 1 { in_ds = 0 }
56- {
57- if (in_ds) {
58- if ($0 ~ /"""[[:space:]]*$/) { in_ds = 0 }
59- next
60- }
61- if ($0 ~ /^[[:space:]]*"""/) {
62- if ($0 ~ /^[[:space:]]*""".*"""[[:space:]]*$/) { next }
63- in_ds = 1
64- next
65- }
66- if (NF && $0 !~ /^[[:space:]]*#/) { total++ }
67- }
68- END { print total }
69- ')
70- echo "::notice::semvertag/**/*.py = ${LOC} LOC (NFR21 soft target: 1500)"
71- echo "semvertag_loc=${LOC}" >> "$GITHUB_OUTPUT"
72- if [ "${LOC}" -gt 1500 ]; then
73- echo "::warning::LOC ${LOC} exceeds NFR21 soft target of 1500"
74- fi
7525
7626 pytest :
7727 runs-on : ubuntu-latest
78- timeout-minutes : 15
7928 strategy :
8029 fail-fast : false
8130 matrix :
9443 cache-dependency-glob : " **/pyproject.toml"
9544 - run : uv python install ${{ matrix.python-version }}
9645 - run : just install
97- - run : just test . --cov=. --cov-report xml
98- # Fork-safe guard: explicit allowlist — push on main + same-repo PR. Any future
99- # event addition (schedule, workflow_dispatch, merge_group, pull_request_target)
100- # is excluded by default so CODECOV_TOKEN is not exposed to those contexts.
101- - if : ${{ github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) }}
102- uses : codecov/codecov-action@v5.5.1
103- env :
104- CODECOV_TOKEN : ${{ secrets.CODECOV_TOKEN }}
105- with :
106- files : ./coverage.xml
107- flags : unittests
108- name : codecov-${{ matrix.python-version }}
109-
110- pip-audit :
111- runs-on : ubuntu-latest
112- timeout-minutes : 10
113- steps :
114- - uses : actions/checkout@v4
115- - uses : extractions/setup-just@v2
116- - uses : astral-sh/setup-uv@v3
117- with :
118- enable-cache : true
119- cache-dependency-glob : " **/uv.lock"
120- - run : uv python install 3.10
121- - run : just install
122- # Export the resolved lockfile to requirements format so pip-audit scans the
123- # pinned versions semvertag actually ships (not whatever pyproject.toml
124- # resolves to fresh today — its specifiers are unbounded).
125- - run : uv export --format requirements-txt --frozen --no-hashes --output-file requirements-audit.txt
126- - uses : pypa/gh-action-pip-audit@v1.1.0
127- with :
128- inputs : requirements-audit.txt
46+ - run : just test --cov-report xml
0 commit comments