tbls + GitHub Actions で DB ドキュメント自動生成
BABYJOB で私たちが開発している保活サービス「えんさがそっ♪」では tbls を活用してデータベース定義書の生成を自動化しています。
tbls とは
(GitHub リポジトリの README から抜粋)
- Go で書かれた、シングルバイナリで動作する CI フレンドリーなデータベース・ドキュメンテーション・ツールです
- Markdown など色々なフォーマットでデータベース定義書を生成することができます
- MySQL、PostgreSQL のような定番の DBMS から BigQuery や Cloud Spanner、Amazon Redshift 等のデータソースにも対応しています
tbls を GitHub Actions で動作させる例
前知識
- データベースは PostgreSQL(
db
コンテナ) - アプリケーションの構築には PHP の Laravel フレームワームを使用している
- Laravel の artisan コマンドをラップしたコンテナ(
migrate
コンテナ)を用意し、データベースマイグレーションを実行する - データベース定義書は
プロジェクトルート/docs/db/
配下に生成される
フレームワーク依存の細かいところは読み流して頂いて、全体の雰囲気をつかんで頂けると嬉しいです 🥰
docker-compose.yml のイメージ
version: "3.8"
services:
#
# データベースコンテナ
#
db:
image: postgres:14.5-bullseye
environment:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: mydb
POSTGRES_INITDB_ARGS: "--encoding=UTF-8 --locale=C"
TZ: Asia/Tokyo
ports:
- "5432:5432"
volumes:
- db-data:/var/lib/postgresql/data
healthcheck:
test: "psql -U postgres -l"
interval: 1s
timeout: 1s
retries: 5
# この記事とは関係がないサービス定義
# #
# # Laravel で構築したアプリケーションコンテナ
# #
# app:
# build:
# context: .
# dockerfile: docker/app.Dockerfile
# environment:
# APP_ENV: local
# DB_HOST: db
# ports:
# - "8000:80"
# この記事とは関係がないサービス定義
# #
# # Laravel の artisan コマンドをラップしたマイグレーション実行+シードデータ投入用コンテナ
# #
# seed:
# build:
# context: .
# dockerfile: docker/migrate.Dockerfile
# environment:
# APP_ENV: local
# DB_HOST: db
# command: migrate --seed
# depends_on:
# db:
# condition: service_healthy
#
# Laravel の artisan コマンドをラップしたマイグレーション実行用コンテナ
#
migrate:
build:
context: .
dockerfile: docker/migrate.Dockerfile
environment:
APP_ENV: local
DB_HOST: db
depends_on:
db:
condition: service_healthy
# NOTE: docker-compose up 時はこのサービスを実行しない
# https://gotohayato.com/content/505/
profiles:
- extra
#
# データベース定義書を生成するコンテナ(tbls コマンドを実行するコンテナ)
#
doc-db:
image: ghcr.io/k1low/tbls:latest
volumes:
- $PWD/docs:/work
command: doc pg://postgres:postgres@db/mydb?sslmode=disable /work/db --config=/work/tbls.yml --rm-dist
# NOTE: docker-compose up 時はこのサービスを実行しない
# https://gotohayato.com/content/505/
profiles:
- extra
volumes:
db-data:
備考
ちなみに、ローカル開発環境などで Docker コンテナでアプリを起動させる場合は、下記のような手順になります。
docker-compose build --parallel app seed
# ① db 起動 + app 起動 → (db のヘルスチェック待ち) → ② seed(マイグレーション+シード投入)起動
docker-compose up
GitHub Action 定義のイメージ
name: Document CI
# NOTE: tbls の設定ファイル、または、マイグレーションファイルに変更が発生した Pull Request で、
# この Action を実行する。
on:
pull_request:
branches: ["**"]
paths:
- 'docs/tbls.yml'
- 'database/migrations/*'
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v3
with:
ref: ${{ github.head_ref }}
# Tips: 「巨大なマスターデータ投入SQL①②」の実行(時間がかかる)は
# データベース定義書の生成と関係がないので、実行時間短縮のため
# データベース定義書の生成の前に実行済み扱いにしている。
- name: "Generate database document"
run: |
set -x
docker-compose build migrate
docker-compose up -d db
docker-compose run --entrypoint "php artisan migrate:install" migrate
docker-compose exec -T db psql -U postgres mydb -c "insert into migrations (migration, batch) values ('巨大なマスターデータ投入SQL①', 1)"
docker-compose exec -T db psql -U postgres mydb -c "insert into migrations (migration, batch) values ('巨大なマスターデータ投入SQL②', 1)"
docker-compose up migrate
docker-compose up doc-db
git status
git add -N .
echo "db_doc_generated=$(if git diff --quiet; then echo "false"; else echo "true"; fi)" >> $GITHUB_ENV
# Tips: DB ドキュメントが追加/更新された場合の追加 push による Action 実行は無駄なので、
# コミットコメントに [ci skip] を付与して Action 実行されないようにしている。
- name: "Push database document"
if: ${{ env.db_doc_generated == 'true' }}
run: |
set -x
git config user.name github-actions[bot]
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
git status
git add .
git commit -m "[ci skip] generate database document"
git push origin HEAD
実行結果の例(カラム追加したとき)
テータベース定義書の更新コミットの履歴
テータベース定義書の更新差分
- テーブル定義書(Markdown)
- ER 図(SVG)
データベース定義書を自動生成するときの Tips
① 実行に時間がかかる SQL はスキップする
データベース定義書を生成する場合、DDL だけ実行されればよいので、それ以外のマスターデータ投入などのSQLは実行済み扱いにしてスキップすると、Action の実行時間の短縮になります。
docker-compose exec -T db psql -U postgres mydb -c "insert into migrations (migration, batch) values ('巨大なマスターデータ投入SQL①', 1)"
docker-compose exec -T db psql -U postgres mydb -c "insert into migrations (migration, batch) values ('巨大なマスターデータ投入SQL②', 1)"
② データベース定義書の生成コミットの push 時に Action 実行しない
GitHub Actions の仕様で、on.pull_request.paths
で指定したファイルに変更が発生したコミットの push 時だけでなく、Pull Request の単位で on.pull_request.paths
で指定したファイルに変更が発生したブランチの push 時に毎回 Action が実行されます。
データベース定義書の生成コミットの push で再度この Action が実行されないように、コミットメッセージに [ci skip]
のおまじないを付与しておくとよいです。(→課金対策)
- name: "Generate database document"
run: |
#
# 略
#
git status
git add -N .
echo "db_doc_generated=$(if git diff --quiet; then echo "false"; else echo "true"; fi)" >> $GITHUB_ENV
- name: "Push database document"
if: ${{ env.db_doc_generated == 'true' }}
run: |
#
# 略
#
git add .
git commit -m "[ci skip] generate database document"
git push origin HEAD
さいごに:なぜデータベース定義書を自動生成したいのか
アプリケーションのソースコードの変更にあわせてデータベース定義書を生成することで、データベース定義書が生きたドキュメントになるからです。
データベース定義書がリポジトリに含まれていることで、だれでも・いつでも・かんたんに、その時点でのデータベース定義を確認することができます。もちろんその更新履歴もすべて手軽に確認することができます。
そしてこの記事で言及されているような、業務プロセスとドキュメンテーションの連続性も重要と考えます。
tbls は "ソフトウェア開発に関わるあらゆるドキュメントをテキストのかたちで、ソースコードと一緒に GitHub で管理する" という夢に近づけてくれる素晴らしいツールです 🚀
私たち BABY JOB は、子育てを取り巻く社会のあり方を変え、「すべての人が子育てを楽しいと思える社会」の実現を目指すスタートアップ企業です。圧倒的なぬくもりと当事者意識をもって、こどもと向き合う時間、そして心のゆとりが生まれるサービスを創出します。baby-job.co.jp/
Discussion