CI/CD Pipeline workflow (JiayuXu0/FastAPI-Template)
The CI/CD Pipeline workflow from JiayuXu0/FastAPI-Template, explained and optimized by Latchkey.
CI health: C - fair
Point runs-on at Latchkey and get run de-duplication, job timeouts, SHA-pinned actions, self-healing for flaky steps, and up to 58% lower cost, applied automatically.
What it does
This is the CI/CD Pipeline workflow from the JiayuXu0/FastAPI-Template repository, a real project running GitHub Actions. It is shown here with attribution under its MIT license.
Below, Latchkey shows a faster, safer version produced by its optimization engine.
The workflow
name: CI/CD Pipeline
on:
push:
branches: [ main, master, develop ]
pull_request:
branches: [ main, master, develop ]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v2
with:
version: "latest"
- name: Set up Python
run: uv python install 3.11
- name: Install dependencies
run: uv sync --dev
# 真红线:ruff lint 与格式都必须通过;不再 || true
- name: Lint with ruff
run: uv run ruff check src/
- name: Format check with ruff
run: uv run ruff format --check src/
# mypy 当前还有积压错误(issue 跟踪),跑出来作为 informational artifact,
# 不阻断流水线;后续逐步清理后再改为真红线。
- name: Type check with mypy (informational)
env:
SECRET_KEY: test_secret_key_for_testing_only_32_chars_long
SWAGGER_UI_PASSWORD: test_password_123
DB_PASSWORD: test_db_password
APP_ENV: testing
DEBUG: "True"
run: uv run mypy src/ --no-error-summary > mypy_report.txt 2>&1 || true
- name: Upload mypy report
uses: actions/upload-artifact@v4
with:
name: mypy-report
path: mypy_report.txt
test:
runs-on: ubuntu-latest
needs: [lint]
services:
redis:
image: redis:7-alpine
ports: ["6379:6379"]
options: >-
--health-cmd "redis-cli ping"
--health-interval 5s
--health-timeout 3s
--health-retries 5
strategy:
matrix:
python-version: ["3.11", "3.12"]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v2
with:
version: "latest"
- name: Set up Python ${{ matrix.python-version }}
run: uv python install ${{ matrix.python-version }}
- name: Install dependencies
run: uv sync --dev
# 真红线:跑 tests/ 全集
- name: Run tests with coverage
env:
SECRET_KEY: test_secret_key_for_testing_only_32_chars_long
SWAGGER_UI_PASSWORD: test_password_123
DB_PASSWORD: test_db_password
APP_ENV: testing
DEBUG: "True"
REDIS_URL: redis://localhost:6379/0
run: |
uv run pytest tests/ -v \
--cov=src --cov-report=xml --cov-report=html --cov-report=term-missing \
--cov-fail-under=30
- name: Upload coverage reports
if: matrix.python-version == '3.11'
uses: actions/upload-artifact@v4
with:
name: coverage-reports
path: |
coverage.xml
htmlcov/
- name: Upload coverage to Codecov
if: matrix.python-version == '3.11'
uses: codecov/codecov-action@v4
with:
file: ./coverage.xml
flags: unittests
name: codecov-umbrella
security:
runs-on: ubuntu-latest
needs: [lint]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v2
- name: Set up Python
run: uv python install 3.11
- name: Install dependencies
run: uv sync --dev
# 真红线:bandit 中/高严重度 → 必须修;low 通过 -ll 过滤
- name: Run security checks with bandit (medium+ severity)
env:
SECRET_KEY: test_secret_key_for_testing_only_32_chars_long
SWAGGER_UI_PASSWORD: test_password_123
DB_PASSWORD: test_db_password
APP_ENV: testing
DEBUG: "True"
run: uv run bandit -r src/ -ll
# safety 现在需要登录账号,改用 pip-audit(PyPA 维护、无需登录)
- name: Run dependency vulnerability scan (informational)
run: |
uv pip install pip-audit
uv run pip-audit --strict --skip-editable || true
build:
runs-on: ubuntu-latest
needs: [test, security]
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master')
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v2
- name: Set up Python
run: uv python install 3.11
- name: Build package
run: |
uv sync
uv build
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: python-package-distributions
path: dist/
The same workflow, on Latchkey
Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.
name: CI/CD Pipeline on: push: branches: [ main, master, develop ] pull_request: branches: [ main, master, develop ] concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: lint: timeout-minutes: 30 runs-on: latchkey-small steps: - name: Checkout code uses: actions/checkout@v4 - name: Install uv uses: astral-sh/setup-uv@v2 with: version: "latest" - name: Set up Python run: uv python install 3.11 - name: Install dependencies run: uv sync --dev # 真红线:ruff lint 与格式都必须通过;不再 || true - name: Lint with ruff run: uv run ruff check src/ - name: Format check with ruff run: uv run ruff format --check src/ # mypy 当前还有积压错误(issue 跟踪),跑出来作为 informational artifact, # 不阻断流水线;后续逐步清理后再改为真红线。 - name: Type check with mypy (informational) env: SECRET_KEY: test_secret_key_for_testing_only_32_chars_long SWAGGER_UI_PASSWORD: test_password_123 DB_PASSWORD: test_db_password APP_ENV: testing DEBUG: "True" run: uv run mypy src/ --no-error-summary > mypy_report.txt 2>&1 || true - name: Upload mypy report uses: actions/upload-artifact@v4 with: name: mypy-report path: mypy_report.txt test: timeout-minutes: 30 runs-on: latchkey-small needs: [lint] services: redis: image: redis:7-alpine ports: ["6379:6379"] options: >- --health-cmd "redis-cli ping" --health-interval 5s --health-timeout 3s --health-retries 5 strategy: matrix: python-version: ["3.11", "3.12"] steps: - name: Checkout code uses: actions/checkout@v4 - name: Install uv uses: astral-sh/setup-uv@v2 with: version: "latest" - name: Set up Python ${{ matrix.python-version }} run: uv python install ${{ matrix.python-version }} - name: Install dependencies run: uv sync --dev # 真红线:跑 tests/ 全集 - name: Run tests with coverage env: SECRET_KEY: test_secret_key_for_testing_only_32_chars_long SWAGGER_UI_PASSWORD: test_password_123 DB_PASSWORD: test_db_password APP_ENV: testing DEBUG: "True" REDIS_URL: redis://localhost:6379/0 run: | uv run pytest tests/ -v \ --cov=src --cov-report=xml --cov-report=html --cov-report=term-missing \ --cov-fail-under=30 - name: Upload coverage reports if: matrix.python-version == '3.11' uses: actions/upload-artifact@v4 with: name: coverage-reports path: | coverage.xml htmlcov/ - name: Upload coverage to Codecov if: matrix.python-version == '3.11' uses: codecov/codecov-action@v4 with: file: ./coverage.xml flags: unittests name: codecov-umbrella security: timeout-minutes: 30 runs-on: latchkey-small needs: [lint] steps: - name: Checkout code uses: actions/checkout@v4 - name: Install uv uses: astral-sh/setup-uv@v2 - name: Set up Python run: uv python install 3.11 - name: Install dependencies run: uv sync --dev # 真红线:bandit 中/高严重度 → 必须修;low 通过 -ll 过滤 - name: Run security checks with bandit (medium+ severity) env: SECRET_KEY: test_secret_key_for_testing_only_32_chars_long SWAGGER_UI_PASSWORD: test_password_123 DB_PASSWORD: test_db_password APP_ENV: testing DEBUG: "True" run: uv run bandit -r src/ -ll # safety 现在需要登录账号,改用 pip-audit(PyPA 维护、无需登录) - name: Run dependency vulnerability scan (informational) run: | uv pip install pip-audit uv run pip-audit --strict --skip-editable || true build: timeout-minutes: 30 runs-on: latchkey-small needs: [test, security] if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master') steps: - name: Checkout code uses: actions/checkout@v4 - name: Install uv uses: astral-sh/setup-uv@v2 - name: Set up Python run: uv python install 3.11 - name: Build package run: | uv sync uv build - name: Upload build artifacts uses: actions/upload-artifact@v4 with: name: python-package-distributions path: dist/
What changed
- Run on Latchkey managed runners with one line (
runs-on), which apply the fixes below automatically and self-heal transient failures. This example useslatchkey-small; pick the runner size that fits the job. - Cancel superseded runs when a branch or PR gets a newer push.
- Add a job timeout so a hung step cannot burn hours of runner time.
2 third-party actions are referenced by a movable tag. Pin them to the commit SHA (Latchkey resolves and applies this automatically) so a repointed tag cannot change what runs.
What Latchkey heals here
This workflow has steps that commonly fail on transient issues (network, registries, flaky browsers). On Latchkey managed runners they are detected, retried, and self-healed instead of failing your build:
- Dependency installs
This workflow runs 4 jobs (5 with the matrix expanded) per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.