Skip to content

chore: bump taiki-e/install-action from 2.85.13 to 2.86.5 #841

chore: bump taiki-e/install-action from 2.85.13 to 2.86.5

chore: bump taiki-e/install-action from 2.85.13 to 2.86.5 #841

Workflow file for this run

name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
schedule:
# Weekly dependency security check
- cron: '0 0 * * 0'
env:
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: 0
CARGO_NET_RETRY: 10
RUST_BACKTRACE: short
RUSTFLAGS: "-D warnings"
RUSTUP_MAX_RETRIES: 10
# Default to minimal permissions (security best practice)
permissions:
contents: read
# Cancel previous runs on new push
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
# Detect which files changed to optimize job execution
changes:
name: Detect Changes
runs-on: ubuntu-latest
permissions:
pull-requests: read
outputs:
rust: ${{ steps.filter.outputs.rust }}
python: ${{ steps.filter.outputs.python }}
node: ${{ steps.filter.outputs.node }}
ci: ${{ steps.filter.outputs.ci }}
docs: ${{ steps.filter.outputs.docs }}
steps:
- uses: actions/checkout@v7
- uses: dorny/paths-filter@v4
id: filter
with:
filters: |
rust:
- '**/*.rs'
- '**/Cargo.toml'
- '**/Cargo.lock'
- 'deny.toml'
- 'clippy.toml'
- 'rustfmt.toml'
python:
- 'crates/exarch-python/**'
- 'crates/exarch-core/**'
- 'Cargo.toml'
- 'Cargo.lock'
node:
- 'crates/exarch-node/**'
- 'crates/exarch-core/**'
- 'Cargo.toml'
- 'Cargo.lock'
ci:
- '.github/workflows/**'
- '.github/labeler.yml'
docs:
- '**/*.md'
- '**/README.md'
# Quick checks first - fail fast
format:
name: Format Check
runs-on: ubuntu-latest
timeout-minutes: 5
needs: changes
if: |
needs.changes.outputs.rust == 'true' ||
github.ref == 'refs/heads/main' ||
github.ref == 'refs/heads/develop'
steps:
- uses: actions/checkout@v7
- name: Install nightly Rust
uses: dtolnay/rust-toolchain@nightly
with:
components: rustfmt
- name: Check formatting
run: cargo +nightly fmt --all -- --check
clippy:
name: Clippy
runs-on: ubuntu-latest
timeout-minutes: 15
needs: changes
if: |
needs.changes.outputs.rust == 'true' ||
github.ref == 'refs/heads/main' ||
github.ref == 'refs/heads/develop'
steps:
- uses: actions/checkout@v7
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- name: Cache Cargo dependencies
uses: Swatinem/rust-cache@v2
with:
shared-key: "clippy"
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Run Clippy
run: cargo clippy --workspace --all-targets --all-features -- -D warnings
documentation:
name: Documentation
runs-on: ubuntu-latest
timeout-minutes: 15
needs: changes
if: |
needs.changes.outputs.rust == 'true' ||
github.ref == 'refs/heads/main' ||
github.ref == 'refs/heads/develop'
steps:
- uses: actions/checkout@v7
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: Cache Cargo dependencies
uses: Swatinem/rust-cache@v2
with:
shared-key: "doc"
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Check documentation
env:
RUSTDOCFLAGS: "-D warnings"
run: |
cargo doc --no-deps --all-features --workspace 2>&1 | tee /tmp/cargo-doc.log
# cargo emits target output-path collisions as a warning, not a rustdoc lint, so
# RUSTDOCFLAGS="-D warnings" above cannot catch it (see #429) — assert it separately.
if grep -q "output filename collision" /tmp/cargo-doc.log; then
echo "::error::cargo doc reported an output filename collision (see #429)"
exit 1
fi
# Security audit
security:
name: Security Audit
runs-on: ubuntu-latest
timeout-minutes: 10
needs: changes
if: |
needs.changes.outputs.rust == 'true' ||
github.ref == 'refs/heads/main' ||
github.ref == 'refs/heads/develop' ||
github.event_name == 'schedule'
steps:
- uses: actions/checkout@v7
- name: Run cargo-deny
uses: EmbarkStudios/cargo-deny-action@v2
with:
log-level: warn
command: check
arguments: --all-features
# Cross-platform tests with matrix
test:
name: Test (${{ matrix.os }})
needs: [changes, format]
runs-on: ${{ matrix.os }}
timeout-minutes: 30
if: |
needs.changes.outputs.rust == 'true' ||
github.ref == 'refs/heads/main' ||
github.ref == 'refs/heads/develop'
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v7
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: Cache Cargo dependencies
uses: Swatinem/rust-cache@v2
with:
shared-key: "test-${{ matrix.os }}"
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Install nextest
uses: taiki-e/install-action@v2.86.5
with:
tool: nextest
- name: Build all targets
run: cargo build --workspace --all-targets --all-features --exclude exarch-python --exclude exarch-node
- name: Run tests
run: cargo nextest run --workspace --all-features --no-fail-fast --exclude exarch-python --exclude exarch-node
- name: Run doctests
run: cargo test --doc --workspace --all-features --exclude exarch-python --exclude exarch-node
# Release-profile tests for exarch-core: exercises cfg(not(debug_assertions))
# tests (e.g. release-only redaction/security assertions) that the debug-mode
# `test` job above never runs (see #476).
test-release:
name: Test (release profile)
needs: [changes, format]
runs-on: ubuntu-latest
timeout-minutes: 20
if: |
needs.changes.outputs.rust == 'true' ||
github.ref == 'refs/heads/main' ||
github.ref == 'refs/heads/develop'
steps:
- uses: actions/checkout@v7
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: Cache Cargo dependencies
uses: Swatinem/rust-cache@v2
with:
shared-key: "test-release"
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Install nextest
uses: taiki-e/install-action@v2.86.5
with:
tool: nextest
- name: Run release-profile tests (exarch-core)
run: cargo nextest run -p exarch-core --release --all-features --no-fail-fast
# Test Python bindings with coverage
test-python:
name: Test Python ${{ matrix.python-version }}
needs: [changes, format]
runs-on: ubuntu-latest
timeout-minutes: 20
# always() + explicit needs.format.result check is required here: a job
# with `needs: [format]` is skipped by GitHub Actions whenever `format`
# itself is skipped (e.g. on a Python-only PR, where rust == 'false'),
# regardless of what this job's own `if` says, unless always() overrides
# that default gating.
if: |
always() &&
needs.changes.result == 'success' &&
(needs.format.result == 'success' || needs.format.result == 'skipped') &&
(needs.changes.outputs.python == 'true' ||
github.ref == 'refs/heads/main' ||
github.ref == 'refs/heads/develop')
strategy:
fail-fast: false
matrix:
python-version: ['3.10', '3.11', '3.12', '3.13', '3.14']
steps:
- uses: actions/checkout@v7
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: Cache Cargo dependencies
uses: Swatinem/rust-cache@v2
with:
shared-key: "python"
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Set up Python
uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}
- name: Install uv
uses: astral-sh/setup-uv@v7
- name: Install dependencies
run: |
cd crates/exarch-python
uv pip install --system maturin "ruff==0.16.0" mypy pytest pytest-cov
- name: Run Rust unit tests (exarch-python)
run: cargo test -p exarch-python --lib --no-default-features
- name: Format check with ruff
run: |
cd crates/exarch-python
ruff format --check .
- name: Lint with ruff
run: |
cd crates/exarch-python
ruff check .
- name: Type check with mypy
run: |
cd crates/exarch-python
mypy . --ignore-missing-imports || true
- name: Build Python bindings
run: |
cd crates/exarch-python
# panic-injection exposes a deliberate-panic test hook used by the
# #395 regression test (test_panic_safety.py); never enabled for
# published wheels (see release.yml).
maturin build --release --features panic-injection,abi3
- name: Install Python bindings
run: uv pip install --system target/wheels/*.whl
- name: Test Python bindings
if: matrix.python-version != '3.12'
run: |
cd crates/exarch-python
pytest tests/ -v
# Coverage is only measured once (Python version doesn't change which
# lines of the Rust-backed bindings get exercised), so only one matrix
# leg uploads to Codecov — uploading all 5 would just duplicate the
# same flag's data and race codecov.yml's after_n_builds threshold.
- name: Test Python bindings with coverage
if: matrix.python-version == '3.12'
run: |
cd crates/exarch-python
pytest tests/ -v --cov --cov-report=xml:coverage.xml
- name: Upload Python coverage to Codecov
if: matrix.python-version == '3.12'
uses: codecov/codecov-action@v7
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: crates/exarch-python/coverage.xml
flags: exarch-python
fail_ci_if_error: false
# Test Node.js bindings with coverage
test-node:
name: Test Node.js Bindings
needs: [changes, format]
runs-on: ubuntu-latest
timeout-minutes: 20
if: |
always() &&
needs.changes.result == 'success' &&
(needs.format.result == 'success' || needs.format.result == 'skipped') &&
(needs.changes.outputs.node == 'true' ||
github.ref == 'refs/heads/main' ||
github.ref == 'refs/heads/develop')
steps:
- uses: actions/checkout@v7
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: Cache Cargo dependencies
uses: Swatinem/rust-cache@v2
with:
shared-key: "node"
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Set up Node.js
uses: actions/setup-node@v7
with:
node-version: '20'
- name: Install dependencies
run: |
cd crates/exarch-node
npm install
- name: Run Rust unit tests (exarch-node)
run: cargo test -p exarch-node --lib
- name: Format check with Biome
run: |
cd crates/exarch-node
npm run format:check
- name: Lint with Biome
run: |
cd crates/exarch-node
npm run lint
- name: Build Node.js bindings
run: |
cd crates/exarch-node
npm run build
- name: Test Node.js bindings
run: |
cd crates/exarch-node
npm test
# Quick compile-only check for criterion benchmarks (does not run them)
bench-build:
name: Bench Build Check
needs: [changes, format]
runs-on: ubuntu-latest
timeout-minutes: 15
if: |
needs.changes.outputs.rust == 'true' ||
github.ref == 'refs/heads/main' ||
github.ref == 'refs/heads/develop'
steps:
- uses: actions/checkout@v7
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: Cache Cargo dependencies
uses: Swatinem/rust-cache@v2
with:
shared-key: "bench-build"
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Build benchmarks (compile only, does not run them)
run: cargo build --workspace --benches --all-features --exclude exarch-python --exclude exarch-node
# MSRV check (exarch-core only)
msrv:
name: MSRV Check (exarch-core)
needs: [changes, format]
runs-on: ubuntu-latest
timeout-minutes: 15
if: |
needs.changes.outputs.rust == 'true' ||
github.ref == 'refs/heads/main' ||
github.ref == 'refs/heads/develop'
steps:
- uses: actions/checkout@v7
- name: Install Rust 1.96.0
uses: dtolnay/rust-toolchain@master
with:
toolchain: "1.96.0"
- name: Cache Cargo dependencies
uses: Swatinem/rust-cache@v2
with:
shared-key: "msrv"
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Check MSRV for exarch-core
run: cargo check -p exarch-core --all-features
# Code coverage (Linux only) - codecov auto-distributes by paths
coverage:
name: Code Coverage
needs: [changes, format]
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: read
if: |
needs.changes.outputs.rust == 'true' ||
github.ref == 'refs/heads/main' ||
github.ref == 'refs/heads/develop'
steps:
- uses: actions/checkout@v7
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: Cache Cargo dependencies
uses: Swatinem/rust-cache@v2
with:
shared-key: "coverage"
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@v2.86.5
with:
tool: cargo-llvm-cov
- name: Install nextest
uses: taiki-e/install-action@v2.86.5
with:
tool: nextest
- name: Generate coverage report
run: |
cargo llvm-cov --all-features --workspace \
--exclude exarch-python --exclude exarch-node \
--lcov --output-path lcov.info nextest
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v7
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: lcov.info
flags: exarch-core, exarch-cli
fail_ci_if_error: false
verbose: true
# All checks passed
ci-success:
name: CI Success
needs: [format, clippy, documentation, security, test, test-release, test-python, test-node, msrv, bench-build]
runs-on: ubuntu-latest
if: always()
steps:
- name: Check all jobs
run: |
# Required jobs that must pass
REQUIRED_JOBS=(
"${{ needs.format.result }}"
"${{ needs.clippy.result }}"
"${{ needs.documentation.result }}"
"${{ needs.security.result }}"
"${{ needs.test.result }}"
"${{ needs.test-release.result }}"
"${{ needs.test-python.result }}"
"${{ needs.test-node.result }}"
"${{ needs.msrv.result }}"
"${{ needs.bench-build.result }}"
)
for result in "${REQUIRED_JOBS[@]}"; do
if [[ "$result" != "success" && "$result" != "skipped" ]]; then
echo "Required job failed or was cancelled: $result"
exit 1
fi
done
echo "All required jobs passed successfully!"