forked from stefanko-ch/Nexus-Stack
-
Notifications
You must be signed in to change notification settings - Fork 0
194 lines (173 loc) · 7 KB
/
Copy pathpython-tests.yml
File metadata and controls
194 lines (173 loc) · 7 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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# =============================================================================
# python-tests — quality gates for the nexus_deploy package
# =============================================================================
# Runs on every push and PR. Three jobs:
# - lint: ruff format check + ruff lint + shellcheck (fast, ~30s)
# - typecheck: mypy --strict (~1-2 min, depends on cache hit)
# - test: pytest unit + integration with coverage gate (≥80%)
#
# Tests run only when Python or workflow files change — to keep CI cheap
# during pure docs/stack PRs.
# =============================================================================
name: Python Tests
on:
pull_request:
paths:
- "src/**"
- "tests/**"
- "pyproject.toml"
- "uv.lock"
- ".python-version"
- ".github/workflows/python-tests.yml"
- "scripts/*.sh"
push:
branches: [main]
paths:
- "src/**"
- "tests/**"
- "pyproject.toml"
- "uv.lock"
- ".python-version"
- ".github/workflows/python-tests.yml"
- "scripts/*.sh"
# Cancel previous runs of this workflow on the same ref. The CI is fast
# but no point burning minutes on a force-push that obsoletes the prior
# attempt.
concurrency:
group: python-tests-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
# ---------------------------------------------------------------------------
# Lint — ruff (Python) + shellcheck (bash helpers)
# ---------------------------------------------------------------------------
lint:
name: Lint (ruff + shellcheck)
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v5
- name: Install uv
uses: astral-sh/setup-uv@v3
with:
version: "0.11.7"
enable-cache: true
- name: Sync dev deps
run: uv sync --frozen --group dev
- name: ruff format --check
run: uv run ruff format --check .
- name: ruff lint
run: uv run ruff check .
- name: shellcheck remaining bash
run: |
# Lints the bash helper scripts in scripts/ — operator
# one-shots (init-r2-state, cleanup-orphaned-resources,
# setup-control-plane-secrets, check-control-plane-env, and
# the smaller capture/check/parse helpers). The main deploy
# path is Python (python -m nexus_deploy run-pipeline) since
# Phase 4c (#535).
# `find -print0 | xargs -0` is portable to macOS bash 3.2 too.
# `--severity=error` only blocks on real bugs; the helpers
# carry a few style/info nits we tolerate.
find scripts -maxdepth 2 -name '*.sh' -type f -print0 \
| xargs -0 uv run shellcheck --severity=error --exclude=SC1091,SC2001
# ---------------------------------------------------------------------------
# Typecheck — mypy --strict
# ---------------------------------------------------------------------------
typecheck:
name: Typecheck (mypy --strict)
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v5
- name: Install uv
uses: astral-sh/setup-uv@v3
with:
version: "0.11.7"
enable-cache: true
- name: Sync deps (incl. type stubs)
run: uv sync --frozen --group dev
- name: mypy strict
run: uv run mypy
# ---------------------------------------------------------------------------
# Test — pytest unit + integration, coverage gate ≥80%
# ---------------------------------------------------------------------------
test:
name: Test (pytest + coverage)
runs-on: ubuntu-latest
timeout-minutes: 15
# Job-scoped permissions — only the coverage-comment step needs write
# access to PRs, and we don't want it bleeding into other jobs.
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v5
- name: Install uv
uses: astral-sh/setup-uv@v3
with:
version: "0.11.7"
enable-cache: true
- name: Sync deps
run: uv sync --frozen --group dev
- name: pytest unit
# Runs the full test suite under pyproject.toml's testpaths (today
# only tests/unit/; an `integration` marker is registered for
# future testcontainers-based tests, but none exist yet, so this
# step is effectively unit-only at present).
# `--cov-fail-under=80` makes the gate explicit on the CLI;
# pyproject.toml's [tool.coverage.report] also has fail_under=80
# so local + CI agree even if someone runs `coverage report` directly.
# `--cov-report=xml` feeds the PR coverage-comment step, `=html`
# feeds the artifact upload, and `tee` keeps the step's stdout
# readable. GitHub-Actions default shell is bash with `pipefail`,
# so a pytest failure still fails the step.
run: |
uv run pytest \
--cov=src/nexus_deploy --cov-fail-under=80 \
--cov-report=term-missing --cov-report=xml --cov-report=html \
| tee pytest-coverage.txt
- name: Coverage comment on PR
# Posts/updates a single markdown comment per PR with total
# coverage, badge, and per-file changed-lines breakdown. No
# external service, no token — just `pull-requests: write`
# scoped above. Skipped on push-to-main runs (no PR to comment on).
if: github.event_name == 'pull_request'
uses: MishaKav/pytest-coverage-comment@v1.1.54
with:
pytest-coverage-path: ./pytest-coverage.txt
pytest-xml-coverage-path: ./coverage.xml
title: "Coverage report — `nexus_deploy`"
badge-title: coverage
hide-badge: false
hide-report: false
create-new-comment: false
report-only-changed-files: false
- name: Upload coverage to Codecov
# External coverage trend graphs + auto-updating README badge.
# Public repos technically don't require a token, but Codecov has
# been progressively rolling out token-required uploads since
# 2023 to deal with token-free upload abuse — providing the
# CODECOV_TOKEN secret avoids the intermittent rate-limit /
# rejection. `fail_ci_if_error: false` makes the step
# non-blocking: if Codecov is down, the gate-relevant local
# `--cov-fail-under=80` step has already passed and CI stays
# green. The MishaKav comment step above is independent of
# Codecov (local-only PR comment); both run.
if: always()
uses: codecov/codecov-action@v4
with:
files: ./coverage.xml
flags: unittests
name: nexus_deploy
fail_ci_if_error: false
token: ${{ secrets.CODECOV_TOKEN }}
- name: Upload coverage artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage-html
path: htmlcov/
retention-days: 7
if-no-files-found: ignore