Package workflow (libtcod/python-tcod)
The Package workflow from libtcod/python-tcod, explained and optimized by Latchkey.
CI health: B - good
Point runs-on at Latchkey and get caching, SHA-pinned actions, self-healing for flaky steps, and up to 58% lower cost, applied automatically.
What it does
This is the Package workflow from the libtcod/python-tcod repository, a real project running GitHub Actions. It is shown here with attribution under its BSD-2-Clause license.
Below, Latchkey shows a faster, safer version produced by its optimization engine.
The workflow
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
name: Package
on:
workflow_dispatch:
push:
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
defaults:
run:
shell: bash
env:
git-depth: 0 # Depth to search for tags.
sdl-version: "3.2.16" # SDL version to bundle
jobs:
ruff:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- name: Install Ruff
run: pip install ruff
- name: Ruff Check
run: ruff check . --fix-only --exit-non-zero-on-fix --output-format=github
- name: Ruff Format
run: ruff format . --check
mypy:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- name: Checkout submodules
run: git submodule update --init --recursive --depth 1
- name: Install typing dependencies
run: pip install mypy pytest -r requirements.txt
- name: Mypy
run: mypy
sdist:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: libsdl-org/setup-sdl@1894460666e4fe0c6603ea0cce5733f1cca56ba1
with:
install-linux-dependencies: true
build-type: "Debug"
version: ${{ env.sdl-version }}
- uses: actions/checkout@v7
with:
persist-credentials: false
fetch-depth: ${{ env.git-depth }}
- name: Checkout submodules
run: git submodule update --init --recursive --depth 1
- name: Install build
run: pip install build
- name: Build source distribution
run: python -m build --sdist
- uses: actions/upload-artifact@v7
with:
name: sdist
path: dist/tcod-*.tar.gz
retention-days: 7
compression-level: 0
# This makes sure that the latest versions of the SDL headers parse correctly.
parse_sdl:
needs: [ruff, mypy]
runs-on: ${{ matrix.os }}
timeout-minutes: 5
strategy:
matrix:
os: ["windows-latest", "macos-latest"]
sdl-version: ["3.2.16"]
fail-fast: true
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
fetch-depth: ${{ env.git-depth }}
- name: Checkout submodules
run: git submodule update --init --recursive --depth 1
- uses: actions/setup-python@v6
with:
python-version: "3.x"
- name: Install build dependencies
run: pip install -r requirements.txt
- name: Test SDL parsing
run: python build_sdl.py
env:
SDL_VERSION: ${{ matrix.sdl-version }}
build:
needs: [ruff, mypy, sdist]
runs-on: ${{ matrix.os }}
timeout-minutes: 15
strategy:
matrix:
os: ["ubuntu-latest", "windows-latest"]
python-version: ["3.10", "3.14t", "pypy-3.10"]
architecture: ["x64"]
include:
- os: "windows-latest"
python-version: "3.10"
architecture: "x86"
- os: "windows-latest"
python-version: "3.14t"
architecture: "x86"
- os: "windows-11-arm"
python-version: "3.11"
architecture: "arm64"
- os: "windows-11-arm"
python-version: "3.14t"
architecture: "arm64"
fail-fast: false
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
fetch-depth: ${{ env.git-depth }}
- name: Checkout submodules
run: git submodule update --init --recursive --depth 1
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
architecture: ${{ matrix.architecture }}
- name: Install APT dependencies
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install xvfb
- uses: libsdl-org/setup-sdl@1894460666e4fe0c6603ea0cce5733f1cca56ba1
if: runner.os == 'Linux'
with:
install-linux-dependencies: true
build-type: "Release"
version: ${{ env.sdl-version }}
- name: Install Python dependencies
run: |
python -m pip install --upgrade pip
pip install pytest pytest-cov pytest-benchmark pytest-timeout build
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Initialize package
run: pip install -e . # Install the package in-place.
- name: Build package
run: python -m build
- name: Test with pytest
if: runner.os == 'Windows'
run: pytest --cov-report=xml --timeout=300
- name: Test with pytest (Xvfb)
if: always() && runner.os != 'Windows'
run: xvfb-run -e /tmp/xvfb.log --server-num=$RANDOM --auto-servernum pytest --cov-report=xml --timeout=300
- name: Xvfb logs
if: runner.os != 'Windows'
run: cat /tmp/xvfb.log
- uses: codecov/codecov-action@v7
- uses: actions/upload-artifact@v7
if: runner.os == 'Windows'
with:
name: wheels-windows-${{ matrix.architecture }}-${{ matrix.python-version }}
path: dist/*.whl
retention-days: 7
compression-level: 0
test-docs:
needs: [ruff, mypy, sdist]
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: libsdl-org/setup-sdl@1894460666e4fe0c6603ea0cce5733f1cca56ba1
if: runner.os == 'Linux'
with:
install-linux-dependencies: true
build-type: "Debug"
version: ${{ env.sdl-version }}
- uses: actions/checkout@v7
with:
persist-credentials: false
fetch-depth: ${{ env.git-depth }}
- name: Checkout submodules
run: git submodule update --init --recursive --depth 1
- name: Install Python dependencies
run: |
python -m pip install --upgrade pip
pip install -r docs/requirements.txt
- name: Install package
run: pip install -e .
env:
TDL_BUILD: DEBUG
- name: Test doc generation
working-directory: docs
run: python -m sphinx -T -E -W --keep-going . _build/html
tox:
needs: [ruff, sdist]
runs-on: ${{ matrix.os }}
timeout-minutes: 15
strategy:
matrix:
os: ["ubuntu-latest"] # "windows-latest" disabled due to free-threaded build issues
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
fetch-depth: ${{ env.git-depth }}
- name: Checkout submodules
run: git submodule update --init --depth 1
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.x"
- name: Install Python dependencies
run: |
python -m pip install --upgrade pip tox
- uses: libsdl-org/setup-sdl@1894460666e4fe0c6603ea0cce5733f1cca56ba1
if: runner.os == 'Linux'
with:
install-linux-dependencies: true
build-type: "Debug"
version: ${{ env.sdl-version }}
- name: Run tox
run: |
tox -vv
linux-wheels:
needs: [ruff, mypy, sdist]
runs-on: ${{ matrix.arch == 'aarch64' && 'ubuntu-24.04-arm' || 'ubuntu-latest'}}
timeout-minutes: 15
strategy:
matrix:
arch: ["x86_64", "aarch64"]
build: ["cp310-manylinux*", "pp311-manylinux*", "cp314t-manylinux*"]
env:
BUILD_DESC: ""
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
fetch-depth: ${{ env.git-depth }}
- name: Checkout submodules
run: git submodule update --init --recursive --depth 1
- name: Build wheels
uses: pypa/cibuildwheel@v4.0.0rc1
env:
CIBW_BUILD: ${{ matrix.build }}
CIBW_ARCHS_LINUX: ${{ matrix.arch }}
CIBW_MANYLINUX_*_IMAGE: manylinux2014
CIBW_MANYLINUX_PYPY_X86_64_IMAGE: manylinux2014
CIBW_MANYLINUX_PYPY_AARCH64_IMAGE: manylinux2014
CIBW_BEFORE_ALL_LINUX: >
yum install -y epel-release &&
yum-config-manager --enable epel &&
yum install -y gcc git-core make cmake \
alsa-lib-devel pulseaudio-libs-devel \
libX11-devel libXext-devel libXrandr-devel libXcursor-devel libXfixes-devel \
libXi-devel libXScrnSaver-devel dbus-devel ibus-devel \
systemd-devel mesa-libGL-devel libxkbcommon-devel mesa-libGLES-devel \
mesa-libEGL-devel vulkan-devel wayland-devel wayland-protocols-devel \
libdrm-devel mesa-libgbm-devel libusb-devel
git clone --depth 1 --branch release-${{env.sdl-version}} https://github.com/libsdl-org/SDL.git sdl_repo &&
cmake -S sdl_repo -B sdl_build &&
cmake --build sdl_build --config Release &&
cmake --install sdl_build --config Release --prefix /usr/local &&
cp --verbose /usr/local/lib64/pkgconfig/sdl3.pc /lib64/pkgconfig/sdl3.pc
CIBW_BEFORE_TEST: pip install numpy
CIBW_TEST_COMMAND: python -c "import tcod.context"
# Skip test on emulated architectures
CIBW_TEST_SKIP: "*_aarch64"
- name: Remove asterisk from label
env:
BUILD_DESC: ${{ matrix.build }}
run: |
BUILD_DESC=${BUILD_DESC//\*}
echo BUILD_DESC=${BUILD_DESC} >> $GITHUB_ENV
- name: Archive wheel
uses: actions/upload-artifact@v7
with:
name: wheels-linux-${{ matrix.arch }}-${{ env.BUILD_DESC }}
path: wheelhouse/*.whl
retention-days: 7
compression-level: 0
build-macos:
needs: [ruff, mypy, sdist]
runs-on: "macos-14"
timeout-minutes: 15
strategy:
fail-fast: true
matrix:
python: ["cp310-*_universal2", "cp314t-*_universal2", "pp311-*"]
env:
PYTHON_DESC: ""
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
fetch-depth: ${{ env.git-depth }}
- name: Checkout submodules
run: git submodule update --init --recursive --depth 1
- uses: actions/setup-python@v6
with:
python-version: "3.x"
- name: Install Python dependencies
run: pip install -r requirements.txt
- name: Prepare package
# Downloads SDL for the later step.
run: python build_sdl.py
- name: Build wheels
uses: pypa/cibuildwheel@v4.0.0rc1
env:
CIBW_BUILD: ${{ matrix.python }}
CIBW_ARCHS_MACOS: x86_64 arm64 universal2
CIBW_BEFORE_BUILD_MACOS: pip install --upgrade delocate
CIBW_BEFORE_TEST: pip install numpy
CIBW_TEST_COMMAND: python -c "import tcod.context"
CIBW_TEST_SKIP: "pp* *-macosx_arm64 *-macosx_universal2:arm64"
MACOSX_DEPLOYMENT_TARGET: "10.13"
- name: Remove asterisk from label
env:
PYTHON_DESC: ${{ matrix.python }}
run: |
PYTHON_DESC=${PYTHON_DESC//\*/X}
echo PYTHON_DESC=${PYTHON_DESC} >> $GITHUB_ENV
- name: Archive wheel
uses: actions/upload-artifact@v7
with:
name: wheels-macos-${{ env.PYTHON_DESC }}
path: wheelhouse/*.whl
retention-days: 7
compression-level: 0
pyodide:
needs: [ruff, mypy, sdist]
runs-on: ubuntu-24.04
timeout-minutes: 15
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
fetch-depth: ${{ env.git-depth }}
- name: Checkout submodules
run: git submodule update --init --recursive --depth 1
- uses: libsdl-org/setup-sdl@1894460666e4fe0c6603ea0cce5733f1cca56ba1
with:
install-linux-dependencies: true
build-type: "Debug"
version: "3.2.4" # Should be equal or less than the version used by Emscripten
- uses: pypa/cibuildwheel@v4.0.0rc1
env:
CIBW_BUILD: cp313-pyodide_wasm32
CIBW_PLATFORM: pyodide
- name: Archive wheel
uses: actions/upload-artifact@v7
with:
name: wheels-pyodide
path: wheelhouse/*.whl
retention-days: 30
compression-level: 0
publish:
needs: [sdist, build, build-macos, linux-wheels, pyodide]
runs-on: ubuntu-latest
timeout-minutes: 5
if: github.ref_type == 'tag'
environment:
name: pypi
url: https://pypi.org/project/tcod/${{ github.ref_name }}
permissions:
id-token: write # Attestation
steps:
- uses: actions/download-artifact@v8
with:
name: sdist
path: dist/
- uses: actions/download-artifact@v8
with:
pattern: wheels-*
path: dist/
merge-multiple: true
- uses: pypa/gh-action-pypi-publish@release/v1
with:
skip-existing: 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.
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions name: Package on: workflow_dispatch: push: pull_request: concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true defaults: run: shell: bash env: git-depth: 0 # Depth to search for tags. sdl-version: "3.2.16" # SDL version to bundle jobs: ruff: runs-on: latchkey-small timeout-minutes: 5 steps: - uses: actions/checkout@v7 with: persist-credentials: false - name: Install Ruff run: pip install ruff - name: Ruff Check run: ruff check . --fix-only --exit-non-zero-on-fix --output-format=github - name: Ruff Format run: ruff format . --check mypy: runs-on: latchkey-small timeout-minutes: 5 steps: - uses: actions/checkout@v7 with: persist-credentials: false - name: Checkout submodules run: git submodule update --init --recursive --depth 1 - name: Install typing dependencies run: pip install mypy pytest -r requirements.txt - name: Mypy run: mypy sdist: runs-on: latchkey-small timeout-minutes: 5 steps: - uses: libsdl-org/setup-sdl@1894460666e4fe0c6603ea0cce5733f1cca56ba1 with: install-linux-dependencies: true build-type: "Debug" version: ${{ env.sdl-version }} - uses: actions/checkout@v7 with: persist-credentials: false fetch-depth: ${{ env.git-depth }} - name: Checkout submodules run: git submodule update --init --recursive --depth 1 - name: Install build run: pip install build - name: Build source distribution run: python -m build --sdist - uses: actions/upload-artifact@v7 with: name: sdist path: dist/tcod-*.tar.gz retention-days: 7 compression-level: 0 # This makes sure that the latest versions of the SDL headers parse correctly. parse_sdl: needs: [ruff, mypy] runs-on: ${{ matrix.os }} timeout-minutes: 5 strategy: matrix: os: ["windows-latest", "macos-latest"] sdl-version: ["3.2.16"] fail-fast: true steps: - uses: actions/checkout@v7 with: persist-credentials: false fetch-depth: ${{ env.git-depth }} - name: Checkout submodules run: git submodule update --init --recursive --depth 1 - uses: actions/setup-python@v6 with: cache: 'pip' python-version: "3.x" - name: Install build dependencies run: pip install -r requirements.txt - name: Test SDL parsing run: python build_sdl.py env: SDL_VERSION: ${{ matrix.sdl-version }} build: needs: [ruff, mypy, sdist] runs-on: ${{ matrix.os }} timeout-minutes: 15 strategy: matrix: os: ["ubuntu-latest", "windows-latest"] python-version: ["3.10", "3.14t", "pypy-3.10"] architecture: ["x64"] include: - os: "windows-latest" python-version: "3.10" architecture: "x86" - os: "windows-latest" python-version: "3.14t" architecture: "x86" - os: "windows-11-arm" python-version: "3.11" architecture: "arm64" - os: "windows-11-arm" python-version: "3.14t" architecture: "arm64" fail-fast: false steps: - uses: actions/checkout@v7 with: persist-credentials: false fetch-depth: ${{ env.git-depth }} - name: Checkout submodules run: git submodule update --init --recursive --depth 1 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v6 with: cache: 'pip' python-version: ${{ matrix.python-version }} architecture: ${{ matrix.architecture }} - name: Install APT dependencies if: runner.os == 'Linux' run: | sudo apt-get update sudo apt-get install xvfb - uses: libsdl-org/setup-sdl@1894460666e4fe0c6603ea0cce5733f1cca56ba1 if: runner.os == 'Linux' with: install-linux-dependencies: true build-type: "Release" version: ${{ env.sdl-version }} - name: Install Python dependencies run: | python -m pip install --upgrade pip pip install pytest pytest-cov pytest-benchmark pytest-timeout build if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - name: Initialize package run: pip install -e . # Install the package in-place. - name: Build package run: python -m build - name: Test with pytest if: runner.os == 'Windows' run: pytest --cov-report=xml --timeout=300 - name: Test with pytest (Xvfb) if: always() && runner.os != 'Windows' run: xvfb-run -e /tmp/xvfb.log --server-num=$RANDOM --auto-servernum pytest --cov-report=xml --timeout=300 - name: Xvfb logs if: runner.os != 'Windows' run: cat /tmp/xvfb.log - uses: codecov/codecov-action@v7 - uses: actions/upload-artifact@v7 if: runner.os == 'Windows' with: name: wheels-windows-${{ matrix.architecture }}-${{ matrix.python-version }} path: dist/*.whl retention-days: 7 compression-level: 0 test-docs: needs: [ruff, mypy, sdist] runs-on: latchkey-small timeout-minutes: 15 steps: - uses: libsdl-org/setup-sdl@1894460666e4fe0c6603ea0cce5733f1cca56ba1 if: runner.os == 'Linux' with: install-linux-dependencies: true build-type: "Debug" version: ${{ env.sdl-version }} - uses: actions/checkout@v7 with: persist-credentials: false fetch-depth: ${{ env.git-depth }} - name: Checkout submodules run: git submodule update --init --recursive --depth 1 - name: Install Python dependencies run: | python -m pip install --upgrade pip pip install -r docs/requirements.txt - name: Install package run: pip install -e . env: TDL_BUILD: DEBUG - name: Test doc generation working-directory: docs run: python -m sphinx -T -E -W --keep-going . _build/html tox: needs: [ruff, sdist] runs-on: ${{ matrix.os }} timeout-minutes: 15 strategy: matrix: os: ["ubuntu-latest"] # "windows-latest" disabled due to free-threaded build issues steps: - uses: actions/checkout@v7 with: persist-credentials: false fetch-depth: ${{ env.git-depth }} - name: Checkout submodules run: git submodule update --init --depth 1 - name: Set up Python uses: actions/setup-python@v6 with: cache: 'pip' python-version: "3.x" - name: Install Python dependencies run: | python -m pip install --upgrade pip tox - uses: libsdl-org/setup-sdl@1894460666e4fe0c6603ea0cce5733f1cca56ba1 if: runner.os == 'Linux' with: install-linux-dependencies: true build-type: "Debug" version: ${{ env.sdl-version }} - name: Run tox run: | tox -vv linux-wheels: needs: [ruff, mypy, sdist] runs-on: ${{ matrix.arch == 'aarch64' && 'ubuntu-24.04-arm' || 'ubuntu-latest'}} timeout-minutes: 15 strategy: matrix: arch: ["x86_64", "aarch64"] build: ["cp310-manylinux*", "pp311-manylinux*", "cp314t-manylinux*"] env: BUILD_DESC: "" steps: - uses: actions/checkout@v7 with: persist-credentials: false fetch-depth: ${{ env.git-depth }} - name: Checkout submodules run: git submodule update --init --recursive --depth 1 - name: Build wheels uses: pypa/cibuildwheel@v4.0.0rc1 env: CIBW_BUILD: ${{ matrix.build }} CIBW_ARCHS_LINUX: ${{ matrix.arch }} CIBW_MANYLINUX_*_IMAGE: manylinux2014 CIBW_MANYLINUX_PYPY_X86_64_IMAGE: manylinux2014 CIBW_MANYLINUX_PYPY_AARCH64_IMAGE: manylinux2014 CIBW_BEFORE_ALL_LINUX: > yum install -y epel-release && yum-config-manager --enable epel && yum install -y gcc git-core make cmake \ alsa-lib-devel pulseaudio-libs-devel \ libX11-devel libXext-devel libXrandr-devel libXcursor-devel libXfixes-devel \ libXi-devel libXScrnSaver-devel dbus-devel ibus-devel \ systemd-devel mesa-libGL-devel libxkbcommon-devel mesa-libGLES-devel \ mesa-libEGL-devel vulkan-devel wayland-devel wayland-protocols-devel \ libdrm-devel mesa-libgbm-devel libusb-devel git clone --depth 1 --branch release-${{env.sdl-version}} https://github.com/libsdl-org/SDL.git sdl_repo && cmake -S sdl_repo -B sdl_build && cmake --build sdl_build --config Release && cmake --install sdl_build --config Release --prefix /usr/local && cp --verbose /usr/local/lib64/pkgconfig/sdl3.pc /lib64/pkgconfig/sdl3.pc CIBW_BEFORE_TEST: pip install numpy CIBW_TEST_COMMAND: python -c "import tcod.context" # Skip test on emulated architectures CIBW_TEST_SKIP: "*_aarch64" - name: Remove asterisk from label env: BUILD_DESC: ${{ matrix.build }} run: | BUILD_DESC=${BUILD_DESC//\*} echo BUILD_DESC=${BUILD_DESC} >> $GITHUB_ENV - name: Archive wheel uses: actions/upload-artifact@v7 with: name: wheels-linux-${{ matrix.arch }}-${{ env.BUILD_DESC }} path: wheelhouse/*.whl retention-days: 7 compression-level: 0 build-macos: needs: [ruff, mypy, sdist] runs-on: "macos-14" timeout-minutes: 15 strategy: fail-fast: true matrix: python: ["cp310-*_universal2", "cp314t-*_universal2", "pp311-*"] env: PYTHON_DESC: "" steps: - uses: actions/checkout@v7 with: persist-credentials: false fetch-depth: ${{ env.git-depth }} - name: Checkout submodules run: git submodule update --init --recursive --depth 1 - uses: actions/setup-python@v6 with: cache: 'pip' python-version: "3.x" - name: Install Python dependencies run: pip install -r requirements.txt - name: Prepare package # Downloads SDL for the later step. run: python build_sdl.py - name: Build wheels uses: pypa/cibuildwheel@v4.0.0rc1 env: CIBW_BUILD: ${{ matrix.python }} CIBW_ARCHS_MACOS: x86_64 arm64 universal2 CIBW_BEFORE_BUILD_MACOS: pip install --upgrade delocate CIBW_BEFORE_TEST: pip install numpy CIBW_TEST_COMMAND: python -c "import tcod.context" CIBW_TEST_SKIP: "pp* *-macosx_arm64 *-macosx_universal2:arm64" MACOSX_DEPLOYMENT_TARGET: "10.13" - name: Remove asterisk from label env: PYTHON_DESC: ${{ matrix.python }} run: | PYTHON_DESC=${PYTHON_DESC//\*/X} echo PYTHON_DESC=${PYTHON_DESC} >> $GITHUB_ENV - name: Archive wheel uses: actions/upload-artifact@v7 with: name: wheels-macos-${{ env.PYTHON_DESC }} path: wheelhouse/*.whl retention-days: 7 compression-level: 0 pyodide: needs: [ruff, mypy, sdist] runs-on: latchkey-small timeout-minutes: 15 steps: - uses: actions/checkout@v7 with: persist-credentials: false fetch-depth: ${{ env.git-depth }} - name: Checkout submodules run: git submodule update --init --recursive --depth 1 - uses: libsdl-org/setup-sdl@1894460666e4fe0c6603ea0cce5733f1cca56ba1 with: install-linux-dependencies: true build-type: "Debug" version: "3.2.4" # Should be equal or less than the version used by Emscripten - uses: pypa/cibuildwheel@v4.0.0rc1 env: CIBW_BUILD: cp313-pyodide_wasm32 CIBW_PLATFORM: pyodide - name: Archive wheel uses: actions/upload-artifact@v7 with: name: wheels-pyodide path: wheelhouse/*.whl retention-days: 30 compression-level: 0 publish: needs: [sdist, build, build-macos, linux-wheels, pyodide] runs-on: latchkey-small timeout-minutes: 5 if: github.ref_type == 'tag' environment: name: pypi url: https://pypi.org/project/tcod/${{ github.ref_name }} permissions: id-token: write # Attestation steps: - uses: actions/download-artifact@v8 with: name: sdist path: dist/ - uses: actions/download-artifact@v8 with: pattern: wheels-* path: dist/ merge-multiple: true - uses: pypa/gh-action-pypi-publish@release/v1 with: skip-existing: 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. - Cache dependency installs on the setup step so they are served from cache.
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 11 jobs (24 with the matrix expanded) per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.