Rails + GitHub Actionsではまったこと

投稿者
だいそん
Rails + GitHub Actionsではまったこと

やりたいこと

  • gemのキャッシュ
  • yarnライブラリのキャッシュ
  • RSpecの実行
  • システムスペックの実行
  • システムスペック失敗時のスクショをArtifactとしてアップロード
  • DBはmysql5.7

結論

こんなymlを作りました。

# example.yml

name: RUN Rspec
on:
  pull_request:
    branches:
    - master

jobs:
  build:
    runs-on: ubuntu-latest

    services:
      mysql:
        image: mysql:5.7
        env:
          MYSQL_USER: root
          MYSQL_ALLOW_EMPTY_PASSWORD: yes
    container:
      image: ruby:2.6.4
      env:
        RAILS_ENV: test

    steps:
      - uses: actions/checkout@v1
      - uses: actions/cache@v1
        with:
          path: vendor/bundle
          key: bundle-${{ hashFiles('**/Gemfile.lock') }}
      - uses: actions/cache@v1
        with:
          path: node_modules
          key: yarn-${{ hashFiles('**/yarn.lock') }}
      - name: Set up yarn and node
        run: |
          curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
          echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
          curl -sL https://deb.nodesource.com/setup_12.x | bash -
          apt install -y yarn nodejs
      - name: Install chrome
        run: |
          wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | apt-key add -
          echo 'deb http://dl.google.com/linux/chrome/deb/ stable main' | tee /etc/apt/sources.list.d/google-chrome.list
          apt update -y
          apt install -y google-chrome-stable
      - name: bundle install
        run: |
          gem install bundler
          bundle install --path vendor/bundle --quiet --jobs 4 --retry 3
      - name: yarn install
        run: yarn install
      - name: set database.yml
        run: cp -v config/database.ci.yml config/database.yml
      - name: db create
        run: bundle exec rails db:create db:schema:load --trace
      - name: run rspec
        run: bundle exec rspec

      - name: Archive rspec result screenshots
        if: failure()
        uses: actions/upload-artifact@v1
        with:
          name: rspec result screenshots
          path: tmp/screenshots/

以下はまったことや学んだこと

ruby2.6.4がないと言われる

rubyのセットアップはactions/setup-ruby@v1を使うといくつかの記事で紹介されていましたが、2019/12/30現在、2.6系だと2.6.3しか使えないらしいです。

- name: Set up Ruby 2.6
  uses: actions/setup-ruby@v1
  with:
    ruby-version: 2.6.4

なので普通にcontainerイメージをつかうことにしました。

container:
  image: ruby:2.6.4

gemをキャッシュしたい

gemをキャッシュしたい場合はこう書けば良さそうです。

- uses: actions/checkout@v1
- uses: actions/cache@v1
  with:
    path: vendor/bundle
    key: bundle-${{ hashFiles('**/Gemfile.lock') }}

yarnライブラリをキャッシュしたい

そもそもyarnを入れる必要があります。

- name: Set up yarn and node
  run: |
    curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
    echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
    curl -sL https://deb.nodesource.com/setup_12.x | bash -
    apt install -y yarn nodejs

bundleと同じようにyarnもキャッシュさせます。

- uses: actions/cache@v1
  with:
    path: node_modules
    key: yarn-${{ hashFiles('**/yarn.lock') }}

mysql5.7を使いたい

services:
  mysql:
    image: mysql:5.7
    env:
      MYSQL_USER: root
      MYSQL_ALLOW_EMPTY_PASSWORD: yes

database.ci.ymlを作ってそれをCI上でdatabase.ymlにリネームして使ってます。

- name: set database.yml
  run: cp -v config/database.ci.yml config/database.yml
# database.ci.yml

default: &default
  adapter: mysql2
  encoding: utf8mb4
  charset: utf8mb4
  collation: utf8mb4_general_ci
  pool: 5
  host: mysql
  port: 3306
  username: root
  password:

test:
  <<: *default
  database: circle_test

host名をmysqlにしないとうまくmysqlに接続できませんでした。

usernameはMYSQL_USER部分と合わせる必要があるでしょう。 passwordは不要なのでMYSQL_ALLOW_EMPTY_PASSWORD: yesとしてます。

test環境としてrailsコマンドを打ちたい

container:
  image: ruby:2.6.4
  env:
    RAILS_ENV: test

当然ですが、bundle exec rails db:createコマンドなんかもtest環境で行いたいので環境変数としてRAILS_ENV: testを設定しました。

システムスペックを動かしたい

プロジェクトではheadless_chromeを使ってるのですが、特に何も考えずCIを動かすとこのエラーが出ました。

Webdrivers::BrowserNotFound:
Failed to find Chrome binary.

これはChromeをインストールすれば解消されました。

- name: Install chrome
  run: |
    wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | apt-key add -
    echo 'deb http://dl.google.com/linux/chrome/deb/ stable main' | tee /etc/apt/sources.list.d/google-chrome.list
    apt update -y
    apt install -y google-chrome-stable

が、次のエラーが出ました。

Selenium::WebDriver::Error::UnknownError:
unknown error: Chrome failed to start: exited abnormally
(unknown error: DevToolsActivePort file doesn't exist)
(The process started from chrome location /usr/bin/google-chrome is no longer running, so ChromeDriver is assuming that Chrome has crashed.)

このオプションをdriven_byに追加してあげればうまく動きました。

# spec_helper.rb

driven_by :selenium, using: :headless_chrome do |driver_options|
  driver_options.add_argument('--disable-dev-sim-usage')
  driver_options.add_argument('--no-sandbox')
end

システムスペックの結果をArtifactとしてアップロードしたい

- name: Archive rspec result screenshots
  if: failure()
  uses: actions/upload-artifact@v1
  with:
    name: rspec result screenshots
    path: tmp/screenshots/

システムスペックが成功すると tmp/screenshots/ が作られないので no such file or directoryのエラーがでます。なので if: failure() を書いて『直前のジョブが失敗したら=RSpecが失敗したら』という条件を課しています。ただ、システムスペックは通ったけどモデルスペックは通らなかった、という場合でも動いてしまうはずなので何か他の方法をとる必要があると思われます。

CircleCIに比べてちょっと遅い気がしますが今後改善されていくことを期待します。 GitHub上で全て完結するのはとても良いですね。

今回作ったものはこちらです https://github.com/DaichiSaito/github-action-example

一緒にスタートアップを盛り上げませんか?
こわくないよ!SQL 〜本番DBのデータが見たい!の巻〜
2020/02/07
enumのネガティブバージョンを定義してみた
2020/02/27