この記事は、dbt Advent Calendar 2024 シリーズ2 の3日目の記事です。

dbt Advent Calendar 2024
https://qiita.com/advent-calendar/2024/dbt

dbt(Data Build Tool)の自動検証ツールに、
dbt-checkpointというものがあり、試してみたので導入手順メモを残しておきます。

dbt-checkpoint/dbt-checkpoint | GitHub
https://github.com/dbt-checkpoint/dbt-checkpoint

このエントリでは、公式とは異なる手順で導入します(理由は後ほど記載)。

導入手順

dbtのプロジェクトを準備

Gitのリポジトリ用にディレクトリを作ります。

mkdir dbt-checkpoint-study && cd $_
git init

Python仮想環境を用意します。

python -m venv venv
. venv/bin/activate
echo "venv" >> .gitignore

dbtをインストールします(ここでは、とりあえずsqlite向けを入れます)。

pip install dbt-sqlite
pip freeze > requirements.txt

dbtプロジェクトを初期化します。

dbt init sample
echo "logs" >> .gitignore

sample/profiles.ymlを用意します。

sample/profiles.yml

sample:
  outputs:
    dev:
      type: sqlite
      threads: 1
      database: sample
      schema: main
      schemas_and_paths:
        main: /tmp/dbt-sample.db
      schema_directory: /tmp/dbt-sample
  target: dev

動作確認します。

bash -c 'cd sample && dbt debug'

プロジェクトにdbt-checkpointを設定

dbt-checkpointを実行するMakefileとpre-commitを導入します。

.pre-commit-config.yaml

repos:
  - repo: local
    hooks:
      - id: dbt_checkpoint
        name: dbt_checkpoint
        entry: make -C sample check -k
        language: system
        pass_filenames: false

sample/Makefile ※一部のルールしか記載していないので、必要に応じて要追記

SOURCES := $(shell find . -name "*.yml" -or -name "*.sql")
MANIFEST := target/manifest.json
CATALOG := target/catalog.json
CHECKS := check_model_columns_have_desc check_script_semicolon

setup: # install dbt-checkpoint
	@test -d .venv || python -m venv .venv
	@.venv/bin/pip freeze | grep pre_commit_hooks | grep dbt-checkpoint --silent || .venv/bin/pip install git+https://github.com/dbt-checkpoint/dbt-checkpoint.git@v2.0.6
$(MANIFEST): $(SOURCES)
	@.venv/bin/python -m dbt_checkpoint.dbt_parse
$(CATALOG): $(SOURCES)
	@.venv/bin/python -m dbt_checkpoint.dbt_docs_generate
check_model_columns_have_desc: $(MANIFEST) $(CATALOG)
	@find models -name "*.sql" | xargs .venv/bin/python -m dbt_checkpoint.check_model_columns_have_desc
check_script_semicolon: $(MANIFEST)
	@find models -name "*.sql" | xargs .venv/bin/python -m dbt_checkpoint.check_script_semicolon

check: setup $(CHECKS)
clean: # cleanup
	rm -rf .venv
	rm -rf target

未インストールの場合、以下を参照してpre-commitをインストールしておきます。

pre-commit
https://pre-commit.com/

リポジトリにpre-commitのhookを登録します。

pre-commit install

コミットすると、dbt_checkpointが実行されることが確認できます。

git add .
git commit -a -m "initial commit"
$ git commit -a -m "initial commit"
bug: pre-commit's script is installed in migration mode
run `pre-commit install -f --hook-type pre-commit` to fix this

Please report this bug at https://github.com/pre-commit/pre-commit/issues
dbt_checkpoint...........................................................Passed

意図的に検証NGになるように修正してみます。 ここでは、カラムのDescritonをコメントアウトします。

sample/models/example/schema.yml


version: 2

models:
  - name: my_first_dbt_model
    description: "A starter dbt model"
    columns:
      - name: id
        # description: "The primary key for this table"
        tests:
          - unique
          - not_null

  - name: my_second_dbt_model
    description: "A starter dbt model"
    columns:
      - name: id
        description: "The primary key for this table"
        tests:
          - unique
          - not_null

Commitを試みると、検証でエラーになることが確認できます。

$ git commit -a -m "fix: column description commentout"
bug: pre-commit's script is installed in migration mode
run `pre-commit install -f --hook-type pre-commit` to fix this

Please report this bug at https://github.com/pre-commit/pre-commit/issues
dbt_checkpoint...........................................................Failed
- hook id: dbt_checkpoint
- exit code: 2

make: Entering directory '/home/takemikami/tmp/dbt-checkpoint-study/sample'
Executing cmd: `dbt parse`
03:01:47  Running with dbt=1.5.11
03:01:47  Registered adapter: sqlite=1.5.0
03:01:47  Performance info: /home/takemikami/tmp/dbt-checkpoint-study/sample/target/perf_info.json

Executing cmd: `dbt docs generate`
03:01:50  Running with dbt=1.5.11
03:01:50  Registered adapter: sqlite=1.5.0
03:01:50  Found 2 models, 4 tests, 0 snapshots, 0 analyses, 311 macros, 0 operations, 0 seed files, 0 sources, 0 exposures, 0 metrics, 0 groups
03:01:50
03:01:50  Concurrency: 1 threads (target='dev')
03:01:50
03:01:50  Building catalog
03:01:50  Catalog written to /home/takemikami/tmp/dbt-checkpoint-study/sample/target/catalog.json

models/example/my_first_dbt_model.sql: following columns are missing description:
- id
make: *** [Makefile:14: check_model_columns_have_desc] Error 123
make: Target 'check' not remade because of errors.
make: Leaving directory '/home/takemikami/tmp/dbt-checkpoint-study/sample'

補足

公式とは異なる手順で導入して理由ですが、
検証をすり抜けてcommitできてしまうケースがあるからです。

モデル(sql),スキーマ(yml)

マニフェスト(manifest.json)

dbt-checkponintによる自動検証

という流れで検証を行うルールの場合、
モデル(sql)の変更をhookに自動検証が行われるようです。
つまり、モデル(sql)と別commitでスキーマ(yml)が変更された時は自動検証されません。

pre-commitでは、
ファイル単位で完結する自動検証(flake8とか)はpass_filenames=true
複数ファイルの関連する自動検証(mypyとか)はpass_filenames=false
で動かす必要があるのですが、
dbt-checkpointは両方のパターン混在しているので、
確実に自動検証が動くようにpass_filenames=false側に倒して導入してみました。

以上。