[ Golang ] Facebook / ent のER図をGitHub Actionsで自動更新する

# ER図とは
>ER図のEはエンティティ（Entity）の略で、Rはリレーションシップ（Relationship）の略です。つまりER図は「エンティティ＝モノ」と「リレーションシップ＝関係」の組み合わせでシステムのデータやデータ間の処理構造を設計します。例として「顧客が商品を注文する」という処理をER図で表すと以下のようになります。

https://products.sint.co.jp/ober/blog/create-er-diagram#:~:text=ER%E5%9B%B3%E3%81%AEE%E3%81%AF,%E6%A7%8B%E9%80%A0%E3%82%92%E8%A8%AD%E8%A8%88%E3%81%97%E3%81%BE%E3%81%99%E3%80%82

簡潔に説明をすると、ER図とはテーブル間の関係を表した図です。
RDBのようなデータベースを用いてシステムの開発および運用を行う際に、テーブル間の関係を直感的に理解できるようになります。


# なぜER図が必要か
実運用を行なっているシステムとなるとテーブル数が数十に及ぶことが多々ありますので、ER図のようなものなしでは複数のテーブル間の関係を把握することが困難となります。

# なぜ自動更新が必要か
ER図の様なドキュメントは、日々の忙しい開発業務の中では大抵の場合優先順位として後回しになることが多く、ER図の更新忘れなどが発生してしまいます。
自動化しておくと更新の手間を省くことができ、また更新忘れなども防ぐことができる様になります。

# 自動化フロー
1. 開発ブランチをmasterにマージ
2. src/backend-go/migrations/** にmasterとの差分があった場合、ER図を自動生成
3. 新規ブランチを作成し生成されたER図をpush
4. 自動でER図マージ用のPRを立てる
5. PRをauto merge or manual merge

## なぜ上記のようなフローにしたか
まず最初に、開発ブランチに対して実行される自動テストのworkflowの処理の一部として、
`ER図を自動生成 & ER図commit`を実行する方式の採用を検討しました。
しかし、上記の方式を採用すると、開発ブランチの最新commtiがER図自動commitのログになってしまって、
PRマージ時の 「All checks have passed」チェックがUIに表示されなくなってしまいます。
（Pull Requestのマージ前のチェックはきちんと行いたいですね。）

# GitHub Actionsのworkflowを作成する
はじめにworkflowの完成版を掲載しておきます。

## 完成版
```yaml
name: Update ER Diagram

on:
  push:
    branches:
      - master
    paths:
      - "src/backend-go/migrations/**"

defaults:
  run:
    shell: bash
    working-directory: src/backend-go

env:
  BRANCH_NAME: auto-update-er

jobs:
  update-er:
    name: Update ER Diagram
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Push Branch In Advance Before Creating Pull Request
        run: |
          git checkout -b ${{ env.BRANCH_NAME }}
          git push -f origin ${{ env.BRANCH_NAME }}
      - uses: actions/checkout@v3

      - name: Create new ER Diagram
        run: |
          go get github.com/hedwigz/entviz
          go run github.com/hedwigz/entviz/cmd/entviz ./ent/schema
          rm -rf ../../docs/schema-viz.html
          mv schema-viz.html ../../docs/schema-viz.html
          git checkout go.mod
          git checkout go.sum

      - name: Create Pull Request
        uses: peter-evans/create-pull-request@v4
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          commit-message: "chore(docs): Update ER Diagram"
          committer: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
          author: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
          branch: ${{ env.BRANCH_NAME }}
          title: "chore(docs): Update ER Diagram"
          body: |
            Update ER Diagram
            - Auto-generated by GitHub Actions Workflow
          delete-branch: true
          draft: true

      - name: Deploy ER Diagram
        uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./docs
```

## 各stepの解説
ここから各stepの詳細について解説をしていきたいと思います。

### ER図をpushするためのbranchを作成する
```yaml
      - name: Push Branch In Advance Before Creating Pull Request
        run: |
          git checkout -b ${{ env.BRANCH_NAME }}
          git push -f origin ${{ env.BRANCH_NAME }}
```
後ほど説明をするPull Requestの自動生成フローですが、Pull Requestに相対するbranchをリモートリポジトリにあらかじめ用意しておかないと、Pull Requestの自動生成処理が失敗してしまいます。
故に、CIのworkflowにてbranchを作成しリモートリポジトリにpushを行います。

## ent専用のER図を自動生成するためのツールを実行する

```yaml
      - name: Create new ER Diagram
        run: |
          go get github.com/hedwigz/entviz
          go run github.com/hedwigz/entviz/cmd/entviz ./ent/schema
          rm -rf ../../docs/schema-viz.html
          mv schema-viz.html ../../docs/er.html
          git checkout go.mod
          git checkout go.sum
```
`entviz`という、entで定義したDBのschemaをもとにER図を自動生成するためのツールが公開されているので、`go get`でpakeageをinstallした後、`go run github.com/hedwigz/entviz/cmd/entviz ./ent/schema`を実行してER図を出力します。

### go.modとgo.sumをなぜcheckoutしているのか
```yaml
git checkout go.mod
git checkout go.sum
```
`entviz`の様なER図を生成するためのpackageを本番用buildの成果物に含めない様にするためです。
前提として、ER図の生成は本番環境で使われるものではなく、ローカル環境 or GitHub Actionsを実行するCI環境上でのみ使われるものです。
1つのpackageを本番buildの成果物に追加で含めたとしても、そこまで大きな差にはなりませんが、
本番用のbuild imageのサイズは極力最小となるように心がけたいです。

https://entgo.io/ja/blog/2021/08/26/visualizing-your-data-graph-using-entviz/


### Pull Requestを自動生成する
```yaml
      - name: Create Pull Request
        uses: peter-evans/create-pull-request@v4
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          commit-message: "chore(docs): Update ER Diagram"
          committer: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
          author: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
          branch: ${{ env.BRANCH_NAME }}
          title: "chore(docs): Update ER Diagram"
          body: |
            Update ER Diagram
            - Auto-generated by GitHub Actions Workflow
          delete-branch: true
          draft: true
```

対象のrepositoryに対して、自動でPRを立ててくれるpagekageが公開されているので、今回はそちらを使用したいと思います。

#### `GITHUB_TOKEN`について
```yaml
token: ${{ secrets.GITHUB_TOKEN }}
```

workflowを実行するrepositoryに対してPRを立てるためには`GITHUB_TOKEN`を付与する必要があります。
この`GITHUB_TOKEN`については事前に発行する必要はないみたいですが、yamlファイル内にきちんと定義しておきましょう。

https://github.com/marketplace/actions/create-pull-request

### ER図をGitHub Pagesにdeployする
```yaml
      - name: Deploy ER Diagram
        uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./docs
```

GitHub Pagesを事前に有効してあることを前提として話を進めます。
GitHub Pagesにdeployをするためのpackageが公開されているので、packageを使用してdeploy処理が実行されるようにします。

https://github.com/peaceiris/actions-gh-pages

# 最後に
上記の設定を行うと、GitHub ActionsでER図を自動生成した後、GitHub Pagesにdeployするための設定がきちんとできていると思います。
忘れがちなER図の更新に関して、自動化を行うことで運用の手間を減らすことができると思いますので、積極的に導入を行なっていきたいですね。