# tests workflow (pypa/setuptools)

> The tests workflow from pypa/setuptools, explained and optimized by Latchkey.

Source: https://latchkey.dev/workflows/pypa-setuptools-main  
Upstream: [pypa/setuptools](https://github.com/pypa/setuptools/blob/main/.github/workflows/main.yml) (.github/workflows/main.yml), licence MIT

## What it does

This is the tests workflow from the pypa/setuptools 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

```yaml
name: tests

on:
  merge_group:
  push:
    branches-ignore:
    # temporary GH branches relating to merge queues (jaraco/skeleton#93)
    - gh-readonly-queue/**
    tags:
    # required if branches-ignore is supplied (jaraco/skeleton#103)
    - '**'
  pull_request:
  workflow_dispatch:

concurrency:
  group: >-
    ${{ github.workflow }}-
    ${{ github.ref_type }}-
    ${{ github.event.pull_request.number || github.sha }}
  cancel-in-progress: true

permissions:
  contents: read

env:
  # Environment variable to support color support (jaraco/skeleton#66)
  FORCE_COLOR: 1

  # Suppress noisy pip warnings
  PIP_DISABLE_PIP_VERSION_CHECK: 'true'
  PIP_NO_WARN_SCRIPT_LOCATION: 'true'

  # Ensure tests can sense settings about the environment
  TOX_OVERRIDE: >-
    testenv.pass_env+=GITHUB_*,FORCE_COLOR


jobs:
  test:
    strategy:
      # https://blog.jaraco.com/efficient-use-of-ci-resources/
      matrix:
        python:
        - "3.10"
        - "3.14"
        - "3.14t"
        platform:
        - ubuntu-latest
        - macos-latest
        - windows-latest
        include:
        - python: "3.11"
          platform: ubuntu-latest
        - python: "3.12"
          platform: ubuntu-latest
        - python: "3.13"
          platform: ubuntu-latest
        # Disabled: cffi (required by PyNaCl) doesn't support free-threaded CPython 3.13t.
        # - python: "3.13t"
        #   platform: ubuntu-latest
        - python: "3.15"
          platform: ubuntu-latest
        - python: pypy3.11
          platform: ubuntu-latest
          distutils: stdlib
        - platform: ubuntu-latest
          python: "3.10"
          distutils: stdlib
    runs-on: ${{ matrix.platform }}
    continue-on-error: ${{ matrix.python == '3.15' || matrix.python == 'pypy3.11' }}
    # XXX: pypy seems to be flaky with unrelated tests in #6345
    env:
      SETUPTOOLS_USE_DISTUTILS: ${{ matrix.distutils || 'local' }}
    timeout-minutes: 75
    steps:
      - uses: actions/checkout@v4
      - name: Install build dependencies
        # Install dependencies for building packages on pre-release Pythons
        # jaraco/skeleton#161
        if: matrix.python == '3.15' && matrix.platform == 'ubuntu-latest'
        run: |
          sudo apt update
          sudo apt install -y libxml2-dev libxslt-dev
      - name: Setup Python
        id: python-install
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python }}
          allow-prereleases: true
        # Workaround for actions/setup-python#981 on macos
        # Workaround for https://github.com/pypa/setuptools/issues/5143 on windows
        # (env var only modified for this specific step)
        env:
          SETUPTOOLS_USE_DISTUTILS: >-
            ${{
              (
                ( matrix.platform == 'macos-latest' || matrix.platform == 'windows-latest' )
                && matrix.python == '3.9'
                && 'stdlib'
              )
              || matrix.distutils
              || 'local'
            }}
      - uses: actions/cache@v4
        id: cache
        with:
          path: setuptools/tests/config/downloads/*.cfg
          key: >-
            ${{ hashFiles('setuptools/tests/config/setupcfg_examples.txt') }}-
            ${{ hashFiles('setuptools/tests/config/downloads/*.py') }}
      - name: Populate download cache
        if: steps.cache.outputs.cache-hit != 'true'
        working-directory: setuptools/tests/config
        run: python -m downloads.preload setupcfg_examples.txt
      - name: Adjust env vars
        shell: bash
        run: |
          echo 'PIPX_DEFAULT_PYTHON=${{ steps.python-install.outputs.python-path }}' >> $GITHUB_ENV
      - name: Pre-build distributions for test
        shell: bash
        run: |
          rm -rf dist
          # workaround for pypa/setuptools#4333
          pipx run --pip-args 'pyproject-hooks!=1.1' build
          echo "PRE_BUILT_SETUPTOOLS_SDIST=$(ls dist/*.tar.gz)" >> $GITHUB_ENV
          echo "PRE_BUILT_SETUPTOOLS_WHEEL=$(ls dist/*.whl)" >> $GITHUB_ENV
          rm -rf setuptools.egg-info  # Avoid interfering with the other tests
      - name: Workaround for unreleased PyNaCl (pyca/pynacl#805)
        if: contains(matrix.python, 'pypy')
        run: echo "SETUPTOOLS_ENFORCE_DEPRECATION=0" >> $GITHUB_ENV
      - name: Install tox
        run: python -m pip install tox
      - name: Run
        run: tox
      - name: Create coverage report
        if: hashFiles('.coverage') != ''  # Rudimentary `file.exists()`
        run: pipx run coverage xml --ignore-errors
      - name: Publish coverage
        if: hashFiles('coverage.xml') != ''  # Rudimentary `file.exists()`
        uses: codecov/codecov-action@v4
        with:
          flags: >-  # Mark which lines are covered by which envs
            CI-GHA,
            ${{ github.job }},
            OS-${{ runner.os }},
            VM-${{ matrix.platform }},
            Py-${{ steps.python-install.outputs.python-version }}
          token: ${{ secrets.CODECOV_TOKEN }}

  collateral:
    strategy:
      fail-fast: false
      matrix:
        job:
        - diffcov
        - docs
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: 3.x
      - name: Install tox
        run: python -m pip install tox
      - name: Eval ${{ matrix.job }}
        run: tox -e ${{ matrix.job }}

  check:  # This job does nothing and is only used for the branch protection
    if: always()

    needs:
    - check-changed-folders
    - integration-test
    - test
    - collateral
    - test_cygwin

    runs-on: ubuntu-latest

    steps:
    - name: Decide whether the needed jobs succeeded or failed
      uses: re-actors/alls-green@release/v1
      with:
        allowed-skips: check-changed-folders, integration-test
        jobs: ${{ toJSON(needs) }}

  test_cygwin:
    strategy:
      matrix:
        python:
        - 312
        platform:
        - windows-latest
    runs-on: ${{ matrix.platform }}
    timeout-minutes: 75
    steps:
      - uses: actions/checkout@v4
      - name: Install Cygwin with Python
        uses: cygwin/cygwin-install-action@v4
        with:
          platform: x86_64
          packages: >-
            python${{ matrix.python }},
            python${{ matrix.python }}-devel,
            python${{ matrix.python }}-pip,
            gcc-core,
            git,
      - name: Record the currently selected Python version
        id: python-install
        # NOTE: This roughly emulates what `actions/setup-python` provides
        # NOTE: except the action gets the version from the installation path
        # NOTE: on disk and we get it from runtime.
        run: |
          python -c 'import platform; print("python-version=" + platform.python_version())' >> ${GITHUB_OUTPUT}
        shell: C:\cygwin\bin\env.exe CYGWIN_NOWINPATH=1 CHERE_INVOKING=1 C:\cygwin\bin\bash.exe -leo pipefail -o igncr {0}
      - name: Install tox using pip
        shell: C:\cygwin\bin\env.exe CYGWIN_NOWINPATH=1 CHERE_INVOKING=1 C:\cygwin\bin\bash.exe -leo pipefail -o igncr {0}
        run: |
          # Workaround for https://github.com/pypa/setuptools/issues/4831
          python -m pip install tox
      - name: Run tests
        shell: C:\cygwin\bin\env.exe CYGWIN_NOWINPATH=1 CHERE_INVOKING=1 C:\cygwin\bin\bash.exe -leo pipefail -o igncr {0}
        run: |
          git config --global --add safe.directory "$(cygpath -u "${{ github.workspace }}")" # workaround for #3408
          echo "$(cygpath -u "${{ github.workspace }}")" # for debugging purposes
          python -m tox
      - name: Create coverage report
        if: hashFiles('.coverage') != ''  # Rudimentary `file.exists()`
        run: |
          python -m pip install coverage
          python -m coverage xml --ignore-errors
        shell: C:\cygwin\bin\env.exe CYGWIN_NOWINPATH=1 CHERE_INVOKING=1 C:\cygwin\bin\bash.exe -leo pipefail -o igncr {0}
      - name: Publish coverage
        if: hashFiles('coverage.xml') != ''  # Rudimentary `file.exists()`
        uses: codecov/codecov-action@v4
        with:
          flags: >-  # Mark which lines are covered by which envs
            CI-GHA,
            ${{ github.job }},
            OS-${{ runner.os }},
            VM-${{ matrix.platform }},
            Py-${{ steps.python-install.outputs.python-version }}
          token: ${{ secrets.CODECOV_TOKEN }}

  check-changed-folders:
    name: Fail the job if files changed under _disutils/_vendor folders
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
        with:
          fetch-depth: 0
      - name: Check if files changed in the _distutils folder
        id: changed-files-specific-distutils
        uses: tj-actions/changed-files@v46
        with:
          files: |
            setuptools/_distutils/**
      - name: Check if files changed in the _vendor folder
        id: changed-files-specific-vendor
        uses: tj-actions/changed-files@v46
        with:
          files: |
            setuptools/_vendor/**
      - name: Fail the job if any file(s) in the _distutils folder change
        if: steps.changed-files-specific-distutils.outputs.any_changed == 'true'
        run: |
          echo "One or more files in the setuptools/_distutils folder has changed." | tee "${GITHUB_STEP_SUMMARY}"
          exit 1      
      - name: Fail the job if any file(s) in the _vendor folder change
        if: steps.changed-files-specific-vendor.outputs.any_changed == 'true'
        run: |
          echo "One or more files in the setuptools/_vendor folder has changed." | tee "${GITHUB_STEP_SUMMARY}"
          exit 1 

  integration-test:
    needs: test
    if: github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && contains(github.ref, 'refs/tags/'))
    # To avoid long times and high resource usage, we assume that:
    # 1. The setuptools APIs used by packages don't vary too much with OS or
    #    Python implementation
    # 2. Any circumstance for which the previous assumption is not valid is
    #    already tested via unit tests (or other tests not classified here as
    #    "integration")
    # With that in mind, the integration tests can run for a single setup
    runs-on: ubuntu-latest
    timeout-minutes: 75
    steps:
      - uses: actions/checkout@v4
      - name: Install OS-level dependencies
        run: |
          sudo apt-get update
          sudo apt-get install build-essential gfortran libopenblas-dev libyaml-dev
      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          # Use a release that is not very new but still have a long life:
          python-version: "3.10"
      - name: Install tox
        run: |
          python -m pip install tox
      - name: Run integration tests
        run: tox -e integration

  release:
    permissions:
      contents: write
    needs:
    - check
    if: >-  # `always()` prevents auto-cancellation when previous steps are skipped (#5151):
      always()
      && needs.check.result == 'success'
      && github.event_name == 'push' && github.ref_type == 'tag'
    runs-on: ubuntu-latest
    timeout-minutes: 75
    steps:
      - uses: actions/checkout@v4
      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: 3.x
      - name: Install tox
        run: python -m pip install tox
      - name: Run
        run: tox -e release
        env:
          TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

## FAQ

### What does the tests workflow (pypa/setuptools) workflow do?

This is the tests workflow from the pypa/setuptools repository, a real project running GitHub Actions. It is shown here with attribution under its MIT license.

### What CI health grade does this workflow get?

This Python workflow grades C. Paste your own workflow into the Latchkey grader to see its grade and the exact fixes.

### How can I improve this Python workflow?

Add caching and job timeouts. Latchkey applies these automatically on managed runners when you point runs-on at Latchkey.

---

Latchkey runs CI/CD that repairs its own failures. Agent entry points: https://latchkey.dev/agent.txt, https://latchkey.dev/openapi.json, https://latchkey.dev/llms.txt
