CI/CD testing project for Termai, using a simple FastAPI service with one endpoint:
GET /healthreturnsstatusandtime(Australia/Sydney ISO-8601 format).
- Python 3.11+
python -m venv .venvWindows PowerShell:
.venv\Scripts\Activate.ps1macOS/Linux:
source .venv/bin/activateInstall app and test dependencies:
python -m pip install --upgrade pip
python -m pip install -e ".[test,dev]"Compile source and tests:
python -m compileall app testsRun tests:
python -m pytest -qRun tests with info
python -m pytest -vv -s -rA --log-cli-level=INFOStart FastAPI with Uvicorn:
uvicorn app.main:app --host 0.0.0.0 --port 8101 --reloadHealth endpoint:
curl http://127.0.0.1:8101/healthBuild the image:
$RAW_VERSION = python -m setuptools_scm
$VERSION = $RAW_VERSION.Trim() -replace '\+', '-'
docker build -t "termai-cicd:$VERSION" -t "termai-cicd:latest" .Run the container:
docker run --rm -p 8101:8101 --name termai-cicd-local "termai-cicd:$VERSION"Test the health endpoint from another terminal:
curl http://127.0.0.1:8101/healthInspect logs:
docker logs termai-cicd-localStop the container:
docker stop termai-cicd-localThe GitHub Actions workflow at .github/workflows/ci.yml runs on every push to main and performs:
- Python setup and dependency installation from
requirements.txtandrequirements-test.txt. - Unit/integration test execution with
pytest. - Docker image build.
- Image push to GitHub Container Registry (GHCR) with tags:
ghcr.io/<owner>/<repo>:<commit-sha>ghcr.io/<owner>/<repo>:latest
Required GitHub setup:
- Repository Actions must have
packages: writepermission. - Registry auth is handled with
${{ secrets.GITHUB_TOKEN }}in the workflow.
Dynamic version tags are sanitized for Docker compatibility (replaces + with -):
raw_version="$(python -m setuptools_scm)"
docker_version="${raw_version//+/-}"
echo "value=$docker_version" >> "$GITHUB_OUTPUT"The workflow outputs docker_version and uses it for image tags.
Project versioning is managed by setuptools-scm from git history/tags.
- On a tagged commit (for example
v0.2.0), the package version is0.2.0. - On commits after that tag, versions are generated automatically (for example
0.2.0.post1+g<sha>).
Create a new release tag:
git checkout main
git pull
git tag -a v0.2.0 -m "Release v0.2.0"
git push origin v0.2.0Create a GitHub release from the tag:
gh release create v0.2.0 --title "v0.2.0" --notes "Release notes for v0.2.0"Recommended release flow:
- Merge tested changes to
main. - Create and push an annotated tag (
vX.Y.Z). - Create a GitHub release for that tag.
- Let CI build/push the Docker image for the tagged commit.
Manifests are under k8s/:
deployment.yamlservice.yamlingress.yaml(TLS enabled; uses secrettermai-cicd-tls)
These files use placeholders so namespace/image/host are configurable:
${NAMESPACE}${IMAGE}${INGRESS_HOST}
Apply them with envsubst:
export NAMESPACE=termai
export IMAGE=ghcr.io/<owner>/<repo>:<commit-sha>
export INGRESS_HOST=termai.internal.example.com
kubectl create namespace "$NAMESPACE" --dry-run=client -o yaml | kubectl apply -f -
envsubst < k8s/deployment.yaml | kubectl apply -f -
envsubst < k8s/service.yaml | kubectl apply -f -
envsubst < k8s/ingress.yaml | kubectl apply -f -For .dw.csiro.au, cert-manager will provision TLS automatically from the Ingress annotation:
cert-manager.io/cluster-issuer: cluster-issuer-csirotermai-cicd-tls is created/renewed by cert-manager.
Verify HTTPS:
curl -I https://termai-cicd.dw.csiro.au/health- Push code to
mainto trigger CI and publish a new image tag (commit SHA). - Update deployment to the new image:
export NAMESPACE=termai
export IMAGE=ghcr.io/<owner>/<repo>:<new-commit-sha>
envsubst < k8s/deployment.yaml | kubectl apply -f -
kubectl -n "$NAMESPACE" rollout status deploy/termai-cicd.
├── app/ # FastAPI application code
├── tests/ # Pytest test suite
├── Dockerfile # Container build definition
├── .dockerignore
├── requirements.txt # Runtime dependencies
├── requirements-test.txt # Test dependencies
├── k8s/ # Kubernetes manifests
│ ├── deployment.yaml
│ ├── service.yaml
│ └── ingress.yaml
└── .github/
└── workflows/
└── ci.yml # CI pipeline (test, build, push)