CI & repository conventions¶
The ShipSoft repositories share their CI, release tooling and
repository settings through
ShipSoft/.github. Its README
is the reference for every workflow input; this page is the overview:
what exists, who uses it, and what it means when you open a pull
request.
Reusable workflows¶
A repository calls these from its own .github/workflows/ with
uses: ShipSoft/.github/.github/workflows/<name>.yml@main. Callers as
of 2026-10:
| Workflow | What it does | Called by |
|---|---|---|
pixi-cmake-build.yml |
Runs a list of pixi tasks (configure, build, test, …) with --locked, compiling through ccache |
aegir, aegir-genie, data-model, field_service, Geometry, geometry_service, Shannon, ship-ci-metrics, ship-random, Trout |
prek.yml |
Runs the prek hooks from the lint environment, check-only (see Linting & git hooks) |
every active pixi repository except sea-cucumber |
commit-check.yml |
Checks every commit of a PR against Conventional Commits with commitizen | same as prek.yml |
clang-tidy.yml |
clang-tidy ratchet: fails only on findings in changed lines | aegir, aegir-genie, data-model, field_service, Geometry, geometry_service, Shannon, ship-random |
pixi-lock-update.yml |
Scheduled PR that runs pixi update and shows the diff |
every active pixi repository except sea-cucumber |
config-sync.yml |
Scheduled PR that copies the shared config files from sync/ |
all active repositories except sea-cucumber |
release.yml |
Publishes a GitHub release for a pushed v* tag, with notes from git-cliff |
aegir, aegir-genie, data-model, field_service, Geometry, geometry_service, Shannon, ship-ci-metrics, ship-random, Trout |
doxygen-pages.yml |
Builds Doxygen and deploys it to GitHub Pages through Actions | aegir, aegir-genie, data-model, field_service, Geometry, geometry_service, Shannon, ship-random, Trout |
doxygen-gh-pages.yml |
The same, published to a gh-pages branch |
FairShip |
physics-metrics.yml |
Stores physics metrics from main in git notes and compares PRs against them |
aegir |
rattler-build-and-upload.yml |
Builds conda recipes and uploads them to prefix.dev/ship-experiment/stable |
ship-conda-recipes (see CI and secrets) |
The workflows are referenced by @main, so a change in
ShipSoft/.github reaches every caller on its next run.
What a pull request has to pass¶
Every repository listed in
repo-config/repos.json
gets the same two rulesets on its default branch:
- no deletion and no force-push, with no bypass for anyone;
- linear history, a merge queue, one approving review, resolved conversations, and squash or rebase as the only merge methods. Repository admins may bypass this one.
Instead of requiring individual jobs, the rulesets require two
aggregator jobs with fixed names: All checks passed in the build
workflow and Lint passed in the lint workflow. Each repository
defines them to fail if any other job in the same workflow failed or
was cancelled. Both workflows must also run on merge_group, or the
merge queue waits for a check that never arrives. commit-check.yml
is skipped in the queue, which counts as a pass: commit messages are
checked on the pull request.
Some repositories have a different tier in repos.json. sea-cucumber
builds, tests and lints in one job, so it only requires
All checks passed. Trout, htcondor_submission_scripts, tutorials and
.github itself have no required checks.
The settings are applied by hand with
repo-config/apply-repo-config.sh (a dry run prints the drift), not
by a scheduled job.
Shared configuration files¶
Some files have to be identical everywhere. Their canonical copies
live in ShipSoft/.github/sync/,
and each repository's config-sync.yml caller opens a PR on the first
of the month when its copy has drifted:
AI_POLICY.mdin every repository;.clang-tidyandcliff.tomlin the C++ repositories.
Edit these in ShipSoft/.github, not in the repository you're working
on; a local edit is overwritten by the next sync. A repository that
needs extra clang-tidy settings adds a .clang-tidy with
InheritParentConfig: true in a subdirectory instead. .clang-format
is deliberately per repository.
Naming¶
SHiP is the only top-level C++ namespace. Everything nested in it is
lower_case (SHiP::geometry, SHiP::aegir::g4), and a type inside
it doesn't repeat the prefix (SHiP::GeometryService, not
SHiP::SHiPGeometryService). The shared .clang-tidy enforces the
case rule. A forbid-ship-namespace hook that rejects the old
lower-case ship namespace exists in ShipSoft/.github, but can't be
used until that repository has its first tag.
Dependency updates¶
Two mechanisms keep dependencies current:
pixi-lock-update.ymlrefreshespixi.lockon the first of each month, within the version ranges inpixi.toml.- Renovate bumps the ranges
themselves, GitHub Actions versions and pre-commit revisions.
Repositories opt in with a
renovate.jsonthat extends the shared preset,local>ShipSoft/.github. It runs at weekends with at most five open PRs and compares conda packages with conda versioning.
Releases¶
data-model, Geometry, geometry_service, field_service and Trout
release with a scripts/release.sh in the repository:
scripts/release.sh X.Y.Zbumps the version inCMakeLists.txt(and, where present,CITATION.cff, the[package]version inpixi.tomlor the dev recipe), regeneratesCHANGELOG.mdwith git-cliff and creates achore(release): vX.Y.Zcommit.- Open a pull request with that commit and merge it.
- Tag the release commit on
mainasvX.Y.Zand push the tag. release.ymlpublishes the GitHub release with notes generated from the Conventional Commits since the previous tag.
The script's --help lists repository-specific steps (data-model, for
example, also writes a frozen compatibility reference file). Getting
the new version onto prefix.dev/ship-experiment/stable is a separate step in
ship-conda-recipes; see Bump a version.
Physics metrics¶
aegir compares a set of physics metrics between a pull request and
main on every PR. The tools come from
ship-ci-metrics
(ship-metrics-extract, -compare, -render, -pr-comment), which
started as FairShip's CI scripts. The CI job extracts metrics from its
output files according to a metrics_config.yaml, and
physics-metrics.yml stores them in git notes on main and posts a
comparison comment on pull requests. Each metric declares whether it
must match exactly, within a relative tolerance, or within its
statistical uncertainty.
Shared random numbers¶
aegir, aegir-genie, Shannon and Trout take their random number
generator from ship-random,
a header-only Philox generator (SHiP::random::PhiloxRng) seeded per
event from a seed, a stream key and a counter. Results are therefore
reproducible regardless of the number of threads. Use a different
stream key for each independent purpose.