SQLFluff on Linux:CI/CDパイプラインでSQLリンティングとコード標準を自動化する

Database tutorial - IT technology blog
Database tutorial - IT technology blog

SQLのコード品質は、開発者がそれぞれ異なるキーワードの大文字・小文字表記、バラバラなインデント、まちまちなクォートスタイルを300個ものファイルで使っているコードベースを引き継いで初めて重要性に気づくものです。SQLFluffはこの問題を解決します — JavaScriptにおけるESLint、PythonにおけるBlackと同様の規律をSQLにもたらします。

MySQL、PostgreSQL、MongoDBを様々なプロジェクトで使ってきた経験から言えば、それぞれに独自の強みとSQLの癖があります。SQLFluffはダイアレクトを認識したリンティングでこれに対応しており、単なるおもちゃのフォーマッターではなく、実際の開発チームで使える実用的なツールとなっています。

クイックスタート:5分でSQLFluffを動かす

pipでインストールできます。システム依存関係も初期設定も不要です:

pip install sqlfluff
sqlfluff --version

意図的に乱雑なSQLのテストファイルを作成します:

select id,name,email FROM users where status='active' and created_at > '2024-01-01'

リンターを実行します:

sqlfluff lint query.sql --dialect postgres

次のような出力が表示されます:

== [query.sql] FAIL
L:   1 | P:   1 | CP01 | Keywords must be consistently upper case.
L:   1 | P:  10 | LT04 | Leading comma enforcement.
L:   1 | P:  17 | LT01 | Expected single space before keyword.

次に自動修正します:

sqlfluff fix query.sql --dialect postgres

SQLFluffはファイルを直接書き換えます。結果は整合性の取れたクリーンなSQL — 手動編集は不要です。これが基本的なワークフローです:lintで問題を確認し、fixで自動修正する。

詳細解説:設定とダイアレクトサポート

毎回フラグを付けてSQLFluffを実行するのはすぐに面倒になります。プロジェクトのルートに.sqlfluff設定ファイルを置けば、自動的に読み込まれます:

[sqlfluff]
dialect = postgres
templater = jinja
max_line_length = 120

[sqlfluff:rules:capitalisation.keywords]
capitalisation_policy = upper

[sqlfluff:rules:capitalisation.identifiers]
capitalisation_policy = lower

[sqlfluff:rules:capitalisation.functions]
capitalisation_policy = upper

[sqlfluff:rules:layout.long_lines]
ignore_comment_clauses = True

あとはプロジェクトのルートからsqlfluff lint .を実行するだけで、設定されたダイアレクトを使ってすべての.sqlファイルを再帰的にリントします。

SQLFluffは標準で幅広いダイアレクトをサポートしています:

  • ansi — 汎用SQL、フォールバックとして最適
  • postgresmysqlsqlite — 定番データベース
  • bigquerysnowflaketsql — クラウド・エンタープライズ向け
  • sparkduckdbhive — 分析エンジン

ルールは異なる懸念事項に対応したカテゴリに整理されています:

  • レイアウト (LT):インデント、スペース、行の長さ、末尾の空白
  • 大文字・小文字 (CP):キーワードと識別子の大文字・小文字表記
  • エイリアス (AL):テーブルとカラムのエイリアス要件
  • 構造 (ST):サブクエリの構造、JOIN条件
  • 参照 (RF):カラム参照、曖昧さの検出

グローバルに無効化せず、特定のルールをインラインで抑制するには:

SELECT *  -- noqa: LT09
FROM really_long_table_name_here;

プロジェクト全体でルールを除外するには:

[sqlfluff]
exclude_rules = LT09, RF01

応用:CI/CD統合

ローカルのリンティングは個々の開発者を助けますが、CI/CDでの強制適用によって、一貫性のないSQLが絶対にmainブランチに入り込まないようになります。主要なプラットフォームでの設定方法を紹介します。

GitHub Actions

# .github/workflows/sql-lint.yml
name: SQLリント

on:
  pull_request:
    paths:
      - '**.sql'

jobs:
  sqlfluff:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Pythonのセットアップ
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'

      - name: SQLFluffのインストール
        run: pip install sqlfluff==3.0.7

      - name: SQLFluffの実行
        run: sqlfluff lint . --dialect postgres --format github-annotation

--format github-annotationフラグがここでの重要なポイントです。エラーをインラインPRアノテーションとして出力するため、レビュワーはCIログを掘り下げることなく、差分上で直接リントの失敗を確認できます。

GitLab CI

# .gitlab-ci.yml
sql-lint:
  image: python:3.11-slim
  stage: test
  script:
    - pip install sqlfluff==3.0.7
    - sqlfluff lint . --dialect postgres
  only:
    changes:
      - "**/*.sql"

Pre-commitフック

pre-commitフックはCIに到達する前に問題を検出します。フィードバックが早くなり、パイプラインの無駄な時間を削減できます:

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/sqlfluff/sqlfluff
    rev: 3.0.7
    hooks:
      - id: sqlfluff-lint
        args: [--dialect, postgres]
      - id: sqlfluff-fix
        args: [--dialect, postgres]
pip install pre-commit
pre-commit install
pre-commit run --all-files

これにより、git commitのたびに自動的にSQLのリンティングと修正が行われます。チームメンバーは手動で何かを実行することを覚える必要がありません。

dbtプロジェクトのサポート

プロジェクトでdbtを使用している場合、SQLFluffはJinjaテンプレートをネイティブに処理できます:

[sqlfluff]
templater = dbt
dialect = postgres

[sqlfluff:templater:dbt]
project_dir = ./dbt_project
profiles_dir = ~/.dbt
sqlfluff lint models/ --templater dbt

実践的なヒント

最初は緩く始め、徐々に厳しくする

レガシープロジェクトにSQLFluffを導入すると、初日から数百件の違反が出る可能性があります。マージ前にすべてを修正しようとすると、導入が頓挫してしまいます。代わりに、既存ファイルの先頭に一時的に-- noqa: allを追加し、その後のPRで1ファイルずつ修正していきましょう。全員の作業を止めることなく、無理のないロールアウトが可能になります。

CIでは変更されたファイルのみをリント

大規模なコードベースでは、すべてのPRで全体をリントすると時間がかかります。変更されたファイルのみに絞りましょう:

git diff --name-only origin/main | grep '\.sql$' | xargs sqlfluff lint --dialect postgres

バージョンを固定する

SQLFluffは頻繁にリリースされ、マイナーバージョン間でルールの動作が変わることがあります。予期しないCIの失敗を避けるためにバージョンを固定しましょう:

# requirements-dev.txt
sqlfluff==3.0.7

CIではLintとFixを分離する

lintステップはビルドを失敗させるべきです。fixステップは開発者ツールとしてのみ使用します — CIが再フォーマットされたファイルを自動的にリポジトリにコミットするのは避けてください。Makefileで明示的に分離しましょう:

.PHONY: lint-sql fix-sql

lint-sql:
	sqlfluff lint . --dialect postgres

fix-sql:
	sqlfluff fix . --dialect postgres

VS Code統合

SQLFluff VS Code拡張機能(dorzey作)は、入力中にインラインでリントエラーを表示します。プロジェクトのvenvバイナリを指定することで、CIと同じバージョンを使用できます:

// .vscode/settings.json
{
  "sqlfluff.dialect": "postgres",
  "sqlfluff.executablePath": "${workspaceFolder}/.venv/bin/sqlfluff"
}

ローカル開発でのpre-commitフックとプルリクエストのCI強制適用を組み合わせることで、二層の安全網が形成されます。問題はコミット前に検出され、漏れたものはマージ前に検出されます。数週間後には、チームはSQLスタイルについて考える必要がなくなります — 自動的に一貫性が保たれるようになるのです。

PostgreSQLプロジェクトでもっと早くやっておけばよかったと思うこと:最初からSQLFluffの厳格な設定を適用すること。数百のSQLファイルに後から一貫性を持たせるのは面倒な作業ですが、早期に導入すれば簡単に避けられます。

Share: