Skip to content
Latchkey

Test workflow (1313e/CMasher)

The Test workflow from 1313e/CMasher, explained and optimized by Latchkey.

C

CI health: C - fair

Point runs-on at Latchkey and get run de-duplication, job timeouts, self-healing for flaky steps, and up to 58% lower cost, applied automatically.

Grade your own workflow free or run it on Latchkey →
Source: 1313e/CMasher.github/workflows/test.ymlLicense BSD-3-ClauseView source

What it does

This is the Test workflow from the 1313e/CMasher 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

workflow (.yml)
# 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: Test

on:
  push:
    branches:
    - master
    tags: v*
  pull_request:
  schedule:
  # run this on first day of the month at 3 am UTC
  - cron: 0 3 1 * *
  workflow_dispatch:

jobs:
  build:
    name: ${{ matrix.os }}, Python ${{ matrix.python-version }}
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest]
        python-version:
        - '3.10'
        - '3.11'
        - '3.12'
        - '3.13'
        - '3.14'

        include:
        - os: ubuntu-22.04
          python-version: 3.10.0
          oldestdeps: true
        - os: macos-latest
          python-version: '3.14'
        - os: windows-latest
          python-version: '3.14'

    concurrency:
      group: ${{ github.ref }}-${{ matrix.os }}-${{ matrix.python-version }}-build
      cancel-in-progress: true

    steps:
    - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
    - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
      with:
        python-version: ${{ matrix.python-version }}

    - name: Set UV_RESOLUTION
      if: ${{ matrix.oldestdeps }}
      run: |
        echo "UV_RESOLUTION=lowest" >> $GITHUB_ENV

    - run: uv sync --group test --compile-bytecode

    - name: Test package (no coverage)
      if: ${{ !startsWith( matrix.os , 'ubuntu' ) }}
      shell: bash # windows compat
      run: |
        uv run --no-sync --no-editable \
          pytest --color=yes --mpl

    - name: Test package (with coverage)
      if: startsWith( matrix.os , 'ubuntu' )
      # cannot use --frozen flag here because it would nullify UV_RESOLUTION
      run: |
        uv run --group covcheck \
          coverage run --parallel-mode -m pytest --color=yes --mpl

    - name: Upload coverage data
      # only using reports from ubuntu because
      # combining reports from multiple platforms is tricky (or impossible ?)
      if: startsWith( matrix.os , 'ubuntu' )
      uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
      with:
        name: cmasher_coverage_data-${{ matrix.os }}-${{ matrix.python-version }}${{ matrix.oldestdeps }}
        path: .coverage.*
        if-no-files-found: ignore
        include-hidden-files: true


  coverage:
    name: Combine & check coverage
    runs-on: ubuntu-latest
    needs: build

    steps:
    - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
    - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
    - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
      with:
        pattern: cmasher_coverage_data-*
        merge-multiple: true

    - run: uv sync --only-group covcheck
    - name: Check coverage
      run: |
        uv run --no-project coverage combine
        uv run --no-project coverage html --skip-covered --skip-empty
        uv run --no-project coverage report --fail-under=98

    - name: Upload HTML report if check failed.
      uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
      with:
        name: cmasher_coverage_report
        path: htmlcov
      if: ${{ failure() }}

  type-check:
    name: type check w/ Python ${{ matrix.python-version }}

    strategy:
      matrix:
        python-version:
        - '3.10'
        - '3.13'

    runs-on: ubuntu-latest

    concurrency:
      group: ${{ github.ref }}-${{ matrix.python-version }}-typecheck
      cancel-in-progress: true

    steps:
    - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
    - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
      with:
        python-version: ${{ matrix.python-version }}

    - name: Run mypy
      run: uv run --no-editable --group typecheck mypy src/cmasher

  docs:
    name: Build docs
    runs-on: ubuntu-latest

    concurrency:
      group: ${{ github.ref }}-docs
      cancel-in-progress: true

    steps:
    - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
    - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
      with:
        python-version: '3.13'

    - name: Build
      run: |
        uv run --frozen --group docs --compile-bytecode \
          sphinx-build -M html docs/source site -W
    - name: Upload artifacts
      uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
      with:
        name: site
        path: site

  build-artifacts:
    name: Build artifacts
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
    - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
    - run: uv build
    - run: uvx twine check dist/*
    - run: uv run scripts/check_dist.py

    - name: Upload artifacts
      uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
      with:
        name: dist
        path: dist

  publish:
    name: Publish to PyPI

    if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
    needs:
    - build
    - type-check
    - docs
    - build-artifacts

    runs-on: ubuntu-latest
    environment:
      name: pypi
      url: https://pypi.org/p/CMasher

    permissions:
      id-token: write

    steps:
    - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
      with:
        name: dist
        path: dist

    - name: Publish package distributions to PyPI
      if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
      uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0

The same workflow, on Latchkey

Removes redundant runs and caps runaway jobs. 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: Test
 
on:
  push:
    branches:
    - master
    tags: v*
  pull_request:
  schedule:
  # run this on first day of the month at 3 am UTC
  - cron: 0 3 1 * *
  workflow_dispatch:
 
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true
 
jobs:
  build:
    timeout-minutes: 30
    name: ${{ matrix.os }}, Python ${{ matrix.python-version }}
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest]
        python-version:
        - '3.10'
        - '3.11'
        - '3.12'
        - '3.13'
        - '3.14'
 
        include:
        - os: ubuntu-22.04
          python-version: 3.10.0
          oldestdeps: true
        - os: macos-latest
          python-version: '3.14'
        - os: windows-latest
          python-version: '3.14'
 
    concurrency:
      group: ${{ github.ref }}-${{ matrix.os }}-${{ matrix.python-version }}-build
      cancel-in-progress: true
 
    steps:
    - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
    - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
      with:
        python-version: ${{ matrix.python-version }}
 
    - name: Set UV_RESOLUTION
      if: ${{ matrix.oldestdeps }}
      run: |
        echo "UV_RESOLUTION=lowest" >> $GITHUB_ENV
 
    - run: uv sync --group test --compile-bytecode
 
    - name: Test package (no coverage)
      if: ${{ !startsWith( matrix.os , 'ubuntu' ) }}
      shell: bash # windows compat
      run: |
        uv run --no-sync --no-editable \
          pytest --color=yes --mpl
 
    - name: Test package (with coverage)
      if: startsWith( matrix.os , 'ubuntu' )
      # cannot use --frozen flag here because it would nullify UV_RESOLUTION
      run: |
        uv run --group covcheck \
          coverage run --parallel-mode -m pytest --color=yes --mpl
 
    - name: Upload coverage data
      # only using reports from ubuntu because
      # combining reports from multiple platforms is tricky (or impossible ?)
      if: startsWith( matrix.os , 'ubuntu' )
      uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
      with:
        name: cmasher_coverage_data-${{ matrix.os }}-${{ matrix.python-version }}${{ matrix.oldestdeps }}
        path: .coverage.*
        if-no-files-found: ignore
        include-hidden-files: true
 
 
  coverage:
    timeout-minutes: 30
    name: Combine & check coverage
    runs-on: latchkey-small
    needs: build
 
    steps:
    - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
    - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
    - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
      with:
        pattern: cmasher_coverage_data-*
        merge-multiple: true
 
    - run: uv sync --only-group covcheck
    - name: Check coverage
      run: |
        uv run --no-project coverage combine
        uv run --no-project coverage html --skip-covered --skip-empty
        uv run --no-project coverage report --fail-under=98
 
    - name: Upload HTML report if check failed.
      uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
      with:
        name: cmasher_coverage_report
        path: htmlcov
      if: ${{ failure() }}
 
  type-check:
    timeout-minutes: 30
    name: type check w/ Python ${{ matrix.python-version }}
 
    strategy:
      matrix:
        python-version:
        - '3.10'
        - '3.13'
 
    runs-on: latchkey-small
 
    concurrency:
      group: ${{ github.ref }}-${{ matrix.python-version }}-typecheck
      cancel-in-progress: true
 
    steps:
    - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
    - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
      with:
        python-version: ${{ matrix.python-version }}
 
    - name: Run mypy
      run: uv run --no-editable --group typecheck mypy src/cmasher
 
  docs:
    timeout-minutes: 30
    name: Build docs
    runs-on: latchkey-small
 
    concurrency:
      group: ${{ github.ref }}-docs
      cancel-in-progress: true
 
    steps:
    - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
    - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
      with:
        python-version: '3.13'
 
    - name: Build
      run: |
        uv run --frozen --group docs --compile-bytecode \
          sphinx-build -M html docs/source site -W
    - name: Upload artifacts
      uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
      with:
        name: site
        path: site
 
  build-artifacts:
    timeout-minutes: 30
    name: Build artifacts
    runs-on: latchkey-small
 
    steps:
    - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
    - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
    - run: uv build
    - run: uvx twine check dist/*
    - run: uv run scripts/check_dist.py
 
    - name: Upload artifacts
      uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
      with:
        name: dist
        path: dist
 
  publish:
    timeout-minutes: 30
    name: Publish to PyPI
 
    if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
    needs:
    - build
    - type-check
    - docs
    - build-artifacts
 
    runs-on: latchkey-small
    environment:
      name: pypi
      url: https://pypi.org/p/CMasher
 
    permissions:
      id-token: write
 
    steps:
    - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
      with:
        name: dist
        path: dist
 
    - name: Publish package distributions to PyPI
      if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
      uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
 

What changed

This workflow runs 6 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.

Actions used in this workflow