📄

tbls + GitHub Actions で DB ドキュメント自動生成

2022/12/22に公開

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  テックブログ

Discussion