CI/CD Pipelines
CI/CD for Python services runs ruff, pytest, image build, and staged deploy on every merge. Pipelines enforce the same commands developers run locally with uv and pin Python 3.14.0 in CI matrices.
Search across all documentation pages
CI/CD for Python services runs ruff, pytest, image build, and staged deploy on every merge. Pipelines enforce the same commands developers run locally with uv and pin Python 3.14.0 in CI matrices.
# .github/workflows/ci.yml (excerpt)
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
- run: uv sync --frozen
- run: uv run ruff check .
- run: uv run pytest -qWhen to reach for this:
GitHub Actions: test, build/push image, deploy staging with OIDC to AWS.
name: ci-cd
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
with:
python-version: "3.14"
- run: uv sync --frozen
- run: uv run ruff check .
- run: uv run pytest -q --cov=app
build:
needs: test
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/ci-ecr-push
aws-region: us-east-1
- uses: docker/build-push-action@v6
with:
push: true
tags: 123456789012.dkr.ecr.us-east-1.amazonaws.com/api:${{ github.sha }}
deploy-staging:
needs: build
runs-on: ubuntu-latest
environment: staging
steps:
- run: echo "kubectl set image deployment/api api=...:${{ github.sha }}"What this demonstrates:
uv sync --frozen matches lockfile in CIgithub.sha for traceabilityenvironment: staging approval rules| Stage | Gates |
|---|---|
| Lint/test | ruff, mypy optional, pytest |
| Build | Dockerfile, scan image |
| Deploy dev | auto on main |
| Deploy prod | manual approval + smoke test |
uv run ruff check . && uv run pytest -q
docker build -t api:local .- run: uv run python -m build # library packages
- run: uv publish # PyPI when releasing libs not services:latest deploy tag - rollback impossible. Fix: immutable SHA tags only./health step after deploy.| Alternative | Use When | Don't Use When |
|---|---|---|
| GitLab CI | GitLab hosting | GitHub-only org |
| Buildkite | Self-hosted agents | Simple GitHub Actions enough |
| ArgoCD GitOps | K8s deploy drift detection | Single VM docker compose |
This repo runs lint-docs in prebuild - keep docs valid when shipping content with code.
uv faster and lockfile-native - align with manifest uv 0.6+ pin.
setup-uv with cache enabled or Docker buildkit cache mounts for uv sync layer.
Separate job before traffic shift - never only in app startup without coordination.
Retag tested SHA or replay deploy job with prod environment approval - same artifact, no rebuild.
Trunk-based with flags preferred; long-lived env branches rot.
pytest marker with docker-compose service deps in CI job or ephemeral preview env.
paths: filters per package - but run smoke whole-system tests on shared lib changes.
Single tool for lint+format - fast CI step before pytest.
Redeploy previous image tag - document in Runbook linked from Deployment Best Practices.
Stack versions: This page was written for Python 3.14.0 (stable 3.14, maintenance 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, and uv 0.6+.
Reviewed by Chris St. John·Last updated Jul 19, 2026