name: CI
on:
workflow_dispatch:
pull_request:
branches: [main]
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
RUST_TEST_THREADS: 4
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@nightly
with:
components: rustfmt, clippy
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
shared-key: nightly
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Check formatting
run: cargo fmt --all -- --check
- name: Run clippy
run: |
set -o pipefail
cargo clippy --workspace --all-targets --all-features -- -D warnings 2>&1 | tee clippy.log
if grep -q "warning: unused dependency" clippy.log; then
echo "::error::Remove the unused dependencies reported above."
exit 1
fi
test-matrix:
name: Test Matrix
runs-on: ubuntu-latest
needs: lint
outputs:
sqlite: ${{ steps.matrix.outputs.sqlite }}
pg: ${{ steps.matrix.outputs.pg }}
steps:
- uses: actions/checkout@v6
- name: Install just
uses: taiki-e/install-action@just
- name: Generate matrices
id: matrix
run: |
echo "sqlite=$(just test::sqlite-matrix-json)" >> $GITHUB_OUTPUT
echo "pg=$(just test::pg-matrix-json)" >> $GITHUB_OUTPUT
test-sqlite:
name: "test::sqlite (${{ matrix.features }})"
runs-on: ubuntu-latest
needs: test-matrix
strategy:
fail-fast: false
matrix:
features: ${{ fromJson(needs.test-matrix.outputs.sqlite) }}
steps:
- uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Install just
uses: taiki-e/install-action@just
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
shared-key: stable
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Run tests
run: just test::sqlite "${{ matrix.features }}"
- name: Run SQLite INSERT SELECT compile-time tests
if: matrix.features == 'rusqlite'
run: >-
cargo test -p drizzle --no-default-features
--features std,sqlite,serde
--test compile_fail insert_select_sqlite_ui
- name: Run SQLite math-extension tests
if: startsWith(matrix.features, 'rusqlite,')
run: >-
cargo test -p drizzle --features "${{ matrix.features }},math"
--test lib -- shared_math_extensions optional_math_functions
- name: Run SQLite strict-decode compile-time tests
if: matrix.features == 'rusqlite'
run: >-
cargo test -p drizzle --features rusqlite,uuid,serde
--test compile_fail strict_decode_ui
- name: Run SQLite query-scope compile-time tests
if: matrix.features == 'rusqlite'
run: >-
cargo test -p drizzle --features rusqlite,uuid,serde
--test compile_fail query_scope_sqlite_ui
- name: Run example
if: contains(matrix.features, 'uuid') && startsWith(matrix.features, 'rusqlite')
run: cargo run --example rusqlite --features "rusqlite,uuid,serde"
test-sqlite-unification:
name: Test SQLite Feature Unification
runs-on: ubuntu-latest
needs: lint
steps:
- uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
shared-key: stable
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Run feature-unification regression
run: cargo test -p drizzle --test sqlite_backend_feature_gating --features "rusqlite,libsql,uuid" -- --test-threads=4
test-downstream:
name: Test Downstream Consumers
runs-on: ubuntu-latest
needs: lint
steps:
- uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
shared-key: stable
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Download locked dependencies
run: cargo fetch --locked
- name: Compile consumer crates against the derive macros
run: cargo test -p drizzle --test downstream_consumers -- --ignored --test-threads=2
test-pg:
name: "test::pg (${{ matrix.features }})"
runs-on: ubuntu-latest
needs: test-matrix
strategy:
fail-fast: false
matrix:
features: ${{ fromJson(needs.test-matrix.outputs.pg) }}
steps:
- uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Install just
uses: taiki-e/install-action@just
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
shared-key: stable
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Run tests
run: just test::pg "${{ matrix.features }}"
- name: Run PostgreSQL INSERT SELECT compile-time tests
if: matrix.features == 'postgres-sync'
run: >-
cargo test -p drizzle --no-default-features
--features std,postgres,serde
--test compile_fail insert_select_postgres_ui
- name: Run PostgreSQL query-scope compile-time tests
if: matrix.features == 'postgres-sync'
run: >-
cargo test -p drizzle --no-default-features
--features std,postgres-sync,serde
--test compile_fail query_scope_postgres_ui
test-mysql:
name: "Test MySQL (${{ matrix.name }})"
runs-on: ubuntu-latest
needs: lint
strategy:
fail-fast: false
matrix:
include:
- name: sync
mysql-version: "8.4"
features: mysql-sync
test-features: mysql-sync,query,serde,uuid,chrono,time,jiff,rust-decimal,arrayvec,compact-str,bytes,smallvec-types
- name: async
mysql-version: "8.4"
features: mysql-async
test-features: mysql-async,query,serde,uuid,chrono,time,jiff,rust-decimal,arrayvec,compact-str,bytes,smallvec-types
- name: unified
mysql-version: "8.4"
features: mysql-sync,mysql-async
test-features: mysql-sync,mysql-async,query,serde,uuid,chrono,time,jiff,rust-decimal,arrayvec,compact-str,bytes,smallvec-types
- name: minimum-sync
mysql-version: "8.0.31"
features: mysql-sync
test-features: mysql-sync,query,serde,uuid,chrono,time,jiff,rust-decimal,arrayvec,compact-str,bytes,smallvec-types
- name: minimum-async
mysql-version: "8.0.31"
features: mysql-async
test-features: mysql-async,query,serde,uuid,chrono,time,jiff,rust-decimal,arrayvec,compact-str,bytes,smallvec-types
services:
mysql:
image: mysql:${{ matrix.mysql-version }}
env:
MYSQL_ROOT_PASSWORD: mysql
MYSQL_DATABASE: drizzle_test
MYSQL_USER: drizzle
MYSQL_PASSWORD: drizzle
ports:
- 3306:3306
options: >-
--health-cmd="mysqladmin ping -h 127.0.0.1 -udrizzle -pdrizzle --silent && mysql -h 127.0.0.1 -udrizzle -pdrizzle drizzle_test -e 'SELECT 1'"
--health-interval=2s
--health-timeout=5s
--health-retries=30
env:
DRIZZLE_MYSQL_URL: mysql://drizzle:drizzle@127.0.0.1:3306/drizzle_test
steps:
- uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
shared-key: stable
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Check adapter features
run: cargo check -p drizzle --no-default-features --features "${{ matrix.features }},query"
- name: Check driver-neutral dialect surface
if: matrix.name == 'sync'
run: cargo check -p drizzle --no-default-features --features mysql
- name: Reject async runtime dependencies
if: matrix.name == 'sync'
shell: bash
run: |
if cargo tree -p drizzle --no-default-features --features mysql-sync,query --edges normal \
| grep -E '(^|[[:space:]])(tokio|mysql_async) v'; then
echo "mysql-sync pulled an async runtime dependency"
exit 1
fi
if cargo tree -p drizzle-cli --no-default-features --features mysql-sync --edges normal \
| grep -E '(^|[[:space:]])(tokio|mysql_async) v'; then
echo "drizzle-cli mysql-sync pulled an async runtime dependency"
exit 1
fi
- name: Run MySQL compile-time tests
if: matrix.name == 'sync'
run: |
cargo test -p drizzle --no-default-features \
--features mysql-sync,serde \
--test compile_fail mysql_macros_ui
cargo test -p drizzle --no-default-features \
--features mysql-sync,serde \
--test compile_fail mysql_builder_ui
cargo test -p drizzle --no-default-features \
--features mysql-sync,serde \
--test compile_fail query_scope_mysql_ui
- name: Run minimal MySQL adapter tests
run: cargo test -p drizzle --no-default-features --features "${{ matrix.features }}"
- name: Run full MySQL adapter tests
run: cargo test -p drizzle --no-default-features --features "${{ matrix.test-features }}"
- name: Run MySQL example
if: matrix.name == 'sync'
run: cargo run --example mysql --no-default-features --features mysql-sync
- name: Run shared CLI parity contract
run: >-
cargo test -p drizzle-cli --no-default-features
--features "${{ matrix.features }}"
--test parity_integration
test-all-features:
name: Test All-Feature Cross-Driver Contracts
runs-on: ubuntu-latest
needs: lint
services:
postgres:
image: postgres:18-alpine
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: drizzle_test
ports:
- 5432:5432
options: >-
--health-cmd="pg_isready -U postgres -d drizzle_test"
--health-interval=2s
--health-timeout=5s
--health-retries=30
mysql:
image: mysql:8.4
env:
MYSQL_ROOT_PASSWORD: mysql
MYSQL_DATABASE: drizzle_test
MYSQL_USER: drizzle
MYSQL_PASSWORD: drizzle
ports:
- 3306:3306
options: >-
--health-cmd="mysqladmin ping -h 127.0.0.1 -udrizzle -pdrizzle --silent && mysql -h 127.0.0.1 -udrizzle -pdrizzle drizzle_test -e 'SELECT 1'"
--health-interval=2s
--health-timeout=5s
--health-retries=30
env:
DRIZZLE_MYSQL_URL: mysql://drizzle:drizzle@127.0.0.1:3306/drizzle_test
steps:
- uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
shared-key: stable
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Compile every workspace target with every feature
run: cargo test --workspace --all-features --no-run
- name: Run all-feature library and driver-neutral contracts
run: |
cargo test --workspace --all-features --lib -- --test-threads=1
cargo test -p drizzle-core -p drizzle-mysql -p drizzle-migrations --all-features --tests
- name: Run stable cross-driver integration contracts
run: >-
cargo test -p drizzle --test lib
--features
"rusqlite,libsql,postgres-sync,tokio-postgres,mysql-sync,mysql-async,query,serde,uuid,chrono,time,jiff,rust-decimal,arrayvec,compact-str,bytes,smallvec-types,cidr,geo-types,bit-vec"
-- --test-threads=1
docs:
name: Documentation
runs-on: ubuntu-latest
needs: lint
steps:
- uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
shared-key: stable
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Check documentation
run: |
RUSTDOCFLAGS="-D warnings" cargo doc --workspace --all-features --no-deps --exclude drizzle-cli
RUSTDOCFLAGS="-D warnings" cargo doc -p drizzle-cli --all-features --no-deps
cargo test --workspace --all-features --doc
build-matrix:
name: Build (${{ matrix.rust }})
runs-on: ubuntu-latest
needs: lint
strategy:
matrix:
rust: [stable, nightly]
steps:
- uses: actions/checkout@v6
- name: Install Rust ${{ matrix.rust }}
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
shared-key: ${{ matrix.rust }}
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Build
run: cargo build --workspace --all-features
msrv:
name: MSRV Check
runs-on: ubuntu-latest
needs: lint
steps:
- uses: actions/checkout@v6
- name: Get Rust version
id: rust-version
run: |
RUST_VERSION=$(grep '^rust-version = ' Cargo.toml | sed 's/rust-version = "\(.*\)"/\1/')
echo "version=$RUST_VERSION" >> $GITHUB_OUTPUT
- name: Install Rust (MSRV)
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ steps.rust-version.outputs.version }}
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
shared-key: msrv
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Check MSRV
run: |
cargo check -p drizzle --no-default-features --features mysql-sync
cargo check -p drizzle --no-default-features --features mysql-async
cargo check -p drizzle --no-default-features --features mysql-sync,mysql-async
cargo check --workspace --all-targets --all-features
- name: Check CLI driver builds for warnings
run: |
failed=()
for features in "" rusqlite libsql turso postgres-sync tokio-postgres mysql-sync mysql-async d1-http; do
echo "::group::drizzle-cli features: ${features:-none}"
cargo check -p drizzle-cli --all-targets --no-default-features --features "$features" \
--config 'build.warnings="deny"' || failed+=("${features:-none}")
echo "::endgroup::"
done
if (( ${#failed[@]} )); then
echo "::error::drizzle-cli check failed with features: ${failed[*]}"
exit 1
fi
no-std:
name: no_std Checks
runs-on: ubuntu-latest
needs: lint
steps:
- uses: actions/checkout@v6
- name: Get Rust version
id: rust-version
run: |
RUST_VERSION=$(grep '^rust-version = ' Cargo.toml | sed 's/rust-version = "\(.*\)"/\1/')
echo "version=$RUST_VERSION" >> $GITHUB_OUTPUT
- name: Install Rust (MSRV) with a bare-metal target
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ steps.rust-version.outputs.version }}
targets: thumbv7em-none-eabihf
- name: Install just
uses: taiki-e/install-action@just
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
shared-key: no-std-msrv
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Check no_std crates
run: just test::no-std
wasm-drivers:
name: WASM Driver Checks
runs-on: ubuntu-latest
needs: lint
steps:
- uses: actions/checkout@v6
- name: Get Rust version
id: rust-version
run: |
RUST_VERSION=$(grep '^rust-version = ' Cargo.toml | sed 's/rust-version = "\(.*\)"/\1/')
echo "version=$RUST_VERSION" >> $GITHUB_OUTPUT
- name: Install Rust (MSRV) with WASM target
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ steps.rust-version.outputs.version }}
targets: wasm32-unknown-unknown
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
shared-key: wasm-msrv
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Check D1 driver
run: cargo check -p drizzle --target wasm32-unknown-unknown --no-default-features --features d1
- name: Check D1 driver (query)
run: cargo check -p drizzle --target wasm32-unknown-unknown --no-default-features --features d1,query
- name: Check Durable driver
run: cargo check -p drizzle --target wasm32-unknown-unknown --no-default-features --features durable
- name: Check Durable driver (query)
run: cargo check -p drizzle --target wasm32-unknown-unknown --no-default-features --features durable,query
- name: Check Durable Object example
run: cargo check --manifest-path examples/durable_object/Cargo.toml --target wasm32-unknown-unknown
- name: Check Hyperdrive driver
run: cargo check -p drizzle --target wasm32-unknown-unknown --no-default-features --features hyperdrive
- name: Check Hyperdrive driver (query)
run: cargo check -p drizzle --target wasm32-unknown-unknown --no-default-features --features hyperdrive,query