CI/CD Pipeline#
This page explains how the project’s continuous integration and delivery pipeline works, from local pre-commit checks through to published container images and Helm charts.
Pipeline overview#
The CI pipeline is defined in .github/workflows/ci.yml and is
composed of four reusable workflow files:
check ─────┬──► container (build & optionally push)
│
└──► helm (package & optionally push)
docs ────────► build & optionally publish to GitHub Pages
Every push to main, every pull request, and every tag triggers the
full pipeline. The check job must succeed before container and helm
run (they depend on it via needs: check). The docs job runs
independently with no dependencies.
Check: lint, type check, and test#
The _check.yml workflow installs Node 22, runs npm ci, then executes
three checks in sequence:
ESLint (
npm run lint) – catches style and correctness issues.TypeScript type check (
npx tsc --noEmit) – ensures the project compiles without errors.Unit tests with coverage (
npm run test:coverage) – runs the Vitest suite.
If any step fails the workflow fails, blocking the container and
helm jobs downstream.
Container image build and publish#
The _container.yml workflow builds a Docker image, smoke-tests it, and
conditionally pushes it to the GitHub Container Registry (GHCR).
Build and test#
Every CI run builds the image and loads it into the local Docker daemon.
A quick health check verifies the container starts and serves
/healthz:
# from _container.yml
docker run -d --name test_container -p 8080:8080 tag_for_testing
curl -sf http://localhost:8080/healthz
The build argument VITE_APP_VERSION is set to the git tag name on tag
pushes and dev otherwise, so the app can display its own version.
Conditional publishing#
The image is only pushed to the registry when both conditions are met:
The
checkjob passed (inputs.publishis true).The git ref is a tag (
github.ref_type == 'tag').
This means pull requests and pushes to main build and test the image
but never publish it. Only a tagged release produces a registry image.
The docker/metadata-action generates two tags for the published image:
the git tag itself (e.g. v1.2.3) and latest.
Helm chart packaging and publish#
The _helm.yml workflow lints, packages, and conditionally pushes the
Helm chart to an OCI registry.
Conditional publishing#
Like the container image, the chart is only pushed when check passes and the ref is a tag:
# from _helm.yml
if: inputs.publish && github.ref_type == 'tag'
The chart is pushed to oci://ghcr.io/<owner>/charts where it can be
installed with:
helm install argocd-monitor oci://ghcr.io/epics-containers/charts/argocd-monitor --version 1.2.3
Documentation publishing#
The _docs.yml workflow builds Sphinx documentation and publishes it to
GitHub Pages.
Key details:
Tag conflict avoidance – when a tag is pushed, the docs job sleeps 60 seconds before checkout to avoid git conflicts with a simultaneous branch push.
Versioned directories – each build is placed under a sanitized ref name (e.g.
main,1.2.3), so multiple versions coexist on the Pages site.Version switcher – a
make_switcher.pyscript updatesswitcher.jsonso the docs site can offer a version dropdown.Publish condition – docs are only published for tags and the
mainbranch, not for pull requests.
Pre-commit hooks#
The .pre-commit-config.yaml file defines hooks that run automatically
on every git commit:
Hook |
Source |
Purpose |
|---|---|---|
|
pre-commit-hooks |
Prevent accidental large file commits |
|
pre-commit-hooks |
Validate YAML syntax (Helm templates excluded) |
|
pre-commit-hooks |
Catch unresolved merge markers |
|
pre-commit-hooks |
Ensure files end with a newline |
|
local |
Lint and auto-fix JS/TS files |
|
local |
TypeScript type checking |
|
compilerla |
Validate conventional commit message format |
|
gitleaks |
Scan for accidentally committed secrets |
These hooks catch common issues before code reaches CI, reducing round-trip time.
The release process#
Releases follow this workflow:
A maintainer pushes a git tag (e.g.
git tag v1.2.3 && git push origin v1.2.3).The tag push triggers the CI pipeline.
Because the ref is a tag:
The container image is built with
VITE_APP_VERSION=v1.2.3and pushed to GHCR with both the version tag andlatest.The Helm chart is packaged as version
1.2.3and pushed to the OCI chart registry.Documentation is built and published under the version directory.
The
_release.ymlworkflow creates a GitHub Release with auto-generated release notes from merged PRs. Tags containinga,b, orrcare marked as pre-releases.