Skip to content
Latchkey

Tests workflow (model-bakers/model_bakery)

The Tests workflow from model-bakers/model_bakery, explained and optimized by Latchkey.

A

CI health: A - excellent

Point runs-on at Latchkey and get job timeouts, self-healing for flaky steps, and up to 58% lower cost, applied automatically.

Grade your own workflow free or run it on Latchkey →
Source: model-bakers/model_bakery.github/workflows/ci.ymlLicense Apache-2.0View source

What it does

This is the Tests workflow from the model-bakers/model_bakery repository, a real project running GitHub Actions. It is shown here with attribution under its Apache-2.0 license.

Below, Latchkey shows a faster, safer version produced by its optimization engine.

The workflow

workflow (.yml)
name: Tests

on:
  push:
    branches:
      - main
  pull_request:

concurrency:
  group: ${{ github.head_ref || github.run_id }}
  cancel-in-progress: true

permissions:
  contents: read

jobs:
  linters:
    runs-on: ubuntu-24.04
    strategy:
      matrix:
        lint-command:
          - ruff check --output-format=github .
          - black --check --diff .
          - ty check model_bakery
    steps:
      - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
        with:
          persist-credentials: false
      - name: Install uv
        uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
        with:
          python-version: "3.13"
      - run: uv run --frozen ${{ matrix.lint-command }}

  sqlite-tests:
    name: SQLite - Python ${{ matrix.python-version }}, Django ${{ matrix.django-version }}
    runs-on: ubuntu-24.04
    strategy:
      fail-fast: false
      matrix:
        python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
        django-version: ["5.2", "6.0"]
        exclude:
          # Django 6.0 supports Python 3.12+
          - python-version: "3.10"
            django-version: "6.0"
          - python-version: "3.11"
            django-version: "6.0"

    steps:
      - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
        with:
          persist-credentials: false
      - name: Set TOX_ENV
        run: echo "TOX_ENV=py$(echo ${{ matrix.python-version }} | tr -d .)-django$(echo ${{ matrix.django-version }} | tr -d .)-sqlite" >> $GITHUB_ENV

      - name: Install uv
        uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
        with:
          python-version: ${{ matrix.python-version }}

      - name: Run tox targets for ${{ matrix.python-version }}
        run: uvx --with tox-uv tox run -e ${TOX_ENV}

      - name: Upload coverage data
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
        with:
          name: coverage-data-${{ env.TOX_ENV }}
          include-hidden-files: true
          path: '.coverage.*'
          if-no-files-found: ignore

  postgresql-tests:
    name: PostgreSQL - Python ${{ matrix.python-version }}, Django ${{ matrix.django-version }}, ${{ matrix.variant }}
    runs-on: ubuntu-24.04
    strategy:
      fail-fast: false
      matrix:
        python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
        django-version: ["5.2", "6.0"]
        variant: ["postgresql", "postgresql-psycopg3"]
        exclude:
          # Django 6.0 supports Python 3.12+
          - python-version: "3.10"
            django-version: "6.0"
          - python-version: "3.11"
            django-version: "6.0"
        include:
          # Latest Python/Django with contenttypes disabled
          - python-version: "3.14"
            django-version: "6.0"
            variant: "postgresql-no-contenttypes"

    env:
      PGUSER: postgres
      PGPASSWORD: postgres

    services:
      postgis:
        image: postgis/postgis:latest@sha256:743c03d986e29c4dc3cba907e6b4477e1a67b9c937ae14f33be4ae9eaf983625
        env:
          POSTGRES_DB: postgres
          POSTGRES_PASSWORD: postgres
          POSTGRES_USER: postgres
        ports:
          - 5432:5432
        options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5

    steps:
      - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
        with:
          persist-credentials: false
      - name: Set TOX_ENV
        run: echo "TOX_ENV=py$(echo ${{ matrix.python-version }} | tr -d .)-django$(echo ${{ matrix.django-version }} | tr -d .)-${{ matrix.variant }}" >> $GITHUB_ENV

      - name: Set up PostgreSQL
        run: |
          sudo apt-get update
          sudo apt-get install -y gdal-bin
          psql template1 -c "CREATE EXTENSION citext;" -U postgres -h localhost -p 5432
          psql template1 -c "CREATE EXTENSION hstore;" -U postgres -h localhost -p 5432
          psql template1 -c "CREATE EXTENSION postgis;" -U postgres -h localhost -p 5432

      - name: Install uv
        uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
        with:
          python-version: ${{ matrix.python-version }}

      - name: Run tox targets for ${{ matrix.python-version }}
        run: uvx --with tox-uv tox run -e ${TOX_ENV}

      - name: Upload coverage data
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
        with:
          name: coverage-data-${{ env.TOX_ENV }}
          include-hidden-files: true
          path: '.coverage.*'
          if-no-files-found: ignore

  coverage:
    name: Coverage
    runs-on: ubuntu-24.04
    needs: [sqlite-tests, postgresql-tests]
    steps:
      - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
        with:
          persist-credentials: false

      - name: Install uv
        uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
        with:
          python-version: "3.13"

      - name: Download data
        uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
        with:
          pattern: coverage-data-*
          merge-multiple: true

      - name: Combine coverage and fail if it's <95%
        run: uvx --with tox-uv tox run -e coverage-report

      - name: Upload HTML report
        if: ${{ failure() }}
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
        with:
          name: html-report
          path: htmlcov

  docs:
    name: Docs
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
        with:
          persist-credentials: false

      - name: Install uv
        uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
        with:
          python-version: "3.13"

      - name: Build docs
        run: uvx --with tox-uv tox run -e docs-build

The same workflow, on Latchkey

Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.

name: Tests
 
on:
  push:
    branches:
      - main
  pull_request:
 
concurrency:
  group: ${{ github.head_ref || github.run_id }}
  cancel-in-progress: true
 
permissions:
  contents: read
 
jobs:
  linters:
    timeout-minutes: 30
    runs-on: latchkey-small
    strategy:
      matrix:
        lint-command:
          - ruff check --output-format=github .
          - black --check --diff .
          - ty check model_bakery
    steps:
      - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
        with:
          persist-credentials: false
      - name: Install uv
        uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
        with:
          python-version: "3.13"
      - run: uv run --frozen ${{ matrix.lint-command }}
 
  sqlite-tests:
    timeout-minutes: 30
    name: SQLite - Python ${{ matrix.python-version }}, Django ${{ matrix.django-version }}
    runs-on: latchkey-small
    strategy:
      fail-fast: false
      matrix:
        python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
        django-version: ["5.2", "6.0"]
        exclude:
          # Django 6.0 supports Python 3.12+
          - python-version: "3.10"
            django-version: "6.0"
          - python-version: "3.11"
            django-version: "6.0"
 
    steps:
      - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
        with:
          persist-credentials: false
      - name: Set TOX_ENV
        run: echo "TOX_ENV=py$(echo ${{ matrix.python-version }} | tr -d .)-django$(echo ${{ matrix.django-version }} | tr -d .)-sqlite" >> $GITHUB_ENV
 
      - name: Install uv
        uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
        with:
          python-version: ${{ matrix.python-version }}
 
      - name: Run tox targets for ${{ matrix.python-version }}
        run: uvx --with tox-uv tox run -e ${TOX_ENV}
 
      - name: Upload coverage data
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
        with:
          name: coverage-data-${{ env.TOX_ENV }}
          include-hidden-files: true
          path: '.coverage.*'
          if-no-files-found: ignore
 
  postgresql-tests:
    timeout-minutes: 30
    name: PostgreSQL - Python ${{ matrix.python-version }}, Django ${{ matrix.django-version }}, ${{ matrix.variant }}
    runs-on: latchkey-small
    strategy:
      fail-fast: false
      matrix:
        python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
        django-version: ["5.2", "6.0"]
        variant: ["postgresql", "postgresql-psycopg3"]
        exclude:
          # Django 6.0 supports Python 3.12+
          - python-version: "3.10"
            django-version: "6.0"
          - python-version: "3.11"
            django-version: "6.0"
        include:
          # Latest Python/Django with contenttypes disabled
          - python-version: "3.14"
            django-version: "6.0"
            variant: "postgresql-no-contenttypes"
 
    env:
      PGUSER: postgres
      PGPASSWORD: postgres
 
    services:
      postgis:
        image: postgis/postgis:latest@sha256:743c03d986e29c4dc3cba907e6b4477e1a67b9c937ae14f33be4ae9eaf983625
        env:
          POSTGRES_DB: postgres
          POSTGRES_PASSWORD: postgres
          POSTGRES_USER: postgres
        ports:
          - 5432:5432
        options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
 
    steps:
      - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
        with:
          persist-credentials: false
      - name: Set TOX_ENV
        run: echo "TOX_ENV=py$(echo ${{ matrix.python-version }} | tr -d .)-django$(echo ${{ matrix.django-version }} | tr -d .)-${{ matrix.variant }}" >> $GITHUB_ENV
 
      - name: Set up PostgreSQL
        run: |
          sudo apt-get update
          sudo apt-get install -y gdal-bin
          psql template1 -c "CREATE EXTENSION citext;" -U postgres -h localhost -p 5432
          psql template1 -c "CREATE EXTENSION hstore;" -U postgres -h localhost -p 5432
          psql template1 -c "CREATE EXTENSION postgis;" -U postgres -h localhost -p 5432
 
      - name: Install uv
        uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
        with:
          python-version: ${{ matrix.python-version }}
 
      - name: Run tox targets for ${{ matrix.python-version }}
        run: uvx --with tox-uv tox run -e ${TOX_ENV}
 
      - name: Upload coverage data
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
        with:
          name: coverage-data-${{ env.TOX_ENV }}
          include-hidden-files: true
          path: '.coverage.*'
          if-no-files-found: ignore
 
  coverage:
    timeout-minutes: 30
    name: Coverage
    runs-on: latchkey-small
    needs: [sqlite-tests, postgresql-tests]
    steps:
      - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
        with:
          persist-credentials: false
 
      - name: Install uv
        uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
        with:
          python-version: "3.13"
 
      - name: Download data
        uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
        with:
          pattern: coverage-data-*
          merge-multiple: true
 
      - name: Combine coverage and fail if it's <95%
        run: uvx --with tox-uv tox run -e coverage-report
 
      - name: Upload HTML report
        if: ${{ failure() }}
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
        with:
          name: html-report
          path: htmlcov
 
  docs:
    timeout-minutes: 30
    name: Docs
    runs-on: latchkey-small
    steps:
      - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
        with:
          persist-credentials: false
 
      - name: Install uv
        uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
        with:
          python-version: "3.13"
 
      - name: Build docs
        run: uvx --with tox-uv tox run -e docs-build
 

What changed

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:

This workflow runs 5 jobs (35 with the matrix expanded) per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.

Actions used in this workflow