test suite workflow (agronholm/anyio)
The test suite workflow from agronholm/anyio, explained and optimized by Latchkey.
CI health: F - at risk
Point runs-on at Latchkey and get caching, 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 test suite workflow from the agronholm/anyio 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: test suite
on:
push:
branches: [master]
pull_request:
jobs:
changed-files:
runs-on: ubuntu-latest
outputs:
workflow-changed: ${{ steps.changed-files.outputs.workflow_any_changed }}
pyproject-changed: ${{ steps.changed-files.outputs.src_any_changed }}
src-changed: ${{ steps.changed-files.outputs.src_any_changed }}
tests-changed: ${{ steps.changed-files.outputs.tests_any_changed }}
docs-changed: ${{ steps.changed-files.outputs.doc_any_changed }}
steps:
- uses: actions/checkout@v7
- name: Get changed files by category
id: changed-files
uses: tj-actions/changed-files@v47
with:
files_yaml: |
workflow:
- .github/workflows/test.yml
pyproject:
- pyproject.toml
src:
- src/**
tests:
- tests/**
doc:
- README.rst
- docs/**
pyright:
runs-on: ubuntu-latest
needs: changed-files
if: |
${{
(needs.changed-files.outputs.workflow-changed == 'true')
|| (needs.changed-files.outputs.src-changed == 'true')
}}
steps:
- uses: actions/checkout@v7
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: 3.x
- uses: actions/cache@v6
with:
path: ~/.cache/pip
key: pip-pyright
- name: Install dependencies
run: pip install -e . pyright
- name: Run pyright
run: pyright --ignoreexternal --verifytypes anyio
test:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14", "3.15", "pypy3.11-v7.3.23"]
extras: ["[trio]"]
lowest-bound: [false]
include:
- os: macos-latest
python-version: "3.10"
extras: "[trio]"
- os: macos-latest
python-version: "3.14"
extras: "[trio]"
- os: windows-latest
python-version: "3.10"
extras: "[trio]"
- os: windows-latest
python-version: "3.14"
extras: "[trio]"
- name: only asyncio
os: ubuntu-latest
python-version: "3.14"
extras: ""
- name: oldest dependencies
os: ubuntu-latest
python-version: "3.10"
extras: "[trio]"
lowest-bound: true
runs-on: ${{ matrix.os }}
needs: changed-files
if: |
${{
(needs.changed-files.outputs.workflow-changed == 'true')
|| (needs.changed-files.outputs.pyproject-changed == 'true')
|| (needs.changed-files.outputs.src-changed == 'true')
|| (needs.changed-files.outputs.tests-changed == 'true')
}}
steps:
- uses: actions/checkout@v7
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
cache: pip
cache-dependency-path: pyproject.toml
- name: Install the project and its dependencies
if: matrix.lowest-bound == false
run: pip install --group test -e .${{ matrix.extras }}
- name: Install the project and its dependencies (lowest bound)
if: matrix.lowest-bound == true
run: |
pip install uv
uv pip install --system --resolution lowest-direct --group test -e .${{ matrix.extras }}
- name: Patch /etc/hosts
if: runner.os != 'Windows'
run: |
echo "1.2.3.4 xn--fa-hia.de" | sudo tee -a /etc/hosts
echo "5.6.7.8 fass.de" | sudo tee -a /etc/hosts
- name: Patch C:\Windows\System32\drivers\etc\hosts
if: runner.os == 'Windows'
run: |
Add-Content -Path C:\Windows\System32\drivers\etc\hosts -Value "1.2.3.4 xn--fa-hia.de"
Add-Content -Path C:\Windows\System32\drivers\etc\hosts -Value "5.6.7.8 fass.de"
- name: Test with pytest
run: coverage run -m pytest -v
timeout-minutes: 10
env:
PYTEST_DISABLE_PLUGIN_AUTOLOAD: 1
- name: Generate coverage report
run: coverage xml
- name: Trust Coveralls Homebrew tap (Homebrew 6 requirement)
if: runner.os == 'macOS'
run: brew trust coverallsapp/coveralls
- name: Upload Coverage
uses: coverallsapp/github-action@v2
with:
parallel: true
file: coverage.xml
docs:
runs-on: ubuntu-latest
needs: changed-files
if: |
${{
(needs.changed-files.outputs.workflow-changed == 'true')
|| (needs.changed-files.outputs.pyproject-changed == 'true')
|| (needs.changed-files.outputs.src-changed == 'true')
|| (needs.changed-files.outputs.docs-changed == 'true')
}}
steps:
- uses: actions/checkout@v7
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
with:
python-version: "3.11"
cache: pip
cache-dependency-path: pyproject.toml
- name: Install the project and its dependencies
run: pip install --group doc -e .
- name: Build documentation
run: sphinx-build -W docs build/sphinx
coveralls:
name: Finish Coveralls
needs: test
runs-on: ubuntu-latest
steps:
- name: Finished
uses: coverallsapp/github-action@v2
with:
parallel-finished: true
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: test suite on: push: branches: [master] pull_request: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: changed-files: timeout-minutes: 30 runs-on: latchkey-small outputs: workflow-changed: ${{ steps.changed-files.outputs.workflow_any_changed }} pyproject-changed: ${{ steps.changed-files.outputs.src_any_changed }} src-changed: ${{ steps.changed-files.outputs.src_any_changed }} tests-changed: ${{ steps.changed-files.outputs.tests_any_changed }} docs-changed: ${{ steps.changed-files.outputs.doc_any_changed }} steps: - uses: actions/checkout@v7 - name: Get changed files by category id: changed-files uses: tj-actions/changed-files@v47 with: files_yaml: | workflow: - .github/workflows/test.yml pyproject: - pyproject.toml src: - src/** tests: - tests/** doc: - README.rst - docs/** pyright: timeout-minutes: 30 runs-on: latchkey-small needs: changed-files if: | ${{ (needs.changed-files.outputs.workflow-changed == 'true') || (needs.changed-files.outputs.src-changed == 'true') }} steps: - uses: actions/checkout@v7 - name: Set up Python uses: actions/setup-python@v6 with: cache: 'pip' python-version: 3.x - uses: actions/cache@v6 with: path: ~/.cache/pip key: pip-pyright - name: Install dependencies run: pip install -e . pyright - name: Run pyright run: pyright --ignoreexternal --verifytypes anyio test: timeout-minutes: 30 strategy: fail-fast: false matrix: os: [ubuntu-latest] python-version: ["3.10", "3.11", "3.12", "3.13", "3.14", "3.15", "pypy3.11-v7.3.23"] extras: ["[trio]"] lowest-bound: [false] include: - os: macos-latest python-version: "3.10" extras: "[trio]" - os: macos-latest python-version: "3.14" extras: "[trio]" - os: windows-latest python-version: "3.10" extras: "[trio]" - os: windows-latest python-version: "3.14" extras: "[trio]" - name: only asyncio os: ubuntu-latest python-version: "3.14" extras: "" - name: oldest dependencies os: ubuntu-latest python-version: "3.10" extras: "[trio]" lowest-bound: true runs-on: ${{ matrix.os }} needs: changed-files if: | ${{ (needs.changed-files.outputs.workflow-changed == 'true') || (needs.changed-files.outputs.pyproject-changed == 'true') || (needs.changed-files.outputs.src-changed == 'true') || (needs.changed-files.outputs.tests-changed == 'true') }} steps: - uses: actions/checkout@v7 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} allow-prereleases: true cache: pip cache-dependency-path: pyproject.toml - name: Install the project and its dependencies if: matrix.lowest-bound == false run: pip install --group test -e .${{ matrix.extras }} - name: Install the project and its dependencies (lowest bound) if: matrix.lowest-bound == true run: | pip install uv uv pip install --system --resolution lowest-direct --group test -e .${{ matrix.extras }} - name: Patch /etc/hosts if: runner.os != 'Windows' run: | echo "1.2.3.4 xn--fa-hia.de" | sudo tee -a /etc/hosts echo "5.6.7.8 fass.de" | sudo tee -a /etc/hosts - name: Patch C:\Windows\System32\drivers\etc\hosts if: runner.os == 'Windows' run: | Add-Content -Path C:\Windows\System32\drivers\etc\hosts -Value "1.2.3.4 xn--fa-hia.de" Add-Content -Path C:\Windows\System32\drivers\etc\hosts -Value "5.6.7.8 fass.de" - name: Test with pytest run: coverage run -m pytest -v timeout-minutes: 10 env: PYTEST_DISABLE_PLUGIN_AUTOLOAD: 1 - name: Generate coverage report run: coverage xml - name: Trust Coveralls Homebrew tap (Homebrew 6 requirement) if: runner.os == 'macOS' run: brew trust coverallsapp/coveralls - name: Upload Coverage uses: coverallsapp/github-action@v2 with: parallel: true file: coverage.xml docs: timeout-minutes: 30 runs-on: latchkey-small needs: changed-files if: | ${{ (needs.changed-files.outputs.workflow-changed == 'true') || (needs.changed-files.outputs.pyproject-changed == 'true') || (needs.changed-files.outputs.src-changed == 'true') || (needs.changed-files.outputs.docs-changed == 'true') }} steps: - uses: actions/checkout@v7 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v6 with: python-version: "3.11" cache: pip cache-dependency-path: pyproject.toml - name: Install the project and its dependencies run: pip install --group doc -e . - name: Build documentation run: sphinx-build -W docs build/sphinx coveralls: timeout-minutes: 30 name: Finish Coveralls needs: test runs-on: latchkey-small steps: - name: Finished uses: coverallsapp/github-action@v2 with: parallel-finished: true
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.
- 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.
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 5 jobs (11 with the matrix expanded) per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.