name: CI
on:
push:
branches: [main]
pull_request:
env:
CARGO_TERM_COLOR: always
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install system dependencies
run: sudo apt-get update && sudo apt-get install -y libfontconfig1-dev
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy, rustfmt
- uses: Swatinem/rust-cache@v2
- name: Format check
run: cargo fmt --all -- --check
# The minimal, plotters-free configuration downstream renderers use must
# stay tiny: ggplot-rs + indexmap (+ equivalent, hashbrown).
- name: Minimal dependency tree (sf, no defaults)
run: |
cargo tree --no-default-features --features sf -e normal --prefix none \
| sed 's/ (.*//' | sort -u | tee /dev/stderr \
| grep -Eqv '^(ggplot-rs|indexmap|equivalent|hashbrown) ' \
&& { echo "::error::unexpected dependency in the minimal tree"; exit 1; } || true
- name: Clippy (default)
run: cargo clippy --all-targets -- -D warnings
- name: Clippy (no default features)
run: cargo clippy --all-targets --no-default-features -- -D warnings
- name: Clippy (arrow only)
run: cargo clippy --all-targets --no-default-features --features arrow -- -D warnings
- name: Tests (default)
run: cargo test
- name: Tests (no default features)
run: cargo test --no-default-features
- name: Tests (arrow)
run: cargo test --no-default-features --features arrow
- name: Clippy (regression)
run: cargo clippy --all-targets --features regression -- -D warnings
- name: Tests (regression)
run: cargo test --features regression
# sf tests use the core DataFrame (no polars), so run without default
# features — a lighter link that avoids the polars-heavy OOM; the coverage
# job still exercises `sf` together with polars.
- name: Clippy (sf)
run: cargo clippy --all-targets --no-default-features --features sf -- -D warnings
# Target the lib (spatial unit tests) + the sf integration test only:
# skips the polars-using doctests and trims the link footprint.
- name: Tests (sf)
run: cargo test --no-default-features --features sf --lib --test sf --test native_svg --test linewidth_arrow --test hexbin --test svg_root_attrs --test formatted_values --test tooltip_templates --test geom_text_font --test geom_ink_paper --test geom_ink_paper_sf --test gradient_limits --test default_output_022 --test default_output_023 --test axis_label_fit --test legend_wrap --test position_panels_r --test position_vjust_text_dodge --test scale_size_area --test errorbar_dodge_caps --test boxplot_identity --test decorative_layer
# The JSON plot spec shared by the CLI and the npm package, plus the
# agent-skill freshness checks (skills/ must match the shipped API).
- name: Clippy (spec)
run: cargo clippy --no-default-features --features spec --lib --tests -- -D warnings
- name: Tests (spec + skills)
run: |
cargo test --no-default-features --features spec --lib spec::
cargo test --no-default-features --features spec --test skills
- name: Clippy (tiles)
run: cargo clippy --no-default-features --features tiles,canvas --lib --tests -- -D warnings
- name: Tests (tiles)
run: cargo test --no-default-features --features tiles,canvas --lib --test map_tile_325
- name: Clippy (geojson)
run: cargo clippy --no-default-features --features geojson --lib -- -D warnings
- name: Tests (geojson)
run: cargo test --no-default-features --features geojson --lib spatial::geojson
- name: Clippy (canvas)
run: cargo clippy --all-targets --no-default-features --features canvas -- -D warnings
- name: Tests (canvas)
run: cargo test --no-default-features --features canvas --lib --test canvas
- name: Clippy (pdf)
run: cargo clippy --no-default-features --features pdf --lib --tests -- -D warnings
- name: Tests (pdf)
run: cargo test --no-default-features --features pdf --lib --test pdf_467
- name: Clippy (ggpubr)
run: cargo clippy --all-targets --no-default-features --features ggpubr -- -D warnings
- name: Tests (ggpubr)
run: cargo test --no-default-features --features ggpubr --lib --test ggpubr_basics --test ggpubr_stat_cor --test ggpubr_compare_means
- name: Add wasm target
run: rustup target add wasm32-unknown-unknown
- name: Build library for wasm32 (sf + canvas, no defaults)
run: cargo build --target wasm32-unknown-unknown --no-default-features --features sf,canvas
- name: Clippy (wasm bindings crate)
run: cargo clippy -p ggplot-rs-wasm --target wasm32-unknown-unknown -- -D warnings
- name: Build (wasm bindings crate)
run: cargo build -p ggplot-rs-wasm --target wasm32-unknown-unknown
- name: Build examples
run: cargo build --examples
# The npm package (@sipemu/ggplot-rs, js/): version lock-step with the crate,
# wasm-bindgen tests across the JS boundary, then vitest + tsc against the
# built package exactly as it will be packed.
npm:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Versions match (crate, wasm crate, js/package.json)
run: node js/check-version.mjs
- uses: dtolnay/rust-toolchain@stable
with:
targets: wasm32-unknown-unknown
- uses: Swatinem/rust-cache@v2
- uses: jetli/wasm-pack-action@v0.4.0
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: npm
cache-dependency-path: js/package-lock.json
- name: wasm-bindgen tests
run: wasm-pack test --node crates/ggplot-rs-wasm --no-default-features
- name: Install
working-directory: js
run: npm ci
- name: Build package
working-directory: js
run: npm run build
- name: Typecheck (shipped .d.ts)
working-directory: js
run: npm run typecheck
- name: vitest
working-directory: js
run: npm test
- name: Pack (dry run)
working-directory: js
run: npm pack --dry-run
# The `ggplot-rs` CLI (bundled DuckDB — a slow C++ build, cached): it must
# build and plot on every PR, since cli-binaries.yml ships it on release.
cli:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- uses: Swatinem/rust-cache@v2
with:
key: cli
- name: Clippy (cli)
run: cargo clippy --features cli --bin ggplot-rs -- -D warnings
- name: Build
run: cargo build --features cli --bin ggplot-rs
- name: Smoke test
run: |
bin=target/debug/ggplot-rs
printf 'x,y,g,lo,hi\n1,2,a,1,3\n2,4,b,3,5\n3,3,a,2,4\n' > smoke.csv
"$bin" --csv smoke.csv --describe
"$bin" --list-geoms | grep -qx sankey
"$bin" --csv smoke.csv --x x --y y --color g --geom point --geom smooth --param se=false -o a.svg
"$bin" --csv smoke.csv --x x --y y --aes ymin=lo --aes ymax=hi --geom pointrange -o b.png
echo '{"data":{"k":["a","b"],"v":[2,1]},"aes":{"weight":"v","fill":"k"},"layers":[{"geom":"treemap"}]}' > s.json
"$bin" --spec s.json -o c.svg
test -s a.svg && test -s b.png && test -s c.svg
coverage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install system dependencies
run: sudo apt-get update && sudo apt-get install -y libfontconfig1-dev
- uses: dtolnay/rust-toolchain@stable
with:
components: llvm-tools-preview
- uses: Swatinem/rust-cache@v2
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@cargo-llvm-cov
- name: Generate coverage
# Explicit features (not --all-features) to skip the `cli` feature, whose
# bundled DuckDB is a slow C++ build and is exercised outside CI.
run: cargo llvm-cov --features polars,arrow,regression,serde,sf,geojson,ggpubr,tiles,canvas,spec --workspace --lcov --output-path lcov.info
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
files: lcov.info
fail_ci_if_error: false
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}