diff --git a/.github/workflows/autofmt.yaml b/.github/workflows/autofmt.yaml index 3119ee1d4..e7a08867c 100644 --- a/.github/workflows/autofmt.yaml +++ b/.github/workflows/autofmt.yaml @@ -51,7 +51,7 @@ jobs: gh pr checkout ${{ github.event.issue.number }} --repo "$GITHUB_REPOSITORY" - name: Install Rust (rustfmt) - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@1.86.0 with: components: rustfmt diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 3d762b62a..9897aaf60 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -38,7 +38,18 @@ jobs: run: sudo apt-get install -y protobuf-compiler - name: Install Rust - uses: dtolnay/rust-toolchain@stable + # 1.86 is the MSRV (pinned via rust-toolchain.toml, see /CLAUDE.md). Plain + # `cargo` resolves to it. fmt, clippy and the library build run on 1.86 to + # guarantee the shipped crate builds there. + uses: dtolnay/rust-toolchain@1.86.0 + + - name: Install Rust (test toolchain) + # The experimental `adbc` feature's test path pulls `adbc_datafusion` → + # `datafusion` ≥53.1.0, which requires rustc ≥1.88. Steps that compile + # tests/dev-dependencies use this newer toolchain via `cargo +stable`. + # Installing it here does not change the default — rust-toolchain.toml + # keeps plain `cargo` on 1.86. + run: rustup toolchain install stable --profile minimal - name: Caching uses: Swatinem/rust-cache@v2 @@ -54,17 +65,23 @@ jobs: run: cargo clippy -- -D warnings - name: Install wasm-pack - run: cargo install wasm-pack + # Compile the tool itself on stable; the actual wasm build below still + # runs on the pinned 1.86 toolchain. + run: cargo +stable install wasm-pack - - name: Build with cargo - run: cargo build --all-targets + - name: Build library (MSRV 1.86) + run: cargo build + + - name: Build all targets + # --all-targets compiles dev-dependencies (datafusion), so it needs ≥1.88. + run: cargo +stable build --all-targets - name: Run tree-sitter tests working-directory: tree-sitter-ggsql run: tree-sitter test - name: Run Rust tests - run: cargo test --lib --bins + run: cargo +stable test --lib --bins - name: Install dbc CLI and SQLite ADBC driver run: | @@ -72,10 +89,10 @@ jobs: "$HOME/.local/bin/dbc" install sqlite - name: Run ADBC unit tests - run: cargo test --features "adbc sqlite" --lib + run: cargo +stable test --features "adbc sqlite" --lib - name: Run ADBC SQLite equivalence tests - run: cargo test --features "adbc sqlite" --lib -- --ignored equivalence + run: cargo +stable test --features "adbc sqlite" --lib -- --ignored equivalence - name: Build WASM library working-directory: ggsql-wasm/library diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 66e089c08..ba548a43a 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -37,7 +37,16 @@ jobs: run: sudo apt-get install -y unixodbc-dev - name: Install Rust - uses: dtolnay/rust-toolchain@stable + # 1.86 is the MSRV (see /CLAUDE.md); the Jupyter kernel build below runs + # on it. Plain `cargo` resolves to 1.86 via rust-toolchain.toml. + uses: dtolnay/rust-toolchain@1.86.0 + + - name: Install Rust (wasm toolchain) + # The wasm build is exempt from the 1.86 pin (R doesn't use wasm); some + # wasm-only deps need a newer rustc. Installing stable here does not + # change the default — rust-toolchain.toml keeps plain `cargo` on 1.86, + # and ggsql-wasm/rust-toolchain.toml selects stable for the wasm build. + run: rustup toolchain install stable --profile minimal - name: Caching uses: Swatinem/rust-cache@v2 @@ -47,10 +56,12 @@ jobs: save-if: ${{ github.ref == 'refs/heads/main' }} - name: Install wasm-pack - run: cargo install wasm-pack + # `cargo install` runs at the repo root (pinned to 1.86); `+stable` + # builds these tools on the newer toolchain instead. + run: cargo +stable install wasm-pack - name: Install wasm-opt - run: cargo install wasm-opt + run: cargo +stable install wasm-opt - name: Setup quarto uses: quarto-dev/quarto-actions/setup@v2 diff --git a/.github/workflows/release-packages.yml b/.github/workflows/release-packages.yml index 5019de1a4..11d899b0a 100644 --- a/.github/workflows/release-packages.yml +++ b/.github/workflows/release-packages.yml @@ -27,7 +27,7 @@ jobs: run: npm install -g tree-sitter-cli - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@1.86.0 with: targets: x86_64-pc-windows-msvc @@ -103,7 +103,7 @@ jobs: run: npm install -g tree-sitter-cli - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@1.86.0 with: targets: x86_64-apple-darwin @@ -210,7 +210,7 @@ jobs: run: npm install -g tree-sitter-cli - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@1.86.0 with: targets: aarch64-apple-darwin @@ -317,7 +317,7 @@ jobs: run: npm install -g tree-sitter-cli - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@1.86.0 with: targets: x86_64-unknown-linux-gnu @@ -364,7 +364,7 @@ jobs: run: npm install -g tree-sitter-cli - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@1.86.0 with: targets: aarch64-unknown-linux-gnu @@ -415,7 +415,7 @@ jobs: run: npm install -g tree-sitter-cli - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@1.86.0 - name: Get crates.io publish token uses: rust-lang/crates-io-auth-action@v1 @@ -476,16 +476,21 @@ jobs: run: npm install -g tree-sitter-cli - name: Install Rust toolchain + # The wasm build is exempt from the 1.86 MSRV pin (R doesn't use wasm); + # some wasm-only deps need a newer rustc. ggsql-wasm/rust-toolchain.toml + # selects stable for the actual build. uses: dtolnay/rust-toolchain@stable - name: Install LLVM run: sudo apt-get install -y llvm - name: Install wasm-pack - run: cargo install wasm-pack + # `cargo install` runs at the repo root, where rust-toolchain.toml pins + # 1.86; `+stable` builds these tools on the newer toolchain instead. + run: cargo +stable install wasm-pack - name: Install wasm-opt - run: cargo install wasm-opt + run: cargo +stable install wasm-opt - name: Build WASM package run: ./ggsql-wasm/build-wasm.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index a3129ad66..65854639b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,8 @@ - Upgraded dependencies: duckdb-rs v1.10502, arrow v58 (#447). - Renamed the `width` setting in the `range` layer to `hinge`. This prevents it from clashing with `width` needed by `position => 'dodge'` (#437). +- Pinned the minimum supported Rust version to 1.86 (the maximum Rust version + CRAN ships) so the crate keeps building for the R bindings. ## 0.3.3 - 2026-05-27 diff --git a/CLAUDE.md b/CLAUDE.md index 883d627d4..780d18c92 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -69,6 +69,15 @@ cd ggsql-vscode && npm install && npm run package cd tree-sitter-ggsql && npx tree-sitter generate ``` +### Rust version (MSRV) + +The toolchain is **pinned to Rust 1.86** (`rust-toolchain.toml` + `rust-version` in `/Cargo.toml`). This is the maximum Rust version CRAN ships, and the R bindings must build against it — **only bump it when CRAN does.** Setting `rust-version` also turns on clippy's MSRV-aware lints, so accidental use of a newer std API fails `clippy`/build with a clear message instead of a cryptic `E0658`. + +Two things are exempt from the pin: + +- **The `adbc` test path.** The experimental `adbc` feature depends (dev-only) on `adbc_datafusion` → `datafusion` ≥53.1.0, which requires rustc ≥1.88. The shipped library still builds on 1.86; only the test / `--all-targets` build needs the newer toolchain. CI (`build.yaml`) runs fmt, clippy and the library build on 1.86, and runs the test-compiling steps with `cargo +stable`. +- **The wasm bindings (`ggsql-wasm`).** R doesn't use wasm, and some wasm-only dependencies require a newer rustc, so the crate has no `rust-version` and a nested `ggsql-wasm/rust-toolchain.toml` selects **stable** for any build done from that directory (`./build-wasm.sh`, `wasm-pack`, `library/`). + Cross-platform installers (NSIS / MSI / DMG / Deb): see [`INSTALLERS.md`](INSTALLERS.md). Releases are tag-driven via `.github/workflows/`. ## Testing diff --git a/Cargo.toml b/Cargo.toml index e7a1e9596..095678431 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,10 @@ resolver = "2" [workspace.package] version = "0.3.3" edition = "2021" +# Pinned to CRAN's maximum supported Rust version for the R bindings. Only bump +# this when CRAN does. Setting it here also turns on clippy's `incompatible_msrv` +# lint, which catches accidental use of std APIs newer than this version. +rust-version = "1.86" authors = ["ggsql Team"] license = "MIT" repository = "https://github.com/posit-dev/ggsql" diff --git a/ggsql-cli/Cargo.toml b/ggsql-cli/Cargo.toml index f4f13eb20..a0049b906 100644 --- a/ggsql-cli/Cargo.toml +++ b/ggsql-cli/Cargo.toml @@ -2,6 +2,7 @@ name = "ggsql-cli" version.workspace = true edition.workspace = true +rust-version.workspace = true authors.workspace = true license.workspace = true repository.workspace = true diff --git a/ggsql-jupyter/Cargo.toml b/ggsql-jupyter/Cargo.toml index 714814b97..6be601eae 100644 --- a/ggsql-jupyter/Cargo.toml +++ b/ggsql-jupyter/Cargo.toml @@ -2,6 +2,7 @@ name = "ggsql-jupyter" version.workspace = true edition.workspace = true +rust-version.workspace = true authors.workspace = true license.workspace = true repository.workspace = true diff --git a/ggsql-wasm/CLAUDE.md b/ggsql-wasm/CLAUDE.md index b40b22679..483d6612c 100644 --- a/ggsql-wasm/CLAUDE.md +++ b/ggsql-wasm/CLAUDE.md @@ -31,6 +31,7 @@ ggsql-wasm/ ## Toolchain +- **Rust stable, not the workspace 1.86 MSRV.** The rest of the workspace is pinned to 1.86 for the R/CRAN bindings (see [`/CLAUDE.md`](../CLAUDE.md)), but R doesn't use wasm and some wasm-only deps need a newer rustc. A nested [`rust-toolchain.toml`](rust-toolchain.toml) selects stable for any build run from this directory; this crate has no `rust-version`. In CI the wasm tool installs (`cargo install wasm-pack`/`wasm-opt`) run at the repo root, so they use `cargo +stable` to avoid the 1.86 pin. - Rust target `wasm32-unknown-unknown` and [`wasm-pack`](https://rustwasm.github.io/wasm-pack/) for compilation. - A clang/llvm with wasm backend support (the build script verifies this with a one-line probe). - `wasm-opt` (from binaryen) for the `-Oz` optimization step. diff --git a/ggsql-wasm/Cargo.toml b/ggsql-wasm/Cargo.toml index ca67029c4..9969ee1e9 100644 --- a/ggsql-wasm/Cargo.toml +++ b/ggsql-wasm/Cargo.toml @@ -2,6 +2,9 @@ name = "ggsql-wasm" version.workspace = true edition.workspace = true +# No `rust-version`: the wasm bindings are not part of the R/CRAN 1.86 MSRV +# guarantee (R doesn't use them) and some wasm-only dependencies require a newer +# rustc. This crate builds on stable — see ggsql-wasm/rust-toolchain.toml. authors.workspace = true license.workspace = true repository.workspace = true diff --git a/ggsql-wasm/rust-toolchain.toml b/ggsql-wasm/rust-toolchain.toml new file mode 100644 index 000000000..af1e3482a --- /dev/null +++ b/ggsql-wasm/rust-toolchain.toml @@ -0,0 +1,7 @@ +# The wasm bindings are exempt from the workspace's 1.86 MSRV pin (R/CRAN, see +# /rust-toolchain.toml): R doesn't use wasm, and some wasm-only dependencies +# require a newer rustc. Building from this directory (./build-wasm.sh, +# wasm-pack, library/) picks up this file and uses stable instead. +[toolchain] +channel = "stable" +targets = ["wasm32-unknown-unknown"] diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 000000000..c9169aeb1 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,6 @@ +# Pinned to CRAN's maximum supported Rust version so the R bindings keep +# building. Only bump this (and `rust-version` in Cargo.toml) when CRAN raises +# the Rust version it ships. See /CLAUDE.md. +[toolchain] +channel = "1.86" +components = ["rustfmt", "clippy"] diff --git a/src/Cargo.toml b/src/Cargo.toml index 3938e4ea1..95614b06d 100644 --- a/src/Cargo.toml +++ b/src/Cargo.toml @@ -2,6 +2,7 @@ name = "ggsql" version.workspace = true edition.workspace = true +rust-version.workspace = true authors.workspace = true license.workspace = true repository.workspace = true diff --git a/src/plot/scale/linetype.rs b/src/plot/scale/linetype.rs index 0b080a581..2099934ca 100644 --- a/src/plot/scale/linetype.rs +++ b/src/plot/scale/linetype.rs @@ -8,7 +8,7 @@ fn parse_hex_linetype(s: &str) -> Option> { let len = s.len(); // Must be even length, 2-8 characters, all hex digits - if !(2..=8).contains(&len) || !len.is_multiple_of(2) { + if !(2..=8).contains(&len) || len % 2 != 0 { return None; } diff --git a/tree-sitter-ggsql/Cargo.toml b/tree-sitter-ggsql/Cargo.toml index 9c991737f..5edfe3f33 100644 --- a/tree-sitter-ggsql/Cargo.toml +++ b/tree-sitter-ggsql/Cargo.toml @@ -2,6 +2,7 @@ name = "tree-sitter-ggsql" version.workspace = true edition.workspace = true +rust-version.workspace = true authors.workspace = true license.workspace = true repository.workspace = true