OMEP-0005: CI/CD Pipeline¶
Context and Problem Statement¶
The project needs a Continuous Integration pipeline that automatically verifies every push and pull request. The pipeline must cover Rust formatting, linting, testing (on multiple toolchains), Python wheel building, and changelog validation.
The project is hosted on GitHub, so the CI solution should integrate natively with the GitHub platform.
Decision Drivers¶
- GitHub-native -- The repository is on GitHub; the CI tool should integrate seamlessly (status checks, PR annotations, caching).
- Matrix testing -- Rust stable and nightly should both be tested to catch regressions early.
- Fast feedback -- Jobs should run in parallel where possible.
- Reproducibility -- CI should use the same tool versions as local development (pinned via mise or action versions).
- Minimal maintenance -- Prefer well-maintained community actions over custom scripts.
Considered Options¶
- Option A: GitHub Actions -- GitHub's built-in CI/CD platform.
- Option B: GitLab CI -- GitLab's CI system (would require mirroring).
- Option C: CircleCI -- Third-party CI service with GitHub integration.
Decision Outcome¶
Chosen option: "GitHub Actions" (Option A), because the project is hosted
on GitHub, Actions are free for public repositories, and the Rust ecosystem
has excellent community-maintained actions (dtolnay/rust-toolchain,
Swatinem/rust-cache, taiki-e/install-action).
Consequences¶
- Good, because zero additional service to manage -- everything is in
.github/workflows/. - Good, because tight integration with GitHub (status checks block merges, annotations appear in PR diffs).
- Good, because community actions for Rust toolchain and caching are battle-tested.
- Good, because matrix strategies allow testing stable + nightly in parallel.
- Bad, because GitHub Actions YAML can be verbose for complex workflows.
- Neutral, because free for public repos; costs only apply if the repo goes private.
Confirmation¶
- Every push to
mainand every PR triggers the workflow. - Branch protection rules require all CI jobs to pass before merging.
- The workflow can be run locally via
mise run ci(for the check/lint/test subset).
Pros and Cons of the Options¶
Option A: GitHub Actions (Chosen)¶
- Good, because native GitHub integration (no external service).
- Good, because free for public repositories.
- Good, because rich marketplace of community actions.
- Good, because matrix builds for multi-toolchain testing.
- Neutral, because YAML syntax, but well-documented.
Option B: GitLab CI¶
- Good, because powerful pipeline DSL.
- Bad, because requires mirroring or migrating the repository.
- Bad, because adds operational complexity.
Option C: CircleCI¶
- Good, because fast builds, good caching.
- Bad, because third-party dependency (account, billing).
- Bad, because less tight GitHub integration than Actions.
More Information¶
Workflow file: .github/workflows/ci.yml
Jobs:
| Job | Description | Toolchain |
|---|---|---|
check |
cargo fmt --check + cargo clippy |
stable |
test |
cargo llvm-cov nextest, both feature configurations |
stable, nightly (matrix) |
build |
cargo build |
stable |
package |
cargo publish --dry-run, mirrors mise run publish:check (OMEP-0009) |
stable |
python |
Build wheel with maturin, run pytest, type-check with ty, verify wheel contents |
stable + Python 3.12/3.13/3.14 (matrix) |
sdist |
Build the sdist, install it and smoke-test the import (OMEP-0009) | stable |
docs |
Build the Zensical site and the rustdoc reference (OMEP-0011) | stable |
changelog |
git cliff --unreleased validation |
N/A |
Deployment of the documentation site to GitHub Pages is a separate workflow,
.github/workflows/docs.yml, which runs on push to main.
Coverage: the test and python jobs also produce coverage and JUnit
reports and upload them to Codecov, each behind its own flag and gated to a
single matrix leg. See OMEP-0012 for the rationale and the component layout.
Key actions used:
| Action | Purpose |
|---|---|
actions/checkout@v7 |
Clone the repository |
dtolnay/rust-toolchain |
Install Rust toolchain |
Swatinem/rust-cache@v2 |
Cache cargo registry and target dir |
taiki-e/install-action |
Install cargo-nextest, cargo-llvm-cov, git-cliff |
actions/setup-python@v7 |
Install Python for the coverage leg |
astral-sh/setup-uv |
Provision Python and the dependency groups for the python, sdist and docs jobs |
codecov/codecov-action@v7 |
Upload coverage and test results (OMEP-0012) |
Triggers: push to main, pull_request targeting main.