Continuous integration#
CI runs on every push to main, every pull request, and every tag. It is
defined in .github/workflows/.
flowchart LR
PR["Pull request"] --> L["Lint<br/>ruff check + format"]
PR --> T["Test<br/>py3.11 / 3.12 / 3.13"]
PR --> D["Docs<br/>sphinx -W"]
PR --> B["Build<br/>sdist + wheel"]
L --> G{"All green?"}
T --> G
D --> G
B --> G
G -- no --> X["Blocked"]
G -- yes --> M["Merge to main"]
M --> PAGES["Publish docs<br/>to GitHub Pages"]
M --> TAG["Tag vX.Y.Z"]
TAG --> REL["Build + GitHub release"]
Workflows#
Workflow |
Trigger |
Does |
|---|---|---|
|
PR, push to |
Lint, test across three Python versions, build the docs, build the distribution. |
|
Push to |
Rebuilds and publishes documentation to GitHub Pages. |
|
Tag |
Builds sdist and wheel, verifies the version matches the tag, creates a GitHub release. See Releases and deployment. |
|
Weekly, or manual |
Opens a PR when a pinned driver submodule moves upstream. |
Jobs#
Lint. ruff check and ruff format --check over src and
tests. Formatting is checked, not applied, so CI never disagrees with what
is committed.
Test. The full suite except hardware, on Python 3.11, 3.12, and 3.13, with coverage. The matrix is not decoration: the summit hosts and developer laptops will not run the same Python for the whole life of the instrument.
The checkout uses fetch-depth: 0. setuptools-scm derives the version from
git history, and a shallow clone silently produces a wrong version, which would
then mask exactly the tag problems release.yml exists to catch.
Docs. Built with -W --keep-going, so a Sphinx warning fails the build.
A broken cross-reference or a document missing from a toctree is a defect,
caught on the PR that introduced it rather than discovered months later.
linkcheck also runs but does not fail the build, because external sites go
down for reasons that have nothing to do with this repository.
Build. python -m build plus twine check, so packaging problems
surface on every PR rather than at the moment someone is trying to cut a
release.
Merge requirements#
A pull request should not merge unless lint, test, docs, and build are all
green. Configure this as branch protection on main: CI that can be
bypassed by clicking merge is advisory, not a gate.
Local checks#
.pre-commit-config.yaml runs the same lint and formatting rules locally,
plus whitespace, YAML, and TOML checks:
$ pip install pre-commit
$ pre-commit install
$ pre-commit run --all-files # first time, or after changing the config
To reproduce a CI run before pushing:
$ ruff check src tests && ruff format --check src tests
$ pytest --cov
$ python -m sphinx -W --keep-going -b html docs/source docs/build/html
$ python -m build
What CI cannot catch#
This matters more for instrument software than for a library, and it should not be inferred from a green badge:
Real device behaviour. EtherCAT bus timing, controller-specific error codes, detector readout, vendor firmware quirks. Simulated drivers model what we believe devices do.
Real timing under load. Several daemons commanding a shared bus while a detector reads out.
Hardware topology mistakes. The daemon-to-controller mapping in Daemon inventory is provisional; CI cannot tell that two mechanisms which the configuration says are on separate buses are physically on one.
Interactions with WMKO systems. The Keck 1 telescope interface is a client of observatory services that cannot be exercised from CI.
Hardware test campaigns cover this ground, and they, not CI, are the gate for summit deployment. CI’s job is to guarantee that a version reaching the bench is worth the bench time.