CI/CD

A project is a git repository, so the pipeline is short: install zsql, put a personal key in ZSQL_API_KEY, run zsql check on pull requests and zsql deploy on merge. The deployed branch is whatever --branch names, and the job fails when a test fails because zsql exits non-zero.

What you need

  • A personal key (zsk_...) for a user with write access to the project, stored as a CI secret. Query keys cannot deploy. Create keys in the console at https://app.0sql.io (see Accounts); a dedicated “ci” key is easy to revoke.
  • ZSQL_API_KEY set from that secret. It wins over any .zsql file, and nothing is written to disk.
  • ZSQL_SERVER=https://app.0sql.io, unless project.yml or a committed config names the server.
  • --branch. CI checkouts are usually detached (git rev-parse --abbrev-ref HEAD says HEAD), and zsql takes the branch from git. Pass the CI’s branch variable explicitly, always.

GitHub Actions

.github/workflows/zsql.yml:

name: zsql

on:
  pull_request:
  push:
    branches: [main]

env:
  ZSQL_API_KEY: ${{ secrets.ZSQL_API_KEY }}
  ZSQL_SERVER: https://app.0sql.io

jobs:
  check:
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install zsql
        run: curl -fsSL https://0sql.io/install.sh | sh
      - name: Validate and run tests
        run: zsql check --branch "${{ github.head_ref }}"

  deploy:
    if: github.event_name == 'push'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install zsql
        run: curl -fsSL https://0sql.io/install.sh | sh
      - name: Deploy
        run: zsql deploy --branch "${{ github.ref_name }}"

On a pull request, zsql check validates the model and runs the tests on the service without deploying; the branch name only labels the output. On a push to main, zsql deploy --branch main updates tpcds/main. To also deploy feature branches as isolated previews, add their pattern to push.branches and the same step deploys tpcds/<branch>; remove them with zsql remove --yes --branch <branch> when the pull request closes.

GitLab CI

.gitlab-ci.yml:

variables:
  ZSQL_SERVER: https://app.0sql.io

default:
  image: debian:bookworm-slim
  before_script:
    - apt-get update -qq && apt-get install -y -qq curl ca-certificates git
    - curl -fsSL https://0sql.io/install.sh | sh

check:
  stage: test
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
  script:
    - zsql check --branch "$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME"

deploy:
  stage: deploy
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
  script:
    - zsql deploy --branch "$CI_COMMIT_BRANCH"

Store ZSQL_API_KEY as a masked, protected CI/CD variable; it reaches the job as an environment variable, which is where zsql looks first.

Failing on tests

zsql check and zsql deploy exit non-zero when the archive is rejected or when any test fails. In the deploy case the model is already live (the HTTP call returned 200 with test_results.failed > 0), so a red job after a merge means “deployed, and a test broke”: fix forward. To keep a broken model off main, require the check job on pull requests before merging.

deploy tpcds (6240 bytes) as tpcds/main (the production branch) to https://app.0sql.io
deployed tpcds/main: 6 tables, 42 fields, 5 joins, 9 paths, 1 policies
FAILED catalog quantity by month
       --- generated
       ...
tests: 2 passed, 1 failed
Error: tests failed

Protected production branches

A project owner can mark the production branch protected in the console. Then only an owner’s key may deploy to it, and anyone else gets:

Forbidden: deploying to the protected production branch 'main' of tpcds needs an owner

Give the CI key’s user owner access on the project, or keep production deploys to a job that uses an owner’s key. Everyone with write access can still deploy feature branches.

Next steps