tblsで生成したER図

DB設計書の自動出力をGitHub ActionsのReusable Workflowで共通化する

はじめに

こんにちは、金子です。

これまで、DB設計書はツールで自動作成していましたが、ツールを動かすのは人の作業でした。AIでの自動化に伴い、社内全体のフローを徐々に見直していて、今回はGitHub上で自動作成する仕組みを作りました。DDLをpushするだけで、DB定義書とER図がGitHub Actionsで生成されます。

仕組み

シンプルです。

  1. phpMyAdminなどから、構造のみのDDLをエクスポートしてリポジトリー内(e2infoではdocs/db/schema/input/<DB名>.sql)に置く
  2. featureブランチにpushすると、GitHub Actionsが起動する
  3. CI上で使い捨てのMySQLを起動してDDLを流し込み、tblsで定義書とER図を生成する
  4. 生成物を同じブランチに自動コミットする

PRを作っていれば、自動コミットもPRの差分に載ります。レビュアーはDBの変更を、定義書の差分としても確認できます。

ワークフローの本体は共通リポジトリに置き、各プロジェクトには呼び出し用のYAMLだけを置きます。YAMLを各リポジトリにコピーする方式も考えましたが、修正を一箇所で済ませるためにこの構成にしました。

各プロジェクトに置く .github/workflows/db-docs.yml

on:
  push:
    branches:
      - "feature/**"
    paths:
      - "docs/db/schema/input/*.sql"
  workflow_dispatch:

jobs:
  db-docs:
    permissions:
      contents: write
    uses: your-org/shared-workflows/.github/workflows/db-docs.yml@main

共通リポジトリに置く本体 .github/workflows/db-docs.yml

name: Generate DB Docs & ERD (Reusable Workflow)

on:
  workflow_call:
    inputs:
      mysql-image:
        description: "CI上で起動する使い捨てMySQLコンテナのイメージ"
        type: string
        default: "mysql:8.0"
      sql-glob:
        description: "取り込み対象DDLのglobパターン"
        type: string
        default: "docs/db/schema/input/*.sql"
      tbls-config-path:
        description: "tblsの設定ファイルパス(呼び出し側リポジトリ内)"
        type: string
        default: "docs/db/.tbls.yml"
    secrets:
      docs_commit_token:
        description: "自動コミットのpushに使うトークン。未指定時はGITHUB_TOKEN"
        required: false

jobs:
  build-docs:
    runs-on: ubuntu-latest
    permissions:
      contents: write

    # 使い捨てMySQLコンテナ。本番/開発DBへは接続しない。
    services:
      mysql:
        image: ${{ inputs.mysql-image }}
        env:
          MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
        ports:
          - 3306:3306
        # optionsはdocker createに渡るためdockerフラグのみ可。
        # --tmpfs: データディレクトリをRAM上に置き起動を短縮。
        options: >-
          --tmpfs /var/lib/mysql
          --health-cmd="mysqladmin ping"
          --health-interval=1s
          --health-timeout=1s
          --health-retries=15

    steps:
      - uses: actions/checkout@v7
        with:
          token: ${{ secrets.docs_commit_token || github.token }}

      # サードパーティ製アクションはコミットハッシュで固定する。
      - uses: k1low/setup-tbls@5e8e69748c0bb15fdb5e51a0ecdb84f1ecd0e3a1 # v1.4.1

      # DDLごとに一時DBを作り、output/<DB名>/ へ定義書を出力する。
      - name: Import DDLs and Generate Docs
        id: generate
        run: |
          glob='${{ inputs.sql-glob }}'
          outroot="$(dirname "$(dirname "$glob")")/output"
          echo "output-root=$outroot" >> "$GITHUB_OUTPUT"

          for file in ${{ inputs.sql-glob }}; do
            [ -e "$file" ] || continue

            dbname=$(basename "$file" .sql)
            docpath="$outroot/$dbname"

            mysql -h 127.0.0.1 -u root -e "CREATE DATABASE \`$dbname\`;"
            mysql -h 127.0.0.1 -u root "$dbname" < "$file"

            # --config: TBLS_DSN設定時はtbls設定が自動読み込みされないため明示する。
            TBLS_DSN="mysql://root:@127.0.0.1:3306/$dbname" \
            TBLS_DOC_PATH="$docpath" \
            tbls doc --config "${{ inputs.tbls-config-path }}" --rm-dist
          done

      - name: Auto commit generated docs
        uses: stefanzweifel/git-auto-commit-action@4a55954c782fc1ea30b9056cd3e7a2b40ca8887d # v7.2.0
        with:
          commit_message: "docs: auto-generate DB docs and ERD"
          # 生成物だけをコミット対象にする。
          file_pattern: "${{ steps.generate.outputs.output-root }}/*"

DBが2つ以上ある案件でも、input/ にファイルを足すだけで、出力はDBごとのフォルダに分かれます。

ハマったところ

mysqldのオプションが渡せない

CIのMySQLを速くしようとして services の options に --innodb-... を書いたら、unknown flagで失敗しました。ここは docker create に渡るオプションなので、dockerのフラグしか書けません。代わりに --tmpfs /var/lib/mysql でデータをメモリに置いて、起動を速くしています。

日本語にならない

.tbls.yml の dict で見出しを日本語化しているのに、なぜか英語のまま出力されました。TBLS_DSN を環境変数で渡すと設定ファイルが自動で読み込まれないようで、--config を明示したら直りました。

TBLS_DSN="mysql://root:@127.0.0.1:3306/$dbname" \
TBLS_DOC_PATH="$docpath" \
tbls doc --config docs/db/.tbls.yml --rm-dist

最後のDBしか残らない

DBが複数あるとき、出力先を共有していると --rm-dist で前のDBの出力が消えます。DBごとにサブフォルダを分けて解決しました。

AIに任せること、任せないこと

導入作業はAIエージェント(Claude Codeなど)にお願いすることが多いので、READMEにAI向けの指示文を用意しました。

最初は共通リポジトリのURLだけを渡していたのですが、呼び出し側のYAMLが作られず、ワークフローが動かないということがありました。本体は workflow_call なので、単体では起動しません。そこで「呼び出し用のファイルをそのままコピーして作ること」「書き換えや要約をしないこと」を指示文に明記しています。

一方で、入力のDDLだけはAIに作らせないことにしました。本番と検証でDB定義や構造が違う案件がたまにあるため、現時点では人間が判定しています(現時点では)

まとめ

  • tbls+GitHub Actionsで、DB設計書とER図の自動出力を全社共通の仕組みにしました
  • AIには導入作業をお願いしつつ、設計書の正しさを決める入力DDLは人が作ることにしました