データベース開発にBranchを導入する

# はじめに

TiDB ServerlessにはBranch機能というものがあります。これはリポジトリのBranch同様に、データのスキーマとデータそのものをコピーした（正確にはcopy on write)開発用Branchを作成する機能です。作るのも、消すのも簡単にできるため、スキーマを変更した場合などのテストに利用することを想定しています。

またGitHubと連携することで、GitHubのPRとともにBranchを作成するといった自動化も可能になります。
この記事ではBranchの作成方法とGitHubに連携して活用する方法について見ていきます。

※ 画面やCLIからもBranchの作成、削除は可能です。

## GitHubとの連携

[公式ドキュメント](https://docs.pingcap.com/tidbcloud/branch-github-integration)の説明に則って解説していきます。
ここではチュートリアル用にGo、Python(django)、Rubyのリポジトリがありますが、ここではRubyリポジトリを使って説明します。

### リポジトリのフォーク
まず[Rubyのチュートリアル](https://github.com/bohnen/branching-rails-example)をフォークします。TiDB ServerlessのブランチはPull Requestで作られるので、自分で管理しているリポジトリを利用します。

### リポジトリとの紐付け

作成したリポジトリと、TiDB Cloudの紐付けを行っていきます。
1. TiDB CloudのメニューからBranchesを選び、右上にある `Connect to Github`を押します。

2. 初めての場合は、`TiDB Cloud Branching` の認可の画面が出ますので、Authorizeします。
![スクリーンショット 2023-12-25 14.40.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12495/b1d2bc03-1cce-849b-c350-76bc3977a02e.png)

3. その後出てくるGithubのアカウント選択画面では、初期では何も選択できません。`Install Other Account` を選択してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12495/cfa9fbcf-1c1e-7a9c-daa4-3d7ad00befb2.png)

4. すると、`TiDB Cloud Branching`をインストールする確認画面になります。`Only select repositories`として、今回利用するリポジトリを選択してインストールします。
![スクリーンショット 2023-12-25 14.43.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12495/01f4fa8b-01ab-bc56-1698-e4cd4a920f22.png)

5. ここまで実行すると元のTiDB Cloudコンソールに戻ってしまいますが、再度 `Connect to Github` を押し、Githubアカウント選択画面に移ります。今度は自分のGitHubアカウントと、先ほど`TiDB Cloud Branching`をインストールしたリポジトリが選択できるので、それを選択します。

紐付けに成功すると、右上のボタンが `Disconnect` になります。

### リポジトリをcloneして接続の確認

さて、紐付けが済んだので、開発を想定したチュートリアルに進みます。

まず、リポジトリをローカルにcloneします。（筆者はMacOSを利用しています)
```bash
git clone https://github.com/<your github account>/branching-rails-example
```

必要なGemをインストールします。
```bash
bundle install
Bundler 2.4.12 is running, but your lockfile was generated with 2.4.10. Installing Bundler 2.4.10 and restarting using that version.
Fetching gem metadata from https://rubygems.org/.
Fetching bundler 2.4.10
Installing bundler 2.4.10
Fetching gem metadata from https://rubygems.org/.........
...
```

TiDB Cloudコンソールで接続情報を取得し、環境変数にセットします。
```bash
export TIDB_DATABASE=test
export TIDB_USER=<TiDB User>
export TIDB_HOST=gateway01.ap-northeast-1.prod.aws.tidbcloud.com
export TIDB_PASSWORD=<TiDB Password>
export TIDB_CERT_PATH=/etc/ssl/cert.pem
```

`rake db:migrate`と`rake db:seed`を実行します。エラーなく実行できることを確認します。
```bash
rake db:migrate
== 20230906033557 CreateArticles: migrating ===================================
-- create_table(:articles)
   -> 0.1121s
== 20230906033557 CreateArticles: migrated (0.1123s) ==========================
```

必要に応じて `rails server` でローカルWebサーバを立てて動きを確認してみてください。

:::note warn
`rake db:migrate`をMacOSで実行時に下記のエラーが出た場合は、
```text
LoadError: dlopen(/Users/bohnen/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/mysql2-0.5.5/lib/mysql2/mysql2.bundle, 0x0009): Library not loaded: /opt/homebrew/opt/mysql/lib/libmysqlclient.21.dylib
```
下記のコマンドでmysql2をビルドしてください。[参照](https://stackoverflow.com/questions/67840691/ld-library-not-found-for-lzstd-while-bundle-install-for-mysql2-gem-ruby-on-mac)
```bash
gem remove mysql2
gem install mysql2  -- --with-opt-dir=$(brew --prefix openssl) --with-ldflags=-L/opt/homebrew/opt/zstd/lib
```
:::

### プルリクエストの作成

動作が確認できたところで、変更を行いPull Requestを作成しましょう。
まずブランチを作成します。
```bash
git checkout -b branchtest
```

変更として、カラムを追加するmigrationを記述します。
```bash
rails generate migration AddAuthorToArticles
      invoke  active_record
      create    db/migrate/20231225060444_add_author_to_articles.rb
```

migrationファイルの中身です
```ruby
class AddAuthorToArticles < ActiveRecord::Migration[7.0]
  def change
    add_column :articles, :author, :string
  end
end
```

リモートにpushします
```bash
git add .
git commit -m "<comment>"
git push origin branchtest
```

これでブランチにpushできたので、GitHubでPull Requestを作成します。

:::note warn
Pull Request作成の際に、送り先が自分のリポジトリのmainになっていることを確認してください。
:::

Pull Requestを作成すると、Actionsが動作してBranchが作られるのが分かります。(作成したBranchは、TiDB CloudのBranches画面でも確認できます）

![スクリーンショット 2023-12-25 15.38.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12495/5e7256fe-4001-3f79-debb-e496286501a8.png)

### Branchデータベースを利用する

BranchはBranches画面から操作することができます。右側にある・・・から接続情報の取得ができます。
通常の接続時同様、パスワードの設定が必要です。
![スクリーンショット 2023-12-25 15.38.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12495/8cf0dca2-9c00-649c-80d4-e2cc90d83ca8.png)

先ほど`rake db:migrate` をしたコンソールに戻って、接続情報を更新して `rake db:migrate`してみます。
```bash
export TIDB_USER=<ブランチのユーザー>
epport TIDB_PASSWORD=<ブランチのパスワード>
# その他情報は変更なし

rails db:migrate
== 20231225060444 AddAuthorToArticles: migrating ==============================
-- add_column(:articles, :author, :string)
   -> 0.4191s
== 20231225060444 AddAuthorToArticles: migrated (0.4193s) =====================
```

正しく実行できました。テーブル定義が変わっていることを、MySQL CLIなどで確認します。
```bash
mysql> desc articles;
+------------+--------------+------+------+---------+----------------+
| Field      | Type         | Null | Key  | Default | Extra          |
+------------+--------------+------+------+---------+----------------+
| id         | bigint(20)   | NO   | PRI  | NULL    | auto_increment |
| title      | varchar(255) | YES  |      | NULL    |                |
| body       | text         | YES  |      | NULL    |                |
| created_at | datetime(6)  | NO   |      | NULL    |                |
| updated_at | datetime(6)  | NO   |      | NULL    |                |
| author     | varchar(255) | YES  |      | NULL    |                |
+------------+--------------+------+------+---------+----------------+
6 rows in set (0.01 sec)
```

この変更はBranchのみに反映され、元のデータベースには反映されません。

### Branchの削除

最後に、Branchの削除です。先ほどのPull RequestをMergeかCloseすると、Branchも合わせて削除されます。

## まとめ

Branch機能を使うと開発用にデータベースを複数作成することができ、特にリポジトリに同期して作成する機能はテスト等の自動化で役立ちそうです。
公式サイトにはActionsのカスタマイズ方法なども記載があるのでそちらを参照して活用してみてください。