Upload Python Package workflow (glomatico/gamdl)
The Upload Python Package workflow from glomatico/gamdl, 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 Upload Python Package workflow from the glomatico/gamdl 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
# This workflow will upload a Python Package to PyPI when a release is created
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
name: Upload Python Package
on:
release:
types: [published]
workflow_dispatch:
permissions:
contents: read
jobs:
build-sdist:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.10"
- uses: dtolnay/rust-toolchain@stable
- name: Build source distribution
run: |
python -m pip install maturin
maturin sdist --out dist
- name: Upload source distribution
uses: actions/upload-artifact@v4
with:
name: dist-sdist
path: dist/
build-wheels:
name: Build wheel (${{ matrix.name }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- name: linux-x86_64
os: ubuntu-latest
python-version: "3.10"
args: ""
- name: linux-aarch64
os: ubuntu-24.04-arm
python-version: "3.10"
args: ""
- name: windows-x86_64
os: windows-latest
python-version: "3.10"
args: ""
- name: windows-arm64
os: windows-11-arm
python-version: "3.12"
args: ""
- name: macos-universal2
os: macos-latest
python-version: "3.10"
args: "--target universal2-apple-darwin"
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- uses: dtolnay/rust-toolchain@stable
- name: Install macOS universal2 Rust target
if: matrix.name == 'macos-universal2'
run: rustup target add x86_64-apple-darwin
- name: Build wheel
run: |
python -m pip install maturin
maturin build --release --out dist ${{ matrix.args }}
- name: Upload wheel
uses: actions/upload-artifact@v4
with:
name: dist-${{ matrix.name }}
path: dist/
pypi-publish:
runs-on: ubuntu-latest
needs:
- build-sdist
- build-wheels
permissions:
# IMPORTANT: this permission is mandatory for trusted publishing
id-token: write
# Dedicated environments with protections for publishing are strongly recommended.
# For more information, see: https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#deployment-protection-rules
environment:
name: pypi
# OPTIONAL: uncomment and update to include your PyPI project URL in the deployment status:
# url: https://pypi.org/p/YOURPROJECT
#
# ALTERNATIVE: if your GitHub Release name is the PyPI project version string
# ALTERNATIVE: exactly, uncomment the following line instead:
# url: https://pypi.org/project/YOURPROJECT/${{ github.event.release.name }}
steps:
- name: Retrieve release distributions
uses: actions/download-artifact@v4
with:
pattern: dist-*
path: dist/
merge-multiple: true
- name: Publish release distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: dist/
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 upload a Python Package to PyPI when a release is created # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries # This workflow uses actions that are not certified by GitHub. # They are provided by a third-party and are governed by # separate terms of service, privacy policy, and support # documentation. name: Upload Python Package on: release: types: [published] workflow_dispatch: permissions: contents: read jobs: build-sdist: timeout-minutes: 30 runs-on: latchkey-small steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: cache: 'pip' python-version: "3.10" - uses: dtolnay/rust-toolchain@stable - name: Build source distribution run: | python -m pip install maturin maturin sdist --out dist - name: Upload source distribution uses: actions/upload-artifact@v4 with: name: dist-sdist path: dist/ build-wheels: timeout-minutes: 30 name: Build wheel (${{ matrix.name }}) runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: include: - name: linux-x86_64 os: ubuntu-latest python-version: "3.10" args: "" - name: linux-aarch64 os: ubuntu-24.04-arm python-version: "3.10" args: "" - name: windows-x86_64 os: windows-latest python-version: "3.10" args: "" - name: windows-arm64 os: windows-11-arm python-version: "3.12" args: "" - name: macos-universal2 os: macos-latest python-version: "3.10" args: "--target universal2-apple-darwin" steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: cache: 'pip' python-version: ${{ matrix.python-version }} - uses: dtolnay/rust-toolchain@stable - name: Install macOS universal2 Rust target if: matrix.name == 'macos-universal2' run: rustup target add x86_64-apple-darwin - name: Build wheel run: | python -m pip install maturin maturin build --release --out dist ${{ matrix.args }} - name: Upload wheel uses: actions/upload-artifact@v4 with: name: dist-${{ matrix.name }} path: dist/ pypi-publish: timeout-minutes: 30 runs-on: latchkey-small needs: - build-sdist - build-wheels permissions: # IMPORTANT: this permission is mandatory for trusted publishing id-token: write # Dedicated environments with protections for publishing are strongly recommended. # For more information, see: https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#deployment-protection-rules environment: name: pypi # OPTIONAL: uncomment and update to include your PyPI project URL in the deployment status: # url: https://pypi.org/p/YOURPROJECT # # ALTERNATIVE: if your GitHub Release name is the PyPI project version string # ALTERNATIVE: exactly, uncomment the following line instead: # url: https://pypi.org/project/YOURPROJECT/${{ github.event.release.name }} steps: - name: Retrieve release distributions uses: actions/download-artifact@v4 with: pattern: dist-* path: dist/ merge-multiple: true - name: Publish release distributions to PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: packages-dir: dist/ 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.
- 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 3 jobs per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.