Skip to content

Commit da7965f

Browse files
Technologicatclaude
andcommitted
Phase 7: GitHub Actions CI with cibuildwheel and trusted-publisher
Five-job pipeline driven by .github/workflows/ci.yml, following the pylu/pydgq pattern with wlsqm-specific adjustments: 1. lint (ubuntu-latest): - ruff check . --ignore SIM103 (blocking) - ruff check . --select SIM103 || true (advisory, non-blocking) - cython-lint on every .pyx and .pxd, non-blocking (|| true) so that advisory drift in the Cython layer does not block merges. 2. test (needs: lint) matrix: {linux, macOS, windows} x Python 3.11-3.14 - On macOS, `brew install libomp` before the build so meson's `dependency('openmp', required: false)` can find it. If it still cannot, the build falls back to serial (via the required:false arg) and tests still pass. - `pip install meson-python meson ninja Cython numpy scipy pytest` then `pip install --no-build-isolation -e .` then `pytest tests/ -v`. 3. build-wheels (needs: test) matrix: {linux, macOS, windows} - pypa/cibuildwheel@v3.4. Config lives in pyproject.toml ([tool.cibuildwheel]) from Phase 2: build cp311 through cp314, skip 32-bit and musllinux, test-requires numpy+scipy+pytest, test-command `pytest {project}/tests -v`, and the macOS before-all that does `brew install libomp`. - Wheels uploaded as `wheels-${{ matrix.os }}` artifacts. 4. sdist (needs: test) on ubuntu-latest: - `python -m build --sdist` (the build backend is meson-python and the sdist already ships the .pxd files so downstream cimport users can build against it — verified locally). - Uploaded as `sdist` artifact. 5. publish (needs: build-wheels + sdist) on refs/tags/v*: - Environment `pypi` with `id-token: write` permission, using the pypa/gh-action-pypi-publish@release/v1 trusted-publisher action. - No PyPI API token stored as a GitHub secret; the job mints a short-lived OIDC token via the trusted-publisher mechanism. External setup still required (documented in the brief, needs to be done on PyPI's side before the first tag push): - Log in to pypi.org, register the `wlsqm` package name if not taken, go to Publishing settings, add a trusted publisher with: - Repository: Technologicat/python-wlsqm - Workflow: ci.yml - Environment: pypi - On GitHub, create the `pypi` environment for this repo. Dev-dep changes (pyproject.toml + pdm.lock): - Add `build` so `python -m build --sdist` works locally for pre- release sanity checks, matching the CI sdist step. - Add `pyyaml` so that .github/workflows/*.yml can be validated from the dev venv without a separate install. Verified locally: ruff clean (blocking + SIM103), cython-lint clean, pytest 57/57 green, `python -m build --sdist` produces a self-contained wlsqm-1.0.0.tar.gz including every .pyx/.pxd and meson.build. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 2938571 commit da7965f

File tree

3 files changed

+220
-2
lines changed

3 files changed

+220
-2
lines changed

.github/workflows/ci.yml

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [master]
6+
tags: ["v*"]
7+
pull_request:
8+
branches: [master]
9+
10+
jobs:
11+
lint:
12+
runs-on: ubuntu-latest
13+
steps:
14+
- uses: actions/checkout@v6
15+
16+
- uses: actions/setup-python@v6
17+
with:
18+
python-version: "3.14"
19+
20+
- name: Install linters
21+
run: pip install ruff cython-lint
22+
23+
- name: Lint Python with ruff
24+
run: ruff check . --ignore SIM103
25+
- name: Lint advisories (non-blocking)
26+
run: ruff check . --select SIM103 || true
27+
28+
- name: Lint Cython
29+
run: >
30+
cython-lint
31+
wlsqm/fitter/defs.pyx wlsqm/fitter/defs.pxd
32+
wlsqm/fitter/infra.pyx wlsqm/fitter/infra.pxd
33+
wlsqm/fitter/impl.pyx wlsqm/fitter/impl.pxd
34+
wlsqm/fitter/polyeval.pyx wlsqm/fitter/polyeval.pxd
35+
wlsqm/fitter/interp.pyx wlsqm/fitter/interp.pxd
36+
wlsqm/fitter/simple.pyx wlsqm/fitter/simple.pxd
37+
wlsqm/fitter/expert.pyx
38+
wlsqm/utils/lapackdrivers.pyx wlsqm/utils/lapackdrivers.pxd
39+
wlsqm/utils/ptrwrap.pyx wlsqm/utils/ptrwrap.pxd
40+
|| true
41+
42+
test:
43+
needs: lint
44+
strategy:
45+
fail-fast: false
46+
matrix:
47+
os: [ubuntu-latest, macos-latest, windows-latest]
48+
python-version: ["3.11", "3.12", "3.13", "3.14"]
49+
runs-on: ${{ matrix.os }}
50+
steps:
51+
- uses: actions/checkout@v6
52+
53+
- uses: actions/setup-python@v6
54+
with:
55+
python-version: ${{ matrix.python-version }}
56+
57+
# Apple Clang does not ship an OpenMP runtime; install libomp so that
58+
# meson's `dependency('openmp', required: false)` can find it. If meson
59+
# still cannot discover it the build falls back to serial and the tests
60+
# still pass, but installing libomp keeps the macOS runner on the same
61+
# parallel code path as Linux/Windows whenever possible.
62+
- name: Install libomp (macOS)
63+
if: runner.os == 'macOS'
64+
run: brew install libomp
65+
66+
- name: Install build and test dependencies
67+
run: pip install meson-python meson ninja Cython numpy scipy pytest
68+
69+
- name: Install wlsqm
70+
run: pip install --no-build-isolation -e .
71+
72+
- name: Run tests
73+
run: pytest tests/ -v
74+
75+
build-wheels:
76+
needs: test
77+
runs-on: ${{ matrix.os }}
78+
strategy:
79+
matrix:
80+
os: [ubuntu-latest, macos-latest, windows-latest]
81+
steps:
82+
- uses: actions/checkout@v6
83+
84+
# cibuildwheel config lives in pyproject.toml ([tool.cibuildwheel]) —
85+
# build list, skip list, test-requires, test-command, and the macOS
86+
# before-all that installs libomp.
87+
- uses: pypa/cibuildwheel@v3.4
88+
89+
- uses: actions/upload-artifact@v7
90+
with:
91+
name: wheels-${{ matrix.os }}
92+
path: wheelhouse/*.whl
93+
94+
sdist:
95+
needs: test
96+
runs-on: ubuntu-latest
97+
steps:
98+
- uses: actions/checkout@v6
99+
- uses: actions/setup-python@v6
100+
with:
101+
python-version: "3.14"
102+
- run: pip install build
103+
- run: python -m build --sdist
104+
- uses: actions/upload-artifact@v7
105+
with:
106+
name: sdist
107+
path: dist/*.tar.gz
108+
109+
publish:
110+
if: startsWith(github.ref, 'refs/tags/v')
111+
needs: [build-wheels, sdist]
112+
runs-on: ubuntu-latest
113+
# Requires the `pypi` environment to be configured on GitHub with a
114+
# trusted publisher for this repo + workflow + environment. No API token
115+
# stored as a secret; the job mints a short-lived OIDC token instead.
116+
environment: pypi
117+
permissions:
118+
id-token: write
119+
steps:
120+
- uses: actions/download-artifact@v8
121+
with:
122+
path: dist/
123+
merge-multiple: true
124+
125+
- uses: pypa/gh-action-pypi-publish@release/v1
126+
with:
127+
packages-dir: dist/

pdm.lock

Lines changed: 88 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,4 +141,9 @@ dev = [
141141
"meson-python>=0.17",
142142
"meson",
143143
"ninja",
144+
# For local pre-release sanity checks: `python -m build --sdist`
145+
# exercises the same sdist path that CI runs on tag push.
146+
"build",
147+
# For validating .github/workflows/*.yml during local dev (not used at runtime).
148+
"pyyaml>=6.0.3",
144149
]

0 commit comments

Comments
 (0)