Skip to content

add Rust coverage for python tests (#328) #1319

add Rust coverage for python tests (#328)

add Rust coverage for python tests (#328) #1319

Workflow file for this run

name: ci
on:
push:
branches:
- main
tags:
- '**'
pull_request: {}
workflow_dispatch:
inputs:
run_release:
description: 'Run release jobs (for manual tag releases)'
type: boolean
default: false
permissions: {}
env:
COLUMNS: 150
UV_PYTHON: '3.14'
UV_FROZEN: '1'
DEBUG: 'napi:*'
LLVM_COV_IGNORE_FILENAME_REGEX: '(tests/|test_cases/|/tests\.rs$$)'
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
# no release versioning, see https://github.com/dtolnay/rust-toolchain/issues/180
- uses: dtolnay/rust-toolchain@efa25f7f19611383d5b0ccf2d1c8914531636bf9
with:
toolchain: nightly
components: rustfmt, clippy
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
with:
lookup-only: false # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions
cache-on-failure: true
prefix-key: 'v1-rust'
- uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0
with:
enable-cache: true # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions
- run: uv sync --all-packages --only-dev
- uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions
with:
path: ~/.cache/pre-commit
key: pre-commit|${{ env.UV_PYTHON }}|${{ hashFiles('.pre-commit-config.yaml') }}
- name: Setup node
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions
with:
node-version: 24
cache: npm
cache-dependency-path: crates/monty-js/package-lock.json
- name: Install dependencies
run: npm install
working-directory: crates/monty-js
- run: uvx pre-commit run --color=always --all-files --verbose
env:
SKIP: no-commit-to-branch
- name: Show diff on failure
if: failure()
run: git diff
test-rust:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
# no release versioning, see https://github.com/dtolnay/rust-toolchain/issues/180
- uses: dtolnay/rust-toolchain@efa25f7f19611383d5b0ccf2d1c8914531636bf9
with:
toolchain: stable
components: llvm-tools
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
with:
lookup-only: false # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions
cache-on-failure: true
- uses: taiki-e/install-action@1ed3272338f573e042a2e6bca3893aa19f43b47a # v2.71.3
with:
tool: cargo-llvm-cov
# this means pyo3 will use Python 3.14 in tests
- name: set up python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: '3.14'
- run: rustc --version --verbose
- run: python3 -V
# don't use .venv python in CI
- run: rm .cargo/config.toml
- run: cargo llvm-cov clean --workspace
# coverage for `make test-no-features`
- run: cargo llvm-cov --no-report -p monty
- run: cargo llvm-cov run --no-report -p monty-datatest
# coverage for `make test-ref-count-panic`
- run: cargo llvm-cov --no-report -p monty --features ref-count-panic
- run: cargo llvm-cov run --no-report -p monty-datatest --features ref-count-panic
# coverage for `make test-ref-count-return`
- run: cargo llvm-cov --no-report -p monty --features ref-count-return
- run: cargo llvm-cov run --no-report -p monty-datatest --features ref-count-return
# coverage for `make test-type-checking`
- run: cargo llvm-cov --no-report -p monty_type_checking -p monty_typeshed
# Generating text report:
- run: cargo llvm-cov report --ignore-filename-regex "$LLVM_COV_IGNORE_FILENAME_REGEX"
# Generate codecov report (use `report` subcommand to avoid recompilation)
- run: cargo llvm-cov report --codecov --output-path=rust-coverage.json --ignore-filename-regex "$LLVM_COV_IGNORE_FILENAME_REGEX"
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: rust-coverage-report
path: rust-coverage.json
if-no-files-found: error
test-python-coverage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
# no release versioning, see https://github.com/dtolnay/rust-toolchain/issues/180
- uses: dtolnay/rust-toolchain@efa25f7f19611383d5b0ccf2d1c8914531636bf9
with:
toolchain: stable
components: llvm-tools
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
with:
lookup-only: false # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions
cache-on-failure: true
- uses: taiki-e/install-action@1ed3272338f573e042a2e6bca3893aa19f43b47a # v2.71.3
with:
tool: cargo-llvm-cov
- name: set up python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: '3.14'
- uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0
with:
enable-cache: true # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions
- run: rustc --version --verbose
- run: python3 -V
- run: uv sync --all-packages --only-dev
# don't use .venv python in CI
- run: rm .cargo/config.toml
- name: Build and test Python bindings and run pytest with Rust coverage
run: |
set -euxo pipefail
eval "$(cargo llvm-cov show-env --export-prefix)"
cargo llvm-cov clean --workspace
uv run maturin develop --uv -m crates/monty-python/Cargo.toml
uv run --package pydantic-monty --only-dev pytest crates/monty-python/tests
cargo llvm-cov report --ignore-filename-regex "$LLVM_COV_IGNORE_FILENAME_REGEX"
cargo llvm-cov report --codecov --output-path=python-rust-coverage.json --ignore-filename-regex "$LLVM_COV_IGNORE_FILENAME_REGEX"
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: python-rust-coverage-report
path: python-rust-coverage.json
if-no-files-found: error
coverage-upload:
runs-on: ubuntu-latest
needs:
- test-rust
- test-python-coverage
permissions:
# Needed to download coverage report artifacts from the coverage producer jobs.
contents: read
actions: read
# Needed by getsentry/codecov-action when posting the single PR coverage comment.
pull-requests: write
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: '*-coverage-report'
merge-multiple: true
path: coverage-reports
- name: List coverage reports
run: ls -lh coverage-reports
- uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
with:
files: coverage-reports/rust-coverage.json,coverage-reports/python-rust-coverage.json
disable_search: true
token: ${{ secrets.CODECOV_TOKEN }}
name: rust-coverage
- uses: getsentry/codecov-action@03112cc3b486a3397dc8d17a58680008721fc86f # 0.3.7
with:
token: ${{ secrets.GITHUB_TOKEN }}
files: coverage-reports/rust-coverage.json,coverage-reports/python-rust-coverage.json
disable-search: true
coverage-format: codecov
post-pr-comment: true
name: rust-coverage
test-python:
name: test python ${{ matrix.python-version }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ['3.10', '3.11', '3.12', '3.13', '3.14']
env:
UV_PYTHON: ${{ matrix.python-version }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
# no release versioning, see https://github.com/dtolnay/rust-toolchain/issues/180
- uses: dtolnay/rust-toolchain@efa25f7f19611383d5b0ccf2d1c8914531636bf9
with:
toolchain: stable
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
with:
lookup-only: false # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions
cache-on-failure: true
- uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0
with:
enable-cache: true # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions
- run: uv sync --all-packages --only-dev
- run: make dev-py
- run: make pytest
# also test with a release build
- run: make dev-py-release
- run: make pytest
# test uv run exercise script
- run: uv run crates/monty-python/exercise.py
test-rust-os:
name: test rust on ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: macos-latest
- os: windows-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
# no release versioning, see https://github.com/dtolnay/rust-toolchain/issues/180
- uses: dtolnay/rust-toolchain@efa25f7f19611383d5b0ccf2d1c8914531636bf9
with:
toolchain: stable
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
with:
lookup-only: false # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions
cache-on-failure: true
- name: set up python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: '3.14'
# don't use .venv python in CI
- name: Remove cargo config (Unix)
if: runner.os != 'Windows'
run: rm .cargo/config.toml
- name: Remove cargo config (Windows)
if: runner.os == 'Windows'
run: Remove-Item .cargo/config.toml
- run: cargo test -p monty --features ref-count-panic
- run: cargo run -p monty-datatest --features ref-count-panic
bench-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
# no release versioning, see https://github.com/dtolnay/rust-toolchain/issues/180
- uses: dtolnay/rust-toolchain@efa25f7f19611383d5b0ccf2d1c8914531636bf9
with:
toolchain: stable
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
with:
lookup-only: false # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions
cache-on-failure: true
- name: set up python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: '3.14'
# don't use .venv python in CI
- run: rm .cargo/config.toml
- run: make dev-bench
miri:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
# no release versioning, see https://github.com/dtolnay/rust-toolchain/issues/180
- uses: dtolnay/rust-toolchain@efa25f7f19611383d5b0ccf2d1c8914531636bf9
with:
toolchain: nightly
components: miri
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
with:
lookup-only: false # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions
cache-on-failure: true
# don't use .venv python in CI
- run: rm .cargo/config.toml
- name: Run miri tests
run: make miri
fuzz:
name: fuzz ${{ matrix.target }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target:
- tokens_input_panic
# disable until https://github.com/astral-sh/ruff/issues/23198 is fixed
# - string_input_panic
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
# no release versioning, see https://github.com/dtolnay/rust-toolchain/issues/180
- uses: dtolnay/rust-toolchain@efa25f7f19611383d5b0ccf2d1c8914531636bf9
with:
toolchain: nightly
- id: cache-rust
uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
with:
lookup-only: false # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions
cache-on-failure: true
prefix-key: 'v1-rust-fuzz'
workspaces: 'crates/fuzz -> target'
- if: steps.cache-rust.outputs.cache-hit != 'true'
run: cargo install cargo-fuzz
# don't use .venv python in CI
- run: rm .cargo/config.toml
- name: Run ${{ matrix.target }} fuzzer
run: |
# Use --sanitizer none to avoid ASAN/SanitizerCoverage linking issues on CI
# (undefined __sancov_gen_.* symbols). For short CI runs, we're mainly
# catching panics, not memory bugs.
cargo fuzz run --fuzz-dir crates/fuzz --sanitizer none ${{ matrix.target }} -- -max_total_time=60
# https://github.com/marketplace/actions/alls-green#why used for branch protection checks
check:
if: always()
needs:
- lint
- test-rust
- test-python-coverage
- coverage-upload
- test-rust-os
- test-python
- bench-test
- fuzz
runs-on: ubuntu-latest
steps:
- name: Decide whether the needed jobs succeeded or failed
uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2
with:
jobs: ${{ toJSON(needs) }}
# Build source distribution
build-sdist:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: '3.12'
- uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad # v1.50.1
with:
command: sdist
args: --out dist
rust-toolchain: stable
working-directory: crates/monty-python
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: pypi_files-sdist
path: crates/monty-python/dist
# Build wheels for exotic architectures (non-PGO)
build:
name: build on ${{ matrix.os }} (${{ matrix.target }} - ${{ matrix.manylinux || 'auto' }})
# only run on push to main, on tags, or if 'Full Build' label is present
if: startsWith(github.ref, 'refs/tags/') || github.ref == 'refs/heads/main' || contains(github.event.pull_request.labels.*.name, 'Full Build') || (github.event_name == 'workflow_dispatch' && inputs.run_release)
strategy:
fail-fast: false
matrix:
include:
# Linux aarch64
- os: linux
target: aarch64
# Linux i686
- os: linux
target: i686
# Linux armv7
- os: linux
target: armv7
# Linux ppc64le
- os: linux
target: ppc64le
# Linux s390x
- os: linux
target: s390x
# Linux x86_64 musl
- os: linux
target: x86_64
manylinux: musllinux_1_1
# Linux aarch64 musl
- os: linux
target: aarch64
manylinux: musllinux_1_1
# macOS x86_64 (Intel)
- os: macos
target: x86_64
# Windows i686
- os: windows
target: i686
runs-on: ${{ (matrix.os == 'linux' && 'ubuntu-latest') || (matrix.os == 'macos' && 'macos-latest') || (matrix.os == 'windows' && 'windows-latest') }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: '3.12'
- name: build wheels
uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad # v1.50.1
with:
target: ${{ matrix.target }}
manylinux: ${{ matrix.manylinux || 'auto' }}
args: --release --out dist -i 3.10 3.11 3.12 3.13 3.14
rust-toolchain: stable
docker-options: -e CI
working-directory: crates/monty-python
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: pypi_files-${{ matrix.os }}-${{ matrix.target }}-${{ matrix.manylinux || 'manylinux' }}
path: crates/monty-python/dist
# PGO-optimized builds for main platforms
build-pgo:
name: build pgo on ${{ matrix.os }}
# only run on push to main, on tags, or if 'Full Build' label is present
if: startsWith(github.ref, 'refs/tags/') || github.ref == 'refs/heads/main' || contains(github.event.pull_request.labels.*.name, 'Full Build') || (github.event_name == 'workflow_dispatch' && inputs.run_release)
strategy:
fail-fast: false
matrix:
include:
# Linux x86_64 (manylinux)
- os: linux
runs-on: ubuntu-latest
interpreter: 3.10 3.11 3.12 3.13 3.14
# Windows x86_64
- os: windows
runs-on: windows-latest
interpreter: 3.10 3.11 3.12 3.13 3.14
# macOS aarch64 (Apple Silicon)
- os: macos
runs-on: macos-latest
interpreter: 3.10 3.11 3.12 3.13 3.14
runs-on: ${{ matrix.runs-on }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: '3.12'
# no release versioning, see https://github.com/dtolnay/rust-toolchain/issues/180
- uses: dtolnay/rust-toolchain@efa25f7f19611383d5b0ccf2d1c8914531636bf9
with:
toolchain: stable
components: llvm-tools
- name: build PGO wheel
id: pgo
uses: ./.github/actions/build-pgo-wheel
with:
interpreter: ${{ matrix.interpreter }}
rust-toolchain: stable
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: pypi_files-${{ matrix.os }}-pgo
path: ${{ steps.pgo.outputs.wheel-dir }}
# Test wheels on exotic architectures via QEMU
test-builds-arch:
name: test build on ${{ matrix.target }}
needs: [build]
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target: [aarch64, armv7, s390x, ppc64le]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: pypi_files-linux-${{ matrix.target }}-*
merge-multiple: true
path: dist
- uses: uraimo/run-on-arch-action@d94c13912ea685de38fccc1109385b83fd79427d # v3.0.1
name: install & test
with:
arch: ${{ matrix.target }}
distro: ubuntu22.04
dockerRunArgs: --volume "${{ github.workspace }}/dist:/dist"
install: |
apt-get update
apt-get install -y --no-install-recommends python3 python3-pip python3-venv
run: |
ls -lh /dist/
python3 -m venv venv
source venv/bin/activate
python3 -m pip install typing_extensions
python3 -m pip install pydantic-monty --no-index --no-deps --find-links /dist --force-reinstall
python3 -c "import pydantic_monty; print(pydantic_monty.Monty('1 + 2').run())"
# Test wheels on main OS platforms
test-builds-os:
name: test build on ${{ matrix.os }}
needs: [build, build-pgo]
runs-on: ${{ matrix.runs-on }}
strategy:
fail-fast: false
matrix:
include:
- os: linux
runs-on: ubuntu-latest
- os: macos
runs-on: macos-latest
- os: windows
runs-on: windows-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: '3.12'
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: pypi_files-${{ matrix.os }}-*
merge-multiple: true
path: dist
- run: pip install typing_extensions
- run: pip install pydantic-monty --no-index --no-deps --find-links dist --force-reinstall
- run: python -c "import pydantic_monty; print(pydantic_monty.Monty('1 + 2').run())"
# Inspect built artifacts
inspect-python-assets:
needs: [build, build-pgo, build-sdist]
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: pypi_files-*
merge-multiple: true
path: dist
- name: list files
run: |
ls -lhR dist/
ls -1 dist/ | wc -l
echo "Expected ~50 wheel files (5 Python versions × 10 platform variants)"
- uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0
with:
enable-cache: true # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions
- run: uvx twine check --strict dist/*
# Release to PyPI
release-python:
name: release to PyPI
needs: [check, inspect-python-assets, test-builds-arch, test-builds-os]
if: success() && (startsWith(github.ref, 'refs/tags/') || (github.event_name == 'workflow_dispatch' && inputs.run_release))
runs-on: ubuntu-latest
environment:
name: release-python
url: https://pypi.org/project/pydantic-monty/${{ steps.check-version.outputs.VERSION }}
permissions:
id-token: write
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0
with:
enable-cache: true # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: pypi_files-*
merge-multiple: true
path: dist
- id: check-version
uses: samuelcolvin/check-python-version@ee87cddb8049d2694cc03badc8569765a05cef00 # v5
with:
version_file_path: 'Cargo.toml'
- run: ls -lhR dist/
- name: Publish to PyPI
run: 'uv publish --trusted-publishing always dist/*'
build-js:
name: build JS - ${{ matrix.settings.target }} - node@22
runs-on: ${{ matrix.settings.host }}
# only run on push to main, on tags, or if 'Full Build' label is present
if: startsWith(github.ref, 'refs/tags/') || github.ref == 'refs/heads/main' || contains(github.event.pull_request.labels.*.name, 'Full Build') || (github.event_name == 'workflow_dispatch' && inputs.run_release)
strategy:
fail-fast: false
matrix:
settings:
- host: macos-latest
target: x86_64-apple-darwin
build: npm run build:napi -- --target x86_64-apple-darwin && npm run build:ts
- host: windows-latest
target: x86_64-pc-windows-msvc
build: npm run build:napi -- --target x86_64-pc-windows-msvc && npm run build:ts
- host: ubuntu-latest
target: x86_64-unknown-linux-gnu
build: npm run build:napi -- --target x86_64-unknown-linux-gnu --use-napi-cross && npm run build:ts
- host: macos-latest
target: aarch64-apple-darwin
build: npm run build:napi -- --target aarch64-apple-darwin && npm run build:ts
- host: ubuntu-24.04-arm
target: aarch64-unknown-linux-gnu
build: npm run build:napi -- --target aarch64-unknown-linux-gnu && npm run build:ts
- host: ubuntu-latest
target: wasm32-wasip1-threads
build: npm run build:napi -- --target wasm32-wasip1-threads && npm run build:ts
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Setup node
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: 24
package-manager-cache: false
# no release versioning, see https://github.com/dtolnay/rust-toolchain/issues/180
- uses: dtolnay/rust-toolchain@efa25f7f19611383d5b0ccf2d1c8914531636bf9
with:
toolchain: stable
targets: ${{ matrix.settings.target }}
- name: Cache cargo
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 # zizmor: ignore[cache-poisoning]
with:
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
~/.napi-rs
.cargo-cache
target/
key: ${{ matrix.settings.target }}-cargo-${{ matrix.settings.host }}
# don't use .venv python in CI
- run: rm .cargo/config.toml
- uses: mlugg/setup-zig@d1434d08867e3ee9daa34448df10607b98908d29 # v2.2.1
if: ${{ contains(matrix.settings.target, 'musl') }}
with:
version: 0.14.1
use-cache: false
- name: Install cargo-zigbuild
uses: taiki-e/install-action@1ed3272338f573e042a2e6bca3893aa19f43b47a # v2.71.3
if: ${{ contains(matrix.settings.target, 'musl') }}
with:
tool: cargo-zigbuild
- name: Setup toolchain
run: ${{ matrix.settings.setup }}
if: ${{ matrix.settings.setup }}
shell: bash
- name: Install dependencies
run: npm install
working-directory: crates/monty-js
- name: Build
run: ${{ matrix.settings.build }}
shell: bash
working-directory: crates/monty-js
- name: Upload artifact
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: js-bindings-${{ matrix.settings.target }}
path: |
crates/monty-js/monty.*.node
crates/monty-js/monty.*.wasm
if-no-files-found: error
# need to upload the .js files generated by napi; they are identical for whatever target
# so might as well upload from the linux job
- if: ${{ matrix.settings.target == 'x86_64-unknown-linux-gnu' }}
name: Upload artifact
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: js-stubs
path: |
crates/monty-js/browser.js
crates/monty-js/index.js
crates/monty-js/index.d.ts
crates/monty-js/wrapper.js
crates/monty-js/wrapper.d.ts
crates/monty-js/monty.wasi.cjs
crates/monty-js/monty.wasi-browser.js
crates/monty-js/wasi-worker.mjs
crates/monty-js/wasi-worker-browser.mjs
if-no-files-found: error
env:
MACOSX_DEPLOYMENT_TARGET: '10.13'
CARGO_INCREMENTAL: '1'
test-js-macOS-windows-binding:
name: Test JS bindings on ${{ matrix.settings.target }} - node@${{ matrix.node }}
needs:
- build-js
strategy:
fail-fast: false
matrix:
settings:
- host: windows-latest
target: x86_64-pc-windows-msvc
architecture: x64
- host: macos-latest
target: aarch64-apple-darwin
architecture: arm64
- host: macos-latest
target: x86_64-apple-darwin
architecture: x64
node:
- '20'
- '22'
runs-on: ${{ matrix.settings.host }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Setup node
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions
with:
node-version: ${{ matrix.node }}
cache: npm
cache-dependency-path: crates/monty-js/package-lock.json
architecture: ${{ matrix.settings.architecture }}
- name: Install dependencies
run: npm install
working-directory: crates/monty-js
- name: Download artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: js-bindings-${{ matrix.settings.target }}
path: crates/monty-js
- name: Download artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: js-stubs
path: crates/monty-js
- name: List packages
run: ls -R .
shell: bash
working-directory: crates/monty-js
- name: Test bindings
run: npm test
working-directory: crates/monty-js
test-js-linux-binding:
name: Test JS ${{ matrix.target }} - node@${{ matrix.node }}
needs:
- build-js
strategy:
fail-fast: false
matrix:
target:
- x86_64-unknown-linux-gnu
- aarch64-unknown-linux-gnu
node:
- '20'
- '22'
runs-on: ${{ contains(matrix.target, 'aarch64') && 'ubuntu-24.04-arm' || 'ubuntu-latest' }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Setup node
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions
with:
node-version: ${{ matrix.node }}
cache: npm
cache-dependency-path: crates/monty-js/package-lock.json
- name: Output docker params
id: docker
run: |
node -e "
if ('${{ matrix.target }}'.startsWith('aarch64')) {
console.log('PLATFORM=linux/arm64')
} else if ('${{ matrix.target }}'.startsWith('armv7')) {
console.log('PLATFORM=linux/arm/v7')
} else {
console.log('PLATFORM=linux/amd64')
}
" >> $GITHUB_OUTPUT
node -e "
if ('${{ matrix.target }}'.endsWith('-musl')) {
console.log('IMAGE=node:${{ matrix.node }}-alpine')
} else {
console.log('IMAGE=node:${{ matrix.node }}-slim')
}
" >> $GITHUB_OUTPUT
- name: Install dependencies
run: npm install
working-directory: crates/monty-js
- name: Download artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: js-bindings-${{ matrix.target }}
path: crates/monty-js
- name: Download artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: js-stubs
path: crates/monty-js
- name: List packages
run: ls -R .
shell: bash
working-directory: crates/monty-js
- name: Set up QEMU
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
if: ${{ contains(matrix.target, 'armv7') }}
with:
platforms: all
- run: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
if: ${{ contains(matrix.target, 'armv7') }}
- name: Test bindings
run: >
docker run --rm -v ${{ github.workspace }}:${{ github.workspace }} -w ${{ github.workspace }}/crates/monty-js --platform ${OUTPUTS_PLATFORM} ${OUTPUTS_IMAGE} npm test
env:
OUTPUTS_PLATFORM: ${{ steps.docker.outputs.PLATFORM }}
OUTPUTS_IMAGE: ${{ steps.docker.outputs.IMAGE }}
test-js-wasi:
name: Test WASI target
needs:
- build-js
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Setup node
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 # zizmor: ignore[cache-poisoning] -- Job does not produce release artifacts and does not have sensitive permissions
with:
node-version: 24
cache: npm
cache-dependency-path: crates/monty-js/package-lock.json
- name: Install dependencies
run: npm install --cpu wasm32
working-directory: crates/monty-js
- name: Download artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: js-bindings-wasm32-wasip1-threads
path: crates/monty-js
- name: Download artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: js-stubs
path: crates/monty-js
- name: List packages
run: ls -R .
shell: bash
working-directory: crates/monty-js
- name: Test bindings
run: npm test
env:
NAPI_RS_FORCE_WASI: 1
working-directory: crates/monty-js
release-js:
name: Release to NPM
runs-on: ubuntu-latest
needs:
- check
- inspect-python-assets
- test-js-macOS-windows-binding
- test-js-linux-binding
- test-js-wasi
if: success() && (startsWith(github.ref, 'refs/tags/') || (github.event_name == 'workflow_dispatch' && inputs.run_release))
permissions:
contents: write
id-token: write
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Setup node
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: 24
package-manager-cache: false
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
run: npm install
working-directory: crates/monty-js
- name: create npm dirs
run: npm run create-npm-dirs
working-directory: crates/monty-js
- name: Download all artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: js-bindings-*
path: crates/monty-js/artifacts
merge-multiple: true
- name: Download artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: js-stubs
path: crates/monty-js
- name: Move artifacts
run: npm run artifacts
working-directory: crates/monty-js
- name: List packages
run: ls -R ./npm
shell: bash
working-directory: crates/monty-js
- name: Publish
run: |
if [[ "$GITHUB_REF" =~ ^refs/tags/v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Publishing stable release"
npm publish --provenance --access public
else
echo "Publishing pre-release with 'next' tag"
npm publish --provenance --tag next --access public
fi
working-directory: crates/monty-js