Operations
CI/CD
How code gets from a PR to a running cluster.
routess uses GitHub Actions running on a self-hosted runner labelled arc-routess.
Pipeline (.github/workflows/ci.yml)
PR / push ──▶ test ──┐
├──▶ release (semantic-release) ──▶ publish-images
PR / push ──▶ helm-validate ┘ │
│
publish-helm ──▶ GHCR (chart)Stages
| Stage | What it does |
|---|---|
| test | bun install → bun fmt → bun lint + Biome → type-check → run tests with a Postgres service container → build everything |
| helm-validate | helm lint + helm template to catch chart errors |
| release | Runs only on main push. semantic-release reads conventional commits, decides version, creates tag + release notes |
| publish-images | Matrix builds web/api/docs/landing Docker images, pushes to GHCR with version, minor, major, and sha tags |
| publish-helm | Updates Chart.yaml version, helm package, helm push to GHCR OCI registry |
| publish-cli | Publishes the routess CLI to npm with provenance. Runs on a GitHub-hosted runner because npm rejects provenance attestations from self-hosted ones |
Build details
- The shared deps image is cached in GHCR (
routess-deps:cache, BuildKit registry cache), so app image builds only re-run when the lockfile ordocker/Dockerfile.depschanges. - Sentry source-map upload credentials come from 1Password and reach
docker buildx bakethrough a BuildKit secret mount; they never enter image layers. VITE_APP_VERSIONis pinned to the release version at build time so the Sentry release matches whatenv-config.jsreports at runtime.
Versioning
semantic-release reads commits since the last tag:
feat:→ minor bumpfix:→ patch bumpfeat!:orBREAKING CHANGE:→ major bump
The same version flows into Docker tags and the Helm chart. Run bun run release locally only if you know what you're doing; the pipeline does it for you.
Self-hosted runner
arc-routess is an Actions Runner Controller deployment in the same cluster. Builds happen close to the registry, which keeps cache hits high.