Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

CI and GitHub Actions

GitHub Action

# .github/workflows/sqlsift.yml
name: SQL Lint
on: [push, pull_request]
jobs:
  sqlsift:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: yukikotani231/sqlsift@main  # or pin a release tag
        with:
          schema: db/schema.sql           # or schema-dir: db/migrations
          files: queries/**/*.sql

Errors are shown as annotations on the pull request diff. All inputs are optional when you have a sqlsift.toml:

InputDescription
filesQuery files (space-separated paths or globs)
schema / schema-dirSchema files, or a directory of migrations
dialectpostgresql, mysql, sqlite, or (alpha) snowflake, bigquery, redshift, databricks
configPath to sqlsift.toml
disableRules to disable, e.g. E0006 E0008
sarif-fileAlso write a SARIF report (see below)
fail-on-errorFail the step on errors (default true)
diff-baseReport only diagnostics that are new compared with this branch, tag or commit, e.g. ${{ github.base_ref }} (see below)
versionsqlsift-cli version from npm (default latest)
cli-pathUse an existing sqlsift binary instead of installing from npm

The exit-code output is 0 (clean), 1 (errors found) or 2 (configuration error).

Any CI, with plain commands

npx sqlsift-cli check --schema schema.sql 'queries/**/*.sql'

The exit code is non-zero when errors are found. Inside a GitHub Actions job that runs sqlsift itself (a make lint step, a script, a container), add --format github to get annotations on the pull request diff.

Report only what a pull request introduces

In a project that already has diagnostics, the ones a pull request adds are easy to miss among the old ones. With diff-base, the action checks the pull request's base too and reports only what is new, with no baseline file to commit or keep up to date:

on: [push, pull_request]
jobs:
  sqlsift:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: yukikotani231/sqlsift@main
        with:
          schema-dir: db/migrations
          files: queries/**/*.sql
          diff-base: ${{ github.base_ref }}

A pull request that drops or renames a column fails with the queries it breaks, even when other queries already had problems. github.base_ref is empty outside pull requests, so pushes to main still report every diagnostic.

How it works: the action fetches the base (one commit, from the repository the workflow runs in), checks it out in a temporary git worktree, runs the same check there with --write-baseline into a temporary baseline file, and then checks the pull request against that baseline (see Baseline for how diagnostics are matched). On a pull_request event the checkout is the merge commit, so this compares the result of merging with the base branch as it is now. No token beyond the default one is needed, and pull requests from forks work the same way. The SARIF file (sarif-file) has only the new diagnostics too.

diff-base takes a branch or tag name (fetched from origin), or a commit SHA, e.g. ${{ github.event.pull_request.base.sha }}. Good to know:

  • The base is checked with its own sqlsift.toml and the same inputs, run from the same directory. If it can't be checked at all (no sqlsift.toml or no query files there yet, a schema file named in schema that the pull request adds), the action prints a warning and reports every diagnostic. Prefer a glob or schema-dir for schema files, so that a new migration file doesn't make the base check fail.
  • Diagnostics are matched by file, rule and statement, so a renamed query file's existing problems are reported as new.
  • A committed baseline (baseline in sqlsift.toml) is not used in this mode: everything the base already reports is hidden anyway.

Rolling out a rule gradually

Make the rule a warning and cap the number of warnings with --max-warnings (or max_warnings in sqlsift.toml), so the backlog can only shrink:

sqlsift check -W missing-required-column --max-warnings 12

Adopting sqlsift on an existing codebase

When a project already has many diagnostics, record them in a baseline and fail CI only on new ones:

sqlsift check --write-baseline          # writes sqlsift-baseline.json; commit it
# sqlsift.toml
baseline = "sqlsift-baseline.json"

From then on sqlsift check (and the editor) hides the recorded diagnostics, and new ones fail the check as usual. When a recorded problem is fixed, sqlsift prints a note; re-run --write-baseline to shrink the file. See Baseline.

Re-check everything when the schema changes

sqlsift's main job is catching queries broken by a schema or migration change, and those query files usually aren't in the PR diff. The simplest setup is to always check every query file, as above: sqlsift checks hundreds of files in well under a second. If you only check changed files, check all of them whenever the schema changes:

on: pull_request
jobs:
  sqlsift:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - id: changed
        env:
          BASE: ${{ github.event.pull_request.base.sha }}
        run: |
          changed=$(git diff --name-only --diff-filter=d "$BASE" HEAD)
          if grep -q '^db/' <<< "$changed"; then
            files='queries/**/*.sql'  # schema changed: check every query
          else
            files=$(grep '^queries/.*\.sql$' <<< "$changed" | tr '\n' ' ' || true)
          fi
          echo "files=$files" >> "$GITHUB_OUTPUT"
      - if: steps.changed.outputs.files != ''
        uses: yukikotani231/sqlsift@main
        with:
          schema-dir: db/migrations
          files: ${{ steps.changed.outputs.files }}

GitHub Code Scanning (SARIF)

Show results in the Security tab and as code scanning alerts:

jobs:
  sqlsift:
    runs-on: ubuntu-latest
    permissions:
      security-events: write
    steps:
      - uses: actions/checkout@v4
      - uses: yukikotani231/sqlsift@main
        with:
          schema: db/schema.sql
          files: queries/**/*.sql
          sarif-file: results.sarif
          fail-on-error: "false"
      - uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: results.sarif