name: CI
on:
push:
branches: [main]
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
lint:
name: Lint (fmt + clippy)
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
- name: Check formatting
run: cargo fmt --check
- name: Clippy (all targets)
run: cargo clippy --all-targets -- -D warnings
test-stable:
name: Test (stable)
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v6
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
- name: Install cargo-nextest
uses: taiki-e/install-action@cargo-nextest
- name: Test (all)
if: github.ref == 'refs/heads/main'
run: cargo nextest run --profile ci --workspace --exclude djvu-py --features cli
- name: Test (fast — skip slow PDF + IW44)
if: github.ref != 'refs/heads/main'
run: >
cargo nextest run --profile ci --workspace --exclude djvu-py --features cli
--filter-expr 'not (binary(pdf_conversion) or test(iw44_new_decode_big))'
- name: Build (no_std check)
run: cargo build --no-default-features
test-beta:
name: Test (beta)
runs-on: ubuntu-latest
if: github.event_name != 'pull_request'
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
- name: Install Rust beta
uses: dtolnay/rust-toolchain@beta
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
key: beta
- name: Install cargo-nextest
uses: taiki-e/install-action@cargo-nextest
- name: Test fast
run: >
cargo nextest run --profile ci --workspace --exclude djvu-py --features cli
--filter-expr 'not (binary(pdf_conversion) or test(iw44_new_decode_big))'
windows-msvc:
name: Windows MSVC smoke
runs-on: windows-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
- name: Install Rust stable (MSVC)
uses: dtolnay/rust-toolchain@stable
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
key: windows-msvc
- name: Build CLI
run: cargo build --features cli
- name: CLI smoke (djvu info)
run: .\target\debug\djvu.exe info tests\fixtures\boy_jb2.djvu
linux-aarch64:
name: Linux aarch64 smoke
runs-on: ubuntu-24.04-arm
timeout-minutes: 15
steps:
- uses: actions/checkout@v6
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
key: linux-aarch64
- name: Build workspace + CLI
run: cargo build --workspace --exclude djvu-py --features cli
- name: Test libraries
run: cargo test --lib --workspace --exclude djvu-py
- name: CLI smoke (djvu info)
run: ./target/debug/djvu info tests/fixtures/boy_jb2.djvu
msrv:
name: MSRV (1.88)
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
- name: Install Rust 1.88
uses: dtolnay/rust-toolchain@master
with:
toolchain: "1.88"
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
key: msrv-1.88
- name: Build
run: cargo build
wasm:
name: wasm32 build check
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
- name: Install Rust stable + wasm32 target
uses: dtolnay/rust-toolchain@stable
with:
targets: wasm32-unknown-unknown
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
key: wasm32
- name: cargo check --target wasm32-unknown-unknown
run: cargo check --target wasm32-unknown-unknown --features wasm
- name: cargo build --no-default-features --target wasm32-unknown-unknown
run: cargo build --no-default-features --target wasm32-unknown-unknown
- name: cargo check --target wasm32-unknown-unknown +simd128
env:
RUSTFLAGS: -C target-feature=+simd128
run: cargo check --target wasm32-unknown-unknown --features wasm
- name: wasm simd128 benchmark harness syntax check
run: |
bash -n scripts/bench_wasm_simd128.sh
node --check scripts/bench_wasm_simd128.mjs
- name: cargo build (no_std smoke crate, wasm32)
run: cargo build --manifest-path tests/no_std_smoke/Cargo.toml --target wasm32-unknown-unknown
ocr-tesseract:
name: OCR (tesseract)
runs-on: ubuntu-latest
if: github.event_name != 'pull_request'
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
key: ocr-tesseract
- name: Install Tesseract and English language data
run: sudo apt-get update && sudo apt-get install -y tesseract-ocr tesseract-ocr-eng libtesseract-dev libleptonica-dev
- name: Build (ocr-tesseract feature)
run: cargo build --features cli,ocr-tesseract
- name: Test (ocr-tesseract integration)
run: cargo test --test ocr_tesseract --features cli,ocr-tesseract
djvu-py:
name: djvu-py (pytest)
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v6
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
key: djvu-py
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install uv
run: pip install uv
- name: Build + test djvu-py (maturin develop + pytest)
run: make -C djvu-py py-test
deps-check:
name: Dependencies (deny + audit)
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v6
- name: Licenses & advisories (cargo deny)
uses: EmbarkStudios/cargo-deny-action@v2
- name: Install cargo-audit
uses: taiki-e/install-action@cargo-audit
- name: Security audit (cargo audit)
run: cargo audit
coverage:
name: Coverage (llvm-cov)
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v6
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
with:
components: llvm-tools-preview
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
key: coverage
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@cargo-llvm-cov
- name: Collect coverage
run: cargo llvm-cov --workspace --features cli --no-report
- name: Coverage summary
run: |
cargo llvm-cov report --summary-only \
--ignore-filename-regex '(benches|examples|fuzz)/'
- name: Export lcov
run: |
cargo llvm-cov report --lcov --output-path lcov.info \
--ignore-filename-regex '(benches|examples|fuzz)/'
- name: Upload coverage artifact
uses: actions/upload-artifact@v4
with:
name: coverage-lcov
path: lcov.info
if-no-files-found: error