name: Build
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
jobs:
fmt_clippy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: Swatinem/rust-cache@v2
- name: Install Rust
uses: dtolnay/rust-toolchain@1.91.1
with:
components: rustfmt, clippy
- name: Fmt
run: cargo fmt --all --check
- name: Clippy
run: cargo clippy --all-targets --verbose
tests:
runs-on: ubuntu-latest
needs: fmt_clippy
steps:
- uses: actions/checkout@v6
- uses: Swatinem/rust-cache@v2
- name: Install Rust
uses: dtolnay/rust-toolchain@1.91.1
- name: Tests
run: cargo test --all-targets --verbose
build:
runs-on: ubuntu-latest
needs: tests
strategy:
matrix:
target: [
"aarch64-unknown-linux-gnu",
"x86_64-unknown-linux-gnu",
"x86_64-pc-windows-gnu",
"wasm32-unknown-unknown"
]
steps:
- uses: actions/checkout@v6
- uses: Swatinem/rust-cache@v2
with:
shared-key: "build-${{ runner.os }}-${{ matrix.target }}"
- name: Install aarch64 cross toolchain
if: matrix.target == 'aarch64-unknown-linux-gnu'
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends gcc-aarch64-linux-gnu libc6-dev-arm64-cross
- name: Install mingw cross toolchain
if: matrix.target == 'x86_64-pc-windows-gnu'
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends mingw-w64
- name: Install Rust
uses: dtolnay/rust-toolchain@1.91.1
with:
targets: ${{ matrix.target }}
- name: Set aarch64 linker
if: matrix.target == 'aarch64-unknown-linux-gnu'
run: echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
- name: Set windows linker
if: matrix.target == 'x86_64-pc-windows-gnu'
run: echo "CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER=x86_64-w64-mingw32-gcc" >> $GITHUB_ENV
- name: Build
run: cargo build --target ${{ matrix.target }} --verbose
wasm-bindings:
runs-on: ubuntu-latest
needs: tests
steps:
- uses: actions/checkout@v6
- uses: Swatinem/rust-cache@v2
- name: Install Rust
uses: dtolnay/rust-toolchain@1.91.1
with:
targets: wasm32-unknown-unknown
- name: Install wasm-pack
uses: jetli/wasm-pack-action@v0.4.0
- name: Build wasm bindings (web + bundler)
run: make wasm-bindings
- name: Upload wasm artifacts
uses: actions/upload-artifact@v4
with:
name: wasm-bindings
path: |
target/wasm/pkg-web
target/wasm/pkg-react
retention-days: 7
examples:
runs-on: ubuntu-latest
needs: tests
steps:
- uses: actions/checkout@v6
- uses: Swatinem/rust-cache@v2
- name: Install Rust (wasm + wasi)
uses: dtolnay/rust-toolchain@1.91.1
with:
targets: wasm32-unknown-unknown
- name: Install Rust stable for WASI
uses: dtolnay/rust-toolchain@stable
with:
targets: wasm32-wasip1
- name: Install wasm-pack
uses: jetli/wasm-pack-action@v0.4.0
- name: Build wasm bindings (web + bundler)
run: make wasm-bindings
- name: Build WASI CLI example (stable toolchain)
run: cargo +stable build --target wasm32-wasip1 --example wasm_cli --verbose
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Build React TS example (bundler)
working-directory: examples/react_web_ts
run: |
npm install --no-package-lock
npm run build
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Python bindings (maturin develop + example)
run: |
python -m venv .venv
source .venv/bin/activate
pip install --upgrade pip maturin
maturin develop --release -m bindings/python/Cargo.toml
python examples/python_cli/main.py
python-wheels:
runs-on: ${{ matrix.os }}
needs: tests
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v6
- uses: Swatinem/rust-cache@v2
- name: Install Rust
uses: dtolnay/rust-toolchain@1.91.1
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install maturin
run: |
pip install --upgrade pip maturin
- name: Build wheel (platform-specific)
shell: bash
run: |
if [[ "${{ matrix.os }}" == "ubuntu-latest" ]]; then
maturin build --release -m bindings/python/Cargo.toml --skip-auditwheel
elif [[ "${{ matrix.os }}" == "macos-latest" ]]; then
maturin build --release -m bindings/python/Cargo.toml
else
maturin build --release -m bindings/python/Cargo.toml
fi
- name: Install built wheel and run CLI example
shell: bash
run: |
set -euo pipefail
wheel=$(ls bindings/python/target/wheels/*.whl | head -n1)
if [[ -z "$wheel" ]]; then
echo "No wheels produced"; exit 1
fi
python -m pip install "$wheel"
python examples/python_cli/main.py
- name: Upload wheel artifact
uses: actions/upload-artifact@v4
with:
name: python-wheel-${{ matrix.os }}
path: bindings/python/target/wheels/*.whl
retention-days: 7
security_audit:
runs-on: ubuntu-latest
needs: fmt_clippy
steps:
- uses: actions/checkout@v6
- uses: Swatinem/rust-cache@v2
- name: Install Rust
uses: dtolnay/rust-toolchain@1.91.1
- name: Install cargo-audit
uses: taiki-e/install-action@v2
with:
tool: cargo-audit
- name: Run cargo-audit
run: cargo audit
- name: Install cargo-deny
uses: taiki-e/install-action@v2
with:
tool: cargo-deny
- name: Run cargo-deny
run: cargo deny check
coverage:
runs-on: ubuntu-latest
needs: [ tests, security_audit ]
permissions:
contents: read
checks: write
id-token: write
steps:
- uses: actions/checkout@v6
- uses: Swatinem/rust-cache@v2
- name: Install dependencies (fontconfig for all-features)
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends libfontconfig1-dev pkg-config
- name: Install Rust
uses: dtolnay/rust-toolchain@1.91.1
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@cargo-llvm-cov
- name: Generate code coverage
run: cargo llvm-cov --all-features --workspace --lcov --output-path lcov.info
- name: Generate cobertura coverage
run: cargo llvm-cov --all-features --workspace --cobertura --output-path cobertura.xml
- name: Coverage summary
uses: irongut/CodeCoverageSummary@v1.3.0
with:
filename: cobertura.xml
badge: true
format: markdown
output: both
- name: Upload coverage artifact
uses: actions/upload-artifact@v5
with:
name: coverage-lcov
path: |
lcov.info
cobertura.xml
code-coverage-results.md
code-coverage-results.txt
retention-days: 7
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
with:
files: lcov.info
fail_ci_if_error: true
use_oidc: true