CI workflow (wntrblm/nox)
The CI workflow from wntrblm/nox, explained and optimized by Latchkey.
CI health: C - fair
Point runs-on at Latchkey and get caching, 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 workflow from the wntrblm/nox 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
name: CI
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
# allow manual runs on branches without a PR
env:
FORCE_COLOR: "1"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions: {}
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python-version:
- "3.10"
- "3.12"
- "3.14"
- "3.15"
include:
- os: ubuntu-22.04
python-version: "3.11"
- os: ubuntu-22.04
python-version: "3.13"
- os: macos-15-intel
python-version: "3.12"
steps:
- uses: actions/checkout@v7.0.0
with:
persist-credentials: false
- name: Set up non-default Pythons
uses: actions/setup-python@v6
with:
python-version: |
3.10
3.11
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
- name: Setup uv
uses: astral-sh/setup-uv@v8.2.0
- name: Set up Miniconda
uses: conda-incubator/setup-miniconda@v4
if: matrix.python-version == '3.14'
with:
channels: conda-forge
conda-remove-defaults: true
conda-version: '26.5.2'
activate-environment:
- name: Install Nox-under-test (uv)
run: uv pip install --system .
- name: Run tests on ${{ matrix.os }}
run: nox --session "tests-${{ matrix.python-version }}" -- --durations=10
- name: Run min-version tests on ${{ matrix.os }}
run: nox --session minimums --force-python="${{ matrix.python-version }}" -- --durations=10
- name: Run Conda tests
if: matrix.python-version == '3.14'
run: nox --session "conda_tests" -- --durations=5
- name: Save coverage report
uses: actions/upload-artifact@v7
with:
name: coverage-${{ github.job }}-${{ strategy.job-index }}
path: .coverage.*
include-hidden-files: true
if-no-files-found: error
# No uv CLI exists in any MSYS2 repo (the msys `uv` package only ships the
# uv_build backend), so the uv backend is exercised via the standalone uv
# binary from setup-uv
msys2:
runs-on: windows-latest
continue-on-error: true
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v7.0.0
with:
persist-credentials: false
- uses: msys2/setup-msys2@v2.32.0
with:
msystem: MINGW64
update: true
# Inherit the runner PATH so the standalone uv (added to GITHUB_PATH
# by setup-uv, which runs after this step) is visible to MinGW Python
path-type: inherit
install: >-
mingw-w64-x86_64-python
mingw-w64-x86_64-python-pip
mingw-w64-x86_64-python-virtualenv
mingw-w64-x86_64-gcc
- name: Setup uv
uses: astral-sh/setup-uv@v8.2.0
- name: Install Nox-under-test
run: python -m pip install .
# Force virtualenv so the session venv stays a MinGW interpreter
# (_IS_MINGW=True). uv stays on PATH, so the uv-backend tests still
# build real uv venvs from within MinGW
- name: Run tests under MinGW
run: |
pyver=$(python -c "import sys; print('{}.{}'.format(*sys.version_info))")
echo "MSYS2 MinGW Python: $pyver"
python -c "import shutil; print('uv discovered at:', shutil.which('uv'))"
nox --session "tests-$pyver" --force-venv-backend virtualenv -- --durations=10
- name: Save coverage report
uses: actions/upload-artifact@v7
with:
name: coverage-${{ github.job }}
path: .coverage.*
include-hidden-files: true
if-no-files-found: error
coverage:
needs: [build, msys2]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7.0.0
with:
persist-credentials: false
- name: Set up Python 3.12
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Setup uv
uses: astral-sh/setup-uv@v8.2.0
- name: Install Nox-under-test
run: uv pip install --system .
- name: Download individual coverage reports
uses: actions/download-artifact@v8
with:
pattern: coverage-*
- name: Display structure of downloaded files
run: ls -aR
- name: Run coverage
run: nox --session "cover"
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7.0.0
with:
persist-credentials: false
- name: Set up Python 3.12
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install Nox-under-test
run: python -m pip install --disable-pip-version-check .
- name: Lint
run: nox --session "lint"
docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7.0.0
with:
persist-credentials: false
- name: Set up Python 3.12
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Setup uv
uses: astral-sh/setup-uv@v8.2.0
- name: Install Nox-under-test
run: uv pip install --system .
- name: Docs
run: nox --session "docs"
The same workflow, on Latchkey
Estimated ~20% faster on cache hits, plus fewer wasted runs and a safer supply chain. Added and changed lines are highlighted.
name: CI on: push: branches: [main] pull_request: workflow_dispatch: # allow manual runs on branches without a PR env: FORCE_COLOR: "1" concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true permissions: {} jobs: build: timeout-minutes: 30 runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] python-version: - "3.10" - "3.12" - "3.14" - "3.15" include: - os: ubuntu-22.04 python-version: "3.11" - os: ubuntu-22.04 python-version: "3.13" - os: macos-15-intel python-version: "3.12" steps: - uses: actions/checkout@v7.0.0 with: persist-credentials: false - name: Set up non-default Pythons uses: actions/setup-python@v6 with: cache: 'pip' python-version: | 3.10 3.11 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v6 with: cache: 'pip' python-version: ${{ matrix.python-version }} allow-prereleases: true - name: Setup uv uses: astral-sh/setup-uv@v8.2.0 - name: Set up Miniconda uses: conda-incubator/setup-miniconda@v4 if: matrix.python-version == '3.14' with: channels: conda-forge conda-remove-defaults: true conda-version: '26.5.2' activate-environment: - name: Install Nox-under-test (uv) run: uv pip install --system . - name: Run tests on ${{ matrix.os }} run: nox --session "tests-${{ matrix.python-version }}" -- --durations=10 - name: Run min-version tests on ${{ matrix.os }} run: nox --session minimums --force-python="${{ matrix.python-version }}" -- --durations=10 - name: Run Conda tests if: matrix.python-version == '3.14' run: nox --session "conda_tests" -- --durations=5 - name: Save coverage report uses: actions/upload-artifact@v7 with: name: coverage-${{ github.job }}-${{ strategy.job-index }} path: .coverage.* include-hidden-files: true if-no-files-found: error # No uv CLI exists in any MSYS2 repo (the msys `uv` package only ships the # uv_build backend), so the uv backend is exercised via the standalone uv # binary from setup-uv msys2: timeout-minutes: 30 runs-on: windows-latest continue-on-error: true defaults: run: shell: msys2 {0} steps: - uses: actions/checkout@v7.0.0 with: persist-credentials: false - uses: msys2/setup-msys2@v2.32.0 with: msystem: MINGW64 update: true # Inherit the runner PATH so the standalone uv (added to GITHUB_PATH # by setup-uv, which runs after this step) is visible to MinGW Python path-type: inherit install: >- mingw-w64-x86_64-python mingw-w64-x86_64-python-pip mingw-w64-x86_64-python-virtualenv mingw-w64-x86_64-gcc - name: Setup uv uses: astral-sh/setup-uv@v8.2.0 - name: Install Nox-under-test run: python -m pip install . # Force virtualenv so the session venv stays a MinGW interpreter # (_IS_MINGW=True). uv stays on PATH, so the uv-backend tests still # build real uv venvs from within MinGW - name: Run tests under MinGW run: | pyver=$(python -c "import sys; print('{}.{}'.format(*sys.version_info))") echo "MSYS2 MinGW Python: $pyver" python -c "import shutil; print('uv discovered at:', shutil.which('uv'))" nox --session "tests-$pyver" --force-venv-backend virtualenv -- --durations=10 - name: Save coverage report uses: actions/upload-artifact@v7 with: name: coverage-${{ github.job }} path: .coverage.* include-hidden-files: true if-no-files-found: error coverage: timeout-minutes: 30 needs: [build, msys2] runs-on: latchkey-small steps: - uses: actions/checkout@v7.0.0 with: persist-credentials: false - name: Set up Python 3.12 uses: actions/setup-python@v6 with: cache: 'pip' python-version: "3.12" - name: Setup uv uses: astral-sh/setup-uv@v8.2.0 - name: Install Nox-under-test run: uv pip install --system . - name: Download individual coverage reports uses: actions/download-artifact@v8 with: pattern: coverage-* - name: Display structure of downloaded files run: ls -aR - name: Run coverage run: nox --session "cover" lint: timeout-minutes: 30 runs-on: latchkey-small steps: - uses: actions/checkout@v7.0.0 with: persist-credentials: false - name: Set up Python 3.12 uses: actions/setup-python@v6 with: cache: 'pip' python-version: "3.12" - name: Install Nox-under-test run: python -m pip install --disable-pip-version-check . - name: Lint run: nox --session "lint" docs: timeout-minutes: 30 runs-on: latchkey-small steps: - uses: actions/checkout@v7.0.0 with: persist-credentials: false - name: Set up Python 3.12 uses: actions/setup-python@v6 with: cache: 'pip' python-version: "3.12" - name: Setup uv uses: astral-sh/setup-uv@v8.2.0 - name: Install Nox-under-test run: uv pip install --system . - name: Docs run: nox --session "docs"
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. - Cache dependency installs on the setup step so they are served from cache.
- Add a job timeout so a hung step cannot burn hours of runner time.
3 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 5 jobs (16 with the matrix expanded) per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.