【GMOリサーチではエンジニアを募集中です】採用情報はこちら!

テーブル変更したら回帰テスト全部実行するようにした話

テーブル変更したら回帰テスト全部実行するようにした話

えらい人:今うちらさ、Git上でデータベースのテーブル構成を管理してるでしょ。

私:あーはいはい。

え:それに変更が入った時にさ、アプリの単体テスト実行したいんだよね。DB使ってるの全部。

私:はい?

え:いやほら、今までの仕組みだとJenkinsでそういうことをやっていたのよ。テーブル構成変更で悪影響でてないか確認したくてね。で、それと同じことをECS使った新しい仕組みのアプリでもやりたいんだよね。Github 使ってなんとかならないかな?

私:んーー?とりあえずやり方調べないとわからないですね。各アプリ側のCIは、Github Actions でやってるからそれを動かせばよいのかな?

え:とにかくやってみてよ。じゃ、よろしくーー。

私:りょ、了解しました。。。

現在の状況

データベースのテーブル構成のSQLファイルは、table_def というGitHubのリポジトリで管理されている。これは、開発PC上に開発環境を作るときや、Jenkins環境でのDB初期化の時にこのリポジトリ内のSQLを使ってデータベースを作っている。

テーブル構造を更新したいときはtable_def上で、masterからブランチ作ってやりたい更新をコミットしてプルリクエストを作る。この時に目視によるレビューをして、問題ないならmasterにマージされる。(ブランチ名はご容赦を…)

アプリ開発の要件でテーブルが増えたり定義が変わったりする。 このことをきっかけとして、発生するであろう既存アプリへの影響を検知したい。そこで、単体テストを動かして結果を知りたいというわけだ。

ECS使った新しい仕組みのアプリでは、CIを Github Actions でやってる。PRにコミット入った時にアプリ側のリポジトリの Github Actions を叩けばよいな。

あるいは、table_def の Github Actions で全部のアプリのテストを実行してもいいかな。 けどアプリ数これから増えそうだし、全部が1個に集中すると管理が大変かもな。やめとこう。

やってみよう

別リポジトリの Github Actions ってどうやって実行すれば良いんだ?そういえばリトアニアにすごいエンジニアがいるから相談してみよう。

リトアニア在住の同僚氏: Found a solution for you

https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows#repository_dispatch

おーなるほど。repository_dispatch というイベントを用意して、Github Actions 内で curlでAPIを叩けばよいのだな。やってみよう!リトアニアの同僚氏ありがとーう。

<<ドタドタ・バタリ>>

ちょっと調べて構成考えてみた。まず処理全体はこんな感じになる。

table_defでのテーブル修正PRでのコミット発生きっかけで、その時点でのSQLファイルを使ってMySQLデータベースのイメージを build して ECR に pushする。この時点での hash値でタグを付けておく。

その後、各アプリにhash値と返信に必要な情報を client_payload で送って、 repository_dispatch を実行する。 各アプリでは、hash値が付いたイメージでデータベースを起動して、単体テストを実行する。結果レポートをS3にアップロードしつつ、成否だけ table_def 上にあるPRにコメントとして残せば良いな。失敗だったら、テスト結果レポートのリンクも入れると。

コード例

テーブル定義リポジトリ

table_defでのgithub Actionsはこんな感じだ。(途中のECRログインの処理は省略)

各アプリへ通知をする処理は繰り返しになるから matrix を使ってみた。イメージのビルドは繰り返されたくないから別のjobに分ける必要がある。ちょっと面倒だぜ。例えば単純に分けただけだとjobが2個とも同時に動き出してしまう。イメージのビルドのjobが終わった後に通知のjobを実行したいので、yaml に以下の記述を入れる。

さらに、ハッシュ値や通知対象アプリのリストをjob間で受け渡すために、以下の記述も入れる。

通知対象のアプリのリストは環境変数から設定するようにした。matrix では配列オブジェクトが必要らしいから、アプリ名をカンマ区切り文字列にして環境変数に設置し、 jq と、fromJSON を使って配列に変換できた。

これもっと端的にできないだろうか? しかしとりあえず設定を環境変数に置くことができたからこれで良しとするか。

各アプリのリポジトリ

アプリのリポジトリでのGithub Actionsはこんな感じだ。Kotlinのアプリケーションだとこうなる。 動作のパラメータのようなものは、client_payload で受け取る。(途中のECRログインやテストの前準備の処理は省略)

if: success() と if: failure()を使えば成功時失敗時のそれぞれの処理を設定できる。

それと、table_def のPRへのコメントは最新の結果だけ表示されるように設定する。 実利用上は複数リポジトリからコメントを受けるので最新のコメントだけが残る形になってしまう。 (どこのリポジトリからのコメントなのかわからないので。) それだと使えないのでメッセージ送信元リポジトリの名前で識別できるようにする。

yamlとしてはこう書く。

ここを参考にした。

https://github.com/marocchino/sticky-pull-request-comment#keep-more-than-one-comment

まとめ

うん。これでできた。これで ECS使った新しい仕組みのアプリでは repository_dispatch を受け取ったら指定されたデータベースのイメージで単体テストやって結果を table_def リポジトリに返せば良いな。テーブル構成変更PRを書いた人がアプリの単体テスト失敗に気がつけるようになるからこれは良いことだ。

各アプリのGithub Actions は既存の単体テストのworkflowをいくつか変更して別に作った形になる。うまく1本のymlファイルに纏めれたらよいけどそれは今後の課題としよう。きれいにメンテしやすく纏められるに越したことはないが、あまりに複雑だったら分けたほうが良いかもしれない。いずれにせよ、CIのコードってどれも似たりよったりでパターンになっていくだろうから、あまり気にしなくても良いかもね。

開発ブログカテゴリの最新記事