PLAY DEVELOPERS BLOG

HuluやTVerなどの日本最大級の動画配信を支える株式会社PLAYが運営するテックブログです。

HuluやTVerなどの日本最大級の動画配信を支える株式会社PLAYが運営するテックブログです。

GitHub Actionsを使ってプルリクエスト作成時に自動でRubocop + RSpecを実行する

こんにちは。LOGICAプロダクトグループの松本です。
GitHub Actionsを使ってlintツール"Rubocop"と単体テスト"RSpec"を実行する方法を紹介します。

概要

  • GitHub Actionsを使い、プッシュするたびにRubocopとRSpecを実行するようにした
  • 実行結果はプルリクで確認できる
  • DB: MySQL
  • マイグレーション管理: Ridgepole
  • 設定方法はこちら

RubocopはNG、RSpecはOK

背景

"プログラムの修正が終わり、コミットしてプッシュしたけど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内の実行エラーを解決しながら定義していきます。
メッセージはちゃんと実行結果に表示されるので一つずつ確認可能です。
(正直面倒でエラーが出るたびに真顔になりますが) 今後プッシュするたびに実行されるワークフローになるので温かい気持ちで対応しましょう。

VM内でのエラーは確認可能

結果

設定を追加することで、プルリクエストを作成するとRubocopとRSpecが実行されるようになりました。
プルリクエスト作成後は新規のコミットをプッシュすれば設定したワークフローが実行されます。
これで冒頭に記載したテストの実行忘れ防止や、レビュー時に状態確認を行う手間を削減できました。

✗でワークフローが失敗していることがわかる

詳細はActionsタブで確認

まとめ

今回説明した内容はCI/CDの最初のステップになります。
ゆくゆくはマージしたコミットをステージング環境にすぐにデプロイするなど、
サーバの役割が増えることで膨らんでいくデプロイタスクの工数削減につなげていきたいと思います。