Release workflow (cocotb/cocotb)
The Release workflow from cocotb/cocotb, explained and optimized by Latchkey.
CI health: C - fair
Point runs-on at Latchkey and get caching, job timeouts, self-healing for flaky steps, and up to 58% lower cost, applied automatically.
What it does
This is the Release workflow from the cocotb/cocotb repository, a real project running GitHub Actions. It is shown here with attribution under its BSD-3-Clause license.
Below, Latchkey shows a faster, safer version produced by its optimization engine.
The workflow
# Copyright cocotb contributors
# Licensed under the Revised BSD License, see LICENSE for details.
# SPDX-License-Identifier: BSD-3-Clause
#
# DO NOT RENAME THIS FILE!
# PyPi uploads use OIDC, aka Trusted Publishing, to avoid the need for API keys.
# https://pypi.org/manage/project/cocotb/settings/publishing/ is configured to
# allow uploads from the cocotb GitHub project and this exact file name.
#
name: Release
concurrency:
group: ${{ github.workflow }}-${{ github.event.number }}-${{ github.event.ref }}
cancel-in-progress: ${{ !(contains(github.ref, 'release/') || contains(github.ref, 'master')) }}
on:
# Run this workflow on every push to master or to a stable branch.
push:
branches:
- master
- "stable/**"
tags:
- 'v*'
workflow_dispatch:
jobs:
build_release:
name: Build distribution on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false # Keep going even if one matrix build fails.
matrix:
os:
- ubuntu-22.04
- windows-2022
- macos-15-intel # x86_64
- macos-14 # ARM64
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.12"
- name: Install uv
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
- name: Install nox
run: python3 -m pip install nox nox-uv
# Use the cibuildwheel configuration inside nox, instead of the
# cibuildwheel GitHub Action, to make the process easy to reproduce
# locally.
- name: Build cocotb release
run: |
nox -s release_clean
nox -s release_build
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: cocotb-dist-${{ matrix.os }}
path: |
dist/*.whl
dist/*.tar.gz
# This tests both the sdist and wheel builds in separate venvs back to back with just the pytest tests.
test_release:
name: Regression Tests
needs: build_release
uses: ./.github/workflows/regression-tests.yml
with:
test_task: release_test
download_artifacts: true
group: ci-free
test_release_licensed:
name: Regression Tests
needs: build_release
uses: ./.github/workflows/regression-tests.yml
with:
test_task: release_test
download_artifacts: true
group: ci-licensed
deploy_pypi:
name: Deploy to pypi.org
needs:
- test_release
- test_release_licensed
permissions:
id-token: write
runs-on: ubuntu-22.04
# Only upload tagged releases.
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.12"
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: dist
pattern: cocotb-dist-*
merge-multiple: true
- name: Publish distribution to PyPI
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
# Authentication to PyPi is done through OIDC ("Trusted Publishing").
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.
# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause # # DO NOT RENAME THIS FILE! # PyPi uploads use OIDC, aka Trusted Publishing, to avoid the need for API keys. # https://pypi.org/manage/project/cocotb/settings/publishing/ is configured to # allow uploads from the cocotb GitHub project and this exact file name. # name: Release concurrency: group: ${{ github.workflow }}-${{ github.event.number }}-${{ github.event.ref }} cancel-in-progress: ${{ !(contains(github.ref, 'release/') || contains(github.ref, 'master')) }} on: # Run this workflow on every push to master or to a stable branch. push: branches: - master - "stable/**" tags: - 'v*' workflow_dispatch: jobs: build_release: timeout-minutes: 30 name: Build distribution on ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: fail-fast: false # Keep going even if one matrix build fails. matrix: os: - ubuntu-22.04 - windows-2022 - macos-15-intel # x86_64 - macos-14 # ARM64 steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: cache: 'pip' python-version: "3.12" - name: Install uv uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 - name: Install nox run: python3 -m pip install nox nox-uv # Use the cibuildwheel configuration inside nox, instead of the # cibuildwheel GitHub Action, to make the process easy to reproduce # locally. - name: Build cocotb release run: | nox -s release_clean nox -s release_build - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: cocotb-dist-${{ matrix.os }} path: | dist/*.whl dist/*.tar.gz # This tests both the sdist and wheel builds in separate venvs back to back with just the pytest tests. test_release: timeout-minutes: 30 name: Regression Tests needs: build_release uses: ./.github/workflows/regression-tests.yml with: test_task: release_test download_artifacts: true group: ci-free test_release_licensed: timeout-minutes: 30 name: Regression Tests needs: build_release uses: ./.github/workflows/regression-tests.yml with: test_task: release_test download_artifacts: true group: ci-licensed deploy_pypi: timeout-minutes: 30 name: Deploy to pypi.org needs: - test_release - test_release_licensed permissions: id-token: write runs-on: latchkey-small # Only upload tagged releases. if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: cache: 'pip' python-version: "3.12" - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: path: dist pattern: cocotb-dist-* merge-multiple: true - name: Publish distribution to PyPI uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0 # Authentication to PyPi is done through OIDC ("Trusted Publishing").
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.
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 4 jobs (7 with the matrix expanded) per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.