# Forgejo/Codeberg CI — THE GATE (plan §1.17).
#
# Codeberg is the only place anyone pushes; it push-mirrors to GitHub. This
# Forgejo workflow is the correctness gate; GitHub Actions on the mirror only
# publishes (.github/workflows/). Jobs:
#   fmt          cargo fmt --check
#   clippy       -D warnings on the linted crates
#   deny         cargo deny check
#   test-sqlite  cargo test (default members) + cargo test -p mentat --features mino
#   test-pg      matrix pg13..pg18, cargo pgrx test
#   test-mino    cargo test -p mino-rs
#   test-ffi     build + test crates/sqlite/ffi
#   test-sqlite-ext  build the SQLite loadable extension + sqlite3 smoke test
#   test-duckdb  build the DuckDB extension + load/query smoke test
#   nix-build    flake builds the SQLite CLI + one extension
#
# Forgejo Actions syntax is nearly identical to GitHub Actions.

name: ci

on:
  push:
  pull_request:

concurrency:
  group: ci-${{ github.ref }}
  cancel-in-progress: true

env:
  CARGO_TERM_COLOR: always
  CARGO_INCREMENTAL: "0"
  PGRX_VERSION: "0.17.0"
  RUST_TOOLCHAIN: "1.90.0"
  DUCKDB_VERSION: "v1.5.5"

jobs:
  # --- SQLite / shared front-end: no postgres, no clang required ---------
  fmt:
    name: fmt
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@v4
      - name: Install Rust
        run: |
          curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
            | sh -s -- -y --default-toolchain ${{ env.RUST_TOOLCHAIN }} --component rustfmt
          echo "$HOME/.cargo/bin" >> $GITHUB_PATH
      - name: cargo fmt --check
        run: cargo fmt --all -- --check

  clippy:
    name: clippy (-D warnings)
    runs-on: ubuntu-latest
    timeout-minutes: 20
    steps:
      - uses: actions/checkout@v4
      - name: Install build deps
        run: |
          sudo apt-get update
          sudo apt-get install -y --no-install-recommends \
              build-essential pkg-config libsqlite3-dev libssl-dev
      - name: Install Rust
        run: |
          curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
            | sh -s -- -y --default-toolchain ${{ env.RUST_TOOLCHAIN }} --component clippy
          echo "$HOME/.cargo/bin" >> $GITHUB_PATH
      - name: Cache cargo
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ci-clippy-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }}
          restore-keys: ci-clippy-${{ runner.os }}-
      # Lint the SQLite side + shared front-end + mino (default members). The
      # pgrx crate's clippy runs in test-pg where pg_config/pgrx are set up.
      - name: cargo clippy
        run: cargo clippy --workspace --exclude pg_mentat --exclude mentat_duckdb --exclude mentat_sqlite_ext -- -D warnings

  deny:
    name: cargo deny
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@v4
      - name: Install Rust
        run: |
          curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
            | sh -s -- -y --default-toolchain ${{ env.RUST_TOOLCHAIN }}
          echo "$HOME/.cargo/bin" >> $GITHUB_PATH
      - name: Install cargo-deny
        run: cargo install --locked cargo-deny
      - name: cargo deny check
        run: cargo deny check

  test-sqlite:
    name: test-sqlite (+ mino feature)
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      - uses: actions/checkout@v4
      - name: Install build deps
        run: |
          sudo apt-get update
          sudo apt-get install -y --no-install-recommends \
              build-essential pkg-config libsqlite3-dev libssl-dev
      - name: Install Rust
        run: |
          curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
            | sh -s -- -y --default-toolchain ${{ env.RUST_TOOLCHAIN }}
          echo "$HOME/.cargo/bin" >> $GITHUB_PATH
      - name: Cache cargo
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ci-sqlite-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }}
          restore-keys: ci-sqlite-${{ runner.os }}-
      # Default members = the SQLite side + shared front-end + mino + mentatd;
      # never touches pg_config/libclang.
      - name: cargo test (default members)
        run: cargo test
      - name: cargo test -p mentat --features mino
        run: cargo test -p mentat --features mino

  test-mino:
    name: test-mino
    runs-on: ubuntu-latest
    timeout-minutes: 20
    steps:
      - uses: actions/checkout@v4
      - name: Install Rust
        run: |
          curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
            | sh -s -- -y --default-toolchain ${{ env.RUST_TOOLCHAIN }}
          echo "$HOME/.cargo/bin" >> $GITHUB_PATH
      - name: Cache cargo
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ci-mino-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }}
          restore-keys: ci-mino-${{ runner.os }}-
      - name: cargo test -p mino-rs
        run: cargo test -p mino-rs

  test-ffi:
    name: test-ffi (C ABI)
    runs-on: ubuntu-latest
    timeout-minutes: 20
    steps:
      - uses: actions/checkout@v4
      - name: Install build deps
        run: |
          sudo apt-get update
          sudo apt-get install -y --no-install-recommends \
              build-essential pkg-config libsqlite3-dev libssl-dev
      - name: Install Rust
        run: |
          curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
            | sh -s -- -y --default-toolchain ${{ env.RUST_TOOLCHAIN }}
          echo "$HOME/.cargo/bin" >> $GITHUB_PATH
      - name: Cache cargo
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ci-ffi-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }}
          restore-keys: ci-ffi-${{ runner.os }}-
      - name: build + test crates/sqlite/ffi
        run: |
          cargo build -p mentat_ffi
          cargo test -p mentat_ffi

  test-sqlite-ext:
    name: test-sqlite-ext (loadable extension)
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      - uses: actions/checkout@v4
      - name: Install build deps + sqlite3 CLI
        run: |
          sudo apt-get update
          sudo apt-get install -y --no-install-recommends \
              build-essential pkg-config libsqlite3-dev libssl-dev sqlite3
          sqlite3 --version
      - name: Install Rust
        run: |
          curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
            | sh -s -- -y --default-toolchain ${{ env.RUST_TOOLCHAIN }} --component clippy
          echo "$HOME/.cargo/bin" >> $GITHUB_PATH
      - name: Cache cargo
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ci-sqlite-ext-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }}
          restore-keys: ci-sqlite-ext-${{ runner.os }}-
      - name: clippy + unit tests
        run: |
          cargo clippy -p mentat_sqlite_ext -- -D warnings
          cargo test -p mentat_sqlite_ext
      - name: Build the loadable extension
        run: cargo build -p mentat_sqlite_ext
      - name: Only the init symbol is exported (no leaked sqlite3_* API)
        run: |
          nm -D --defined-only target/debug/libmentat_sqlite.so | awk '{print $3}' \
            | grep -E '^sqlite3_' | tee /tmp/syms
          test "$(cat /tmp/syms)" = "sqlite3_mentatsqlite_init"
      - name: Load + query smoke test (edn_t/edn_q/edn_pull/edn_eval + json_each JOIN)
        working-directory: crates/sqlite/ext
        run: bash test/smoke.sh

  # --- PostgreSQL extension: needs pgrx + a per-major PostgreSQL ---------
  test-pg:
    name: test-pg (pg${{ matrix.pg }})
    runs-on: ubuntu-latest
    timeout-minutes: 40
    strategy:
      fail-fast: false
      matrix:
        pg: [13, 14, 15, 16, 17, 18]
    steps:
      - uses: actions/checkout@v4
      - name: Install build deps
        run: |
          sudo apt-get update
          sudo apt-get install -y --no-install-recommends \
              build-essential pkg-config libpq-dev libclang-dev clang \
              libreadline-dev zlib1g-dev flex bison
      - name: Install Rust
        run: |
          curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
            | sh -s -- -y --default-toolchain ${{ env.RUST_TOOLCHAIN }}
          echo "$HOME/.cargo/bin" >> $GITHUB_PATH
      - name: Cache cargo
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ci-pg${{ matrix.pg }}-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }}
          restore-keys: ci-pg${{ matrix.pg }}-${{ runner.os }}-
      - name: Install cargo-pgrx
        run: cargo install --locked cargo-pgrx --version "${PGRX_VERSION}"
      - name: pgrx init (download PG${{ matrix.pg }})
        # A pgrx-managed PG (user-owned ~/.pgrx) so `cargo pgrx test` can copy
        # the .so into its lib dir without root.
        run: cargo pgrx init --pg${{ matrix.pg }} download
      - name: cargo pgrx test
        working-directory: crates/pg/pg_mentat
        run: cargo pgrx test --no-default-features --features pg${{ matrix.pg }} pg${{ matrix.pg }}

  # --- DuckDB extension: build + load/query smoke test ------------------
  test-duckdb:
    name: test-duckdb
    runs-on: ubuntu-latest
    timeout-minutes: 40
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: recursive
      - name: Install build deps
        run: |
          sudo apt-get update
          sudo apt-get install -y --no-install-recommends \
              build-essential pkg-config libsqlite3-dev libssl-dev unzip python3
      - name: Install Rust
        run: |
          curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
            | sh -s -- -y --default-toolchain ${{ env.RUST_TOOLCHAIN }}
          echo "$HOME/.cargo/bin" >> $GITHUB_PATH
      - name: Cache cargo
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ci-duckdb-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }}
          restore-keys: ci-duckdb-${{ runner.os }}-
      - name: Build the loadable extension
        working-directory: crates/duckdb
        run: |
          make configure
          make debug
      - name: Fetch a matching DuckDB CLI
        run: |
          set -euxo pipefail
          curl -fsSL \
            "https://github.com/duckdb/duckdb/releases/download/${DUCKDB_VERSION}/duckdb_cli-linux-amd64.zip" \
            -o /tmp/duckdb.zip
          mkdir -p /tmp/duckdb-cli
          unzip -o /tmp/duckdb.zip -d /tmp/duckdb-cli
          /tmp/duckdb-cli/duckdb --version
      - name: Load + query smoke test (edn_t/edn_q/edn_pull/edn_eval + a native JOIN)
        working-directory: crates/duckdb
        run: DUCKDB=/tmp/duckdb-cli/duckdb bash test/smoke.sh

  # --- Nix flake: builds the SQLite CLI + one extension major -----------
  nix-build:
    name: nix-build
    runs-on: ubuntu-latest
    timeout-minutes: 60
    steps:
      - uses: actions/checkout@v4
      - uses: cachix/install-nix-action@v27
        with:
          extra_nix_config: |
            experimental-features = nix-command flakes
      - name: Build mentat-cli + one extension
        # __noChroot derivations fetch crates from the network; relaxed sandbox.
        run: |
          nix build --option sandbox relaxed .#mentat-cli .#mentatd .#pg_mentat-pg16
