Skip to content

docs(readme): document Claude/MCP one-click connector + correct app size #267

docs(readme): document Claude/MCP one-click connector + correct app size

docs(readme): document Claude/MCP one-click connector + correct app size #267

Workflow file for this run

name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
frontend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: frontend/package-lock.json
- name: Install
run: npm --prefix frontend ci
- name: Type-check + build
run: npm --prefix frontend run build
rust:
strategy:
fail-fast: false
matrix:
os: [ubuntu-24.04, windows-latest, macos-14]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
# The full workspace (engine + duckle-runner + duckle-mcp + apps/desktop
# with two embedded binaries) plus test artifacts can exceed the ~14 GB
# free on a GitHub Linux runner ("No space left on device"). Drop large
# preinstalled toolchains we never use to reclaim ~20 GB.
- name: Free disk space (Linux)
if: runner.os == 'Linux'
shell: bash
run: |
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc \
/opt/hostedtoolcache/CodeQL /usr/local/.ghcup /usr/local/share/boost \
/usr/local/share/powershell /usr/share/swift || true
sudo docker image prune --all --force || true
df -h /
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy, rustfmt
- uses: Swatinem/rust-cache@v2
- name: Install Linux WebView deps (Tauri)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y \
libwebkit2gtk-4.1-dev libgtk-3-dev \
libayatana-appindicator3-dev librsvg2-dev libsoup-3.0-dev
- name: Install DuckDB CLI (for engine tests)
shell: bash
run: |
set -e
ver=1.5.3
case "$RUNNER_OS" in
Linux) asset=duckdb_cli-linux-amd64.zip; exe=duckdb ;;
Windows) asset=duckdb_cli-windows-amd64.zip; exe=duckdb.exe ;;
macOS) asset=duckdb_cli-osx-universal.zip; exe=duckdb ;;
esac
# Use RUNNER_TEMP (a native drive-letter path on Windows) so the
# binary path resolves for the Rust test process; $HOME is an
# MSYS path (/c/...) on the Windows runner and Rust cannot find it.
dest="$RUNNER_TEMP/duckdb"
mkdir -p "$dest"
curl -L -o duckdb.zip "https://github.com/duckdb/duckdb/releases/download/v$ver/$asset"
unzip -o duckdb.zip -d "$dest"
bin="$dest/$exe"
if [ "$RUNNER_OS" = "Windows" ]; then bin="$(cygpath -w "$bin")"; fi
echo "using duckdb at: $bin"
echo "DUCKLE_DUCKDB_BIN=$bin" >> "$GITHUB_ENV"
- name: Pre-install DuckDB extensions
shell: bash
# Install once up front so the per-stage LOAD doesn't race with
# parallel test threads downloading the same extension into the
# shared ~/.duckdb cache.
run: |
"$DUCKLE_DUCKDB_BIN" :memory: -c "INSTALL postgres; INSTALL mysql; INSTALL sqlite; INSTALL excel; INSTALL httpfs; INSTALL iceberg; INSTALL delta; INSTALL ducklake; INSTALL vss; INSTALL fts; INSTALL inet;"
# The desktop crate embeds duckle-runner AND duckle-mcp at compile time
# via build.rs include_bytes!, so both binaries must exist before anything
# that compiles apps/desktop. Build them in the dev profile so the engine
# compilation is shared with the cargo test below.
- name: Build + stage duckle-runner + duckle-mcp (embedded into the desktop app)
shell: bash
run: |
set -e
cargo build -p duckle-runner -p duckle-mcp
mkdir -p apps/desktop/bin
if [ "$RUNNER_OS" = "Windows" ]; then
cp target/debug/duckle-runner.exe apps/desktop/bin/duckle-runner.exe
cp target/debug/duckle-mcp.exe apps/desktop/bin/duckle-mcp.exe
else
cp target/debug/duckle-runner apps/desktop/bin/duckle-runner
cp target/debug/duckle-mcp apps/desktop/bin/duckle-mcp
fi
- name: Test
run: cargo test --workspace
# Style checks are informational - they report problems without
# failing the build.
- name: Format check
continue-on-error: true
run: cargo fmt --all --check
- name: Clippy
continue-on-error: true
run: cargo clippy --workspace --all-targets
# Smoke build of the desktop release binary - the exact same command
# the release workflow runs. Catches feature-flag regressions like
# the v0.0.7 bug where `cargo build --release` (without
# `--features custom-protocol`) silently shipped a binary that loaded
# `http://localhost:5173` inside the Tauri WebView instead of the
# embedded frontend. `cargo test --workspace` never exercises this
# path, so the bug only surfaces when someone downloads + launches
# the published artifact.
desktop-release-build:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Free disk space
shell: bash
run: |
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc \
/opt/hostedtoolcache/CodeQL /usr/local/.ghcup /usr/local/share/boost \
/usr/local/share/powershell /usr/share/swift || true
sudo docker image prune --all --force || true
df -h /
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: frontend/package-lock.json
- name: Install frontend deps
run: npm --prefix frontend ci
- name: Build frontend (embedded into the Rust binary)
run: npm --prefix frontend run build
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Install Linux WebView deps (Tauri)
run: |
sudo apt-get update
sudo apt-get install -y \
libwebkit2gtk-4.1-dev libgtk-3-dev \
libayatana-appindicator3-dev librsvg2-dev libsoup-3.0-dev
# Build + stage duckle-runner + duckle-mcp first: the desktop crate embeds
# both at compile time (build.rs include_bytes!). Release profile so the
# engine build is shared with the desktop release build below.
- name: Build + stage duckle-runner + duckle-mcp (embedded into the desktop app)
run: |
set -e
cargo build --release -p duckle-runner -p duckle-mcp
mkdir -p apps/desktop/bin
cp target/release/duckle-runner apps/desktop/bin/duckle-runner
cp target/release/duckle-mcp apps/desktop/bin/duckle-mcp
- name: Build raw Duckle binary (release workflow command)
run: cargo build --release --manifest-path apps/desktop/Cargo.toml --features custom-protocol
- name: Verify embedded frontend (not devUrl) is in binary
# Grep the built binary for the frontend's main JS chunk filename.
# If tauri-codegen embedded devUrl instead, this string will be
# absent and the check fails - catching the v0.0.7-class bug.
run: |
set -e
asset=$(ls frontend/dist/assets/index-*.js | head -1 | xargs basename)
if grep -q "$asset" target/release/duckle; then
echo "OK: embedded frontend asset '$asset' is present in the binary"
else
echo "FAIL: frontend asset '$asset' NOT found in binary - tauri-codegen likely embedded devUrl"
exit 1
fi
# Live PostgreSQL integration tests. Runs against a real postgres
# service container; engine tests that don't see DUCKLE_PG_HOST in the
# main matrix job skip cleanly, so this is the only place they execute.
postgres-integration:
runs-on: ubuntu-latest
services:
postgres:
image: pgvector/pgvector:pg16
env:
POSTGRES_PASSWORD: pgtest
POSTGRES_DB: postgres
ports: ['5432:5432']
options: >-
--health-cmd "pg_isready -U postgres"
--health-interval 5s
--health-timeout 5s
--health-retries 20
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Install DuckDB CLI
run: |
set -e
curl -L -o duckdb.zip https://github.com/duckdb/duckdb/releases/download/v1.5.3/duckdb_cli-linux-amd64.zip
mkdir -p "$RUNNER_TEMP/duckdb"
unzip -o duckdb.zip -d "$RUNNER_TEMP/duckdb"
echo "DUCKLE_DUCKDB_BIN=$RUNNER_TEMP/duckdb/duckdb" >> "$GITHUB_ENV"
- name: Pre-install postgres extension
run: |
"$DUCKLE_DUCKDB_BIN" :memory: -c "INSTALL postgres;"
- name: Run PostgreSQL integration tests
env:
DUCKLE_PG_HOST: localhost
DUCKLE_PG_PORT: '5432'
DUCKLE_PG_DB: postgres
DUCKLE_PG_USER: postgres
DUCKLE_PG_PASS: pgtest
run: cargo test -p duckle-duckdb-engine --test execution -- pg_
# Live MySQL integration tests (also covers MariaDB, same wire).
mysql-integration:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: mytest
MYSQL_DATABASE: ducktest
ports: ['3306:3306']
options: >-
--health-cmd "mysqladmin ping -h localhost -p$$MYSQL_ROOT_PASSWORD"
--health-interval 5s
--health-timeout 5s
--health-retries 30
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Install DuckDB CLI
run: |
set -e
curl -L -o duckdb.zip https://github.com/duckdb/duckdb/releases/download/v1.5.3/duckdb_cli-linux-amd64.zip
mkdir -p "$RUNNER_TEMP/duckdb"
unzip -o duckdb.zip -d "$RUNNER_TEMP/duckdb"
echo "DUCKLE_DUCKDB_BIN=$RUNNER_TEMP/duckdb/duckdb" >> "$GITHUB_ENV"
- name: Pre-install mysql extension
run: |
"$DUCKLE_DUCKDB_BIN" :memory: -c "INSTALL mysql;"
- name: Run MySQL integration tests
env:
DUCKLE_MYSQL_HOST: 127.0.0.1
DUCKLE_MYSQL_PORT: '3306'
DUCKLE_MYSQL_DB: ducktest
DUCKLE_MYSQL_USER: root
DUCKLE_MYSQL_PASS: mytest
run: cargo test -p duckle-duckdb-engine --test execution -- mysql_
# Live MinIO integration tests (covers all S3-compatible: MinIO, R2, B2).
# MinIO needs `server /data` as the container command; GitHub Actions
# service containers can't override CMD, so we run it as a step.
minio-integration:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Start MinIO + create bucket
run: |
set -e
docker run -d --name minio -p 9000:9000 -p 9001:9001 \
-e MINIO_ROOT_USER=minioadmin -e MINIO_ROOT_PASSWORD=minioadmin \
minio/minio:latest server /data --console-address ":9001"
for i in $(seq 1 30); do
if curl -fs http://localhost:9000/minio/health/live >/dev/null 2>&1; then
echo "MinIO is up"; break
fi
sleep 2
done
# mc isn't in the minio server image, so use the standalone client.
curl -fsSL https://dl.min.io/client/mc/release/linux-amd64/mc -o /usr/local/bin/mc
chmod +x /usr/local/bin/mc
mc alias set local http://localhost:9000 minioadmin minioadmin
mc mb local/duckle-test
- name: Install DuckDB CLI
run: |
set -e
curl -L -o duckdb.zip https://github.com/duckdb/duckdb/releases/download/v1.5.3/duckdb_cli-linux-amd64.zip
mkdir -p "$RUNNER_TEMP/duckdb"
unzip -o duckdb.zip -d "$RUNNER_TEMP/duckdb"
echo "DUCKLE_DUCKDB_BIN=$RUNNER_TEMP/duckdb/duckdb" >> "$GITHUB_ENV"
- name: Seed MinIO with a test object
run: |
set -e
# Upload a small parquet file to s3://duckle-test/orders.parquet
# via the DuckDB CLI itself, so the source test reads it back.
"$DUCKLE_DUCKDB_BIN" :memory: -c "
INSTALL httpfs; LOAD httpfs;
CREATE OR REPLACE SECRET seed (
TYPE S3,
KEY_ID 'minioadmin',
SECRET 'minioadmin',
REGION 'us-east-1',
ENDPOINT 'localhost:9000',
URL_STYLE 'path',
USE_SSL false
);
COPY (SELECT * FROM (VALUES (1,'alice'),(2,'bob'),(3,'carol')) t(id,name))
TO 's3://duckle-test/orders.parquet' (FORMAT PARQUET);
"
- name: Run MinIO integration tests
env:
DUCKLE_MINIO_HOST: localhost
DUCKLE_MINIO_PORT: '9000'
DUCKLE_MINIO_BUCKET: duckle-test
DUCKLE_MINIO_ACCESS_KEY: minioadmin
DUCKLE_MINIO_SECRET_KEY: minioadmin
run: cargo test -p duckle-duckdb-engine --test execution -- minio_