こんにちは。LOGICAプロダクトグループの松本です。
GitHub Actionsを使ってlintツール"Rubocop"と単体テスト"RSpec"を実行する方法を紹介します。
概要
- GitHub Actionsを使い、プッシュするたびにRubocopとRSpecを実行するようにした
- 実行結果はプルリクで確認できる
- DB: MySQL
- マイグレーション管理: Ridgepole
- 設定方法はこちら
背景
"プログラムの修正が終わり、コミットしてプッシュしたけどlint&単体テスト実行するのを忘れてた...。"
"レビュワーにアサインされたけどプルリクを確認する以前にlint&単体テスト実行したか確認しないと...。"
などの悩みはありませんか?きっとありますよね。
単体テストはデグレとバグのチェック、
lintは古来より可読性を高めると言われています。
可読性はエンジニアのバイブル、リーダブルコードなどでも取り上げられていますね。
プロダクト開発が進んでくると後々"ここの処理書き直したいなあ...。けど古いソースだから書き直して不具合でると嫌だしやめておこう"となるのはまあ稀によくあるので早めに入れたほうが良さそうです。
プルリクのレビュワーの負荷軽減や、どのコミットまでは成功していたかの記録という観点でも、
実行結果はプルリクの作成時点で確認できるようにしておきたいです。
GitHub Actionsとは
GitHub Actionsを使うことにしましたが、そもそもGitHub Actionsとは何なのでしょうか。
公式ドキュメントの"GitHub Actions を理解する"には以下のように定義されています。
GitHub Actions は、ビルド、テスト、デプロイのパイプラインを自動化できる継続的インテグレーションと継続的デリバリー (CI/CD) のプラットフォームです。 リポジトリに対するすべての pull request をビルドしてテストしたり、 マージされた pull request を運用環境にデプロイしたりするワークフローを作成できます。
引用: https://docs.github.com/ja/actions/learn-github-actions/understanding-github-actions#overview
つまりローカルで流すのが面倒なテストや構文チェックやデプロイのコマンドをGitHub側で実行して作業を楽にしてくれるということです。 ありがたいですね。
解説
設定について記載していきます。
.github/workflows/github-action.yml
name: Run Rubocop and RSpec Actions on: pull_request jobs: Job-Rubocop: runs-on: ubuntu-latest timeout-minutes: 10 steps: - name: Checkout code uses: actions/checkout@v2 - name: Setup Ruby Env uses: ruby/setup-ruby@v1 with: ruby-version: '3.1.2' bundler-cache: true - name: Show ruby version run: ruby -v - name: Run lint run: bundle exec rubocop Job-RSpec: runs-on: ubuntu-latest timeout-minutes: 10 services: mysql: image: mysql:8.0 ports: - 3306:3306 env: MYSQL_ALLOW_EMPTY_PASSWORD: yes options: --health-cmd "mysqladmin ping" --health-interval 10s --health-timeout 5s --health-retries 10 steps: - name: Checkout code uses: actions/checkout@v2 - name: Setup Ruby Env uses: ruby/setup-ruby@v1 with: ruby-version: '3.1.2' bundler-cache: true - name: Database create run: bundle exec rails db:create RAILS_ENV=test - name: Database migrate run: bundle exec ridgepole --config config/database.yml --file db/Schemafile --apply --env test # マイグレーションファイルでの管理方法の場合は以下 # run: bundle exec rails db:migrate RAILS_ENV=test - name: Run tests run: bundle exec rspec
身も蓋もない話ではありますがMySQL + Ridgepole環境の場合は基本的に上のコードをコピペすれば同じことはできると思います。
ただここでブログを終えてしまうとブログ運営者さんのレビューに通る気がしないので少し説明をします。
name
ワークフローの名称を定義します。
steps:
以下のものはStepの実行結果の表示の際に使われます。
on
GitHub Actionsを実行するトリガーを定義します。
[push, pull_request]
とするとプッシュとプルリクエスト作成時にチェックできるようになります。
jobs
GitHub Actionsの定義イメージとしてjobs:
の下に実行したいコマンドとその実行環境を記載していくようになっています。
jobsごとにプルリクエスト下部に実行結果が表示されます。
runs-on
GitHub Actionsはrunnerと呼ばれるVM内で実行されますので、VM環境の指定を行います。
参考: https://github.com/actions/runner-images#available-images
services
VM内で使用するDockerコンテナの設定を記載します。
今回はMySQLのコンテナを使用するのでDocker Hubに公開されているMySQLコンテナのタグを設定しています。
設定はdatabase.ymlと合わせるように気をつけてください。
uses: actions/checkout@v2
ジョブで使用するリポジトリをチェックアウトします。
未定義の状態でなにかコマンドを実行すると、File Not Exist
系のエラーになることがあります。
発生した場合は疑ってみてください。
uses: ruby/setup-ruby@v1
rubyの実行環境を定義します。with:
でバージョンを指定できます。
このステップに到達したときVM内でbundle install
が実行されますが、開発環境がmacOSの場合はVMにubuntu-latest
を指定しているので乖離が発生します。
注意したいのがbundlerのバージョンが2.2以降で開発環境のOSとruns-onで指定したOSが異なる場合、
runnerのbundle install実行時にエラーが出ますので以下を実行してGemfile.lock側にbundle installを行う実行環境を追加する必要があります。
bundle lock --add-platform x86_64-linux
Gemfile.lock
PLATFORMS x86_64-darwin-20 x86_64-linux
このように、ワークフローはVM内の実行エラーを解決しながら定義していきます。
メッセージはちゃんと実行結果に表示されるので一つずつ確認可能です。
(正直面倒でエラーが出るたびに真顔になりますが) 今後プッシュするたびに実行されるワークフローになるので温かい気持ちで対応しましょう。
結果
設定を追加することで、プルリクエストを作成するとRubocopとRSpecが実行されるようになりました。
プルリクエスト作成後は新規のコミットをプッシュすれば設定したワークフローが実行されます。
これで冒頭に記載したテストの実行忘れ防止や、レビュー時に状態確認を行う手間を削減できました。
まとめ
今回説明した内容はCI/CDの最初のステップになります。
ゆくゆくはマージしたコミットをステージング環境にすぐにデプロイするなど、
サーバの役割が増えることで膨らんでいくデプロイタスクの工数削減につなげていきたいと思います。