Ruby on RailsのRSpecテストをGitHubActionsで実行しようとしたら、そこそこ大変だったのでメモに残しておきます。
GitHubActionsとは
GitHub上で動作するサーバレスな実行環境です。
リポジトリ内のファイルに設定を記述することで、GitHubの各種操作にトリガして任意のアクションを実行できる仕組みです。
パブリックリポジトリであれば無料で使えます。
今回はPull Requestの作成に紐づけてRSpecを実行することで、Rails用のCIにしようと思います。
結論
Railsを実行できるDockerイメージをDockerHubにアップロードして、DockerPullしてテストを実行するのが良さそうです。
環境
- Ubuntu 16.04 LTS
- Ruby on Rails 6.0
- Ruby 2.6.6
OS以外は違っても簡単に対応できます。
Dockerイメージを作ってDockerHubにアップロードする
Dockerfile
ベーシックな環境です。
必要なライブラリがあれば追記してください。
FROM ubuntu:16.04
SHELL ["/bin/bash", "-c"]
ENV RUBY_VERSION="2.6.6"
ENV BUNDLER_VERSION="2.1.4"
ENV DEBIAN_FRONTEND="noninteractive"
ENV PATH=/root/.rbenv/bin:/root/.rbenv/shims:$PATH
WORKDIR /app
COPY Gemfile .
COPY Gemfile.lock .
RUN set -x \
&& apt update \
&& apt install -y \
build-essential \
curl \
git \
libssl-dev \
libreadline-dev \
libmysqlclient-dev \
mysql-client \
mysql-server \
tzdata \
zlib1g-dev \
# Install rbenv and ruby
&& git clone https://github.com/sstephenson/rbenv.git ~/.rbenv \
&& git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build \
&& CONFIGURE_OPTS='--disable-install-rdoc' /root/.rbenv/bin/rbenv install ${RUBY_VERSION} -s \
&& /root/.rbenv/bin/rbenv global ${RUBY_VERSION} \
# Install bundler
&& echo 'gem: --no-rdoc --no-ri' > /root/.gemrc \
&& /root/.rbenv/shims/gem install bundler -v ${BUNDLER_VERSION} \
# bundle install
&& /root/.rbenv/shims/bundle config set without development \
&& /root/.rbenv/shims/bundle install \
# delete unused file
&& rm -rf /var/lib/apt/lists/* \
&& rm Gemfile Gemfile.lock
RUNを複数書いてDockerのレイヤを重ねるとMySQL周りで実行時にエラーが出るので1つのコマンドで全環境を構築します。
Dockerのビルド
docker build -t utyosu/build-rails:latest . -f tools/ci/Dockerfile
Dockerイメージのアップロード
DockerHubのアカウントが必要になります。
はじめてのDockerHubリポジトリ登録あたりが参考になりそうです。
docker push utyosu/build-rails:latest
GitHubActionsのトリガを設定する
プロジェクトのリポジトリ内にGitHubAction用のファイルを作成します。
name: build
# Pull Requestをトリガにする
on: [pull_request]
jobs:
build:
# Ubuntuの最新版をベースにする
runs-on: ubuntu-latest
# DockerHubからイメージをPullする
container:
image: utyosu/build-rails:latest
# このブランチをcheckoutする
steps:
- uses: actions/checkout@v1
# test.shを実行する
- name: run test
run: . tools/ci/test.sh
テストスクリプト
テストしたいことを記述します。
このスクリプトが失敗するとビルド失敗になります。
#!/bin/bash
# プロセスが何も起動してないので、まずはMySQLを立ち上げておく
service mysql start
# MySQLユーザの作成と権限の付与
mysql -e 'create user "user_name";'
mysql -e 'grant all on *.* to "user_name";'
export RAILS_ENV=test
bundle config set without development
# Gemをインストールする。
# 何もない状態から
bundle install
# Capistranoが動いているか確認する
# (バージョンの不一致で動かないときがあるので念の為チェックしている)
bundle exec cap -T
# Rubocopによる静的解析
bundle exec rubocop
# railsで定義されているデータベースを作成する
bundle exec rails db:create
# ridgepoleによるデータベースのスキーマ作成
# ridgepoleを使っていない人は代わりに bundle exec rails db:schema:load を実行する
bundle exec ridgepole -c config/database.yml --apply -f db/schema -E test
# RSpecの実行
bundle exec rspec
実際にやってみる
PullRequestを作成すると Some checks haven't completed yet
と表示されます。
DetailsをクリックするとCIの進捗状況を確認できます。
少し待っているとコンソール出力が表示されます。
しばらくすると完了します。
PullRequestに戻ると All checks have passed
と表示されて、問題なくテストが通ったことが分かります。
経緯
GitHub標準のRuby実行環境が用意されているので、最初はそれをベースにして試していました。
しかし、RailsやGemのインストールで30分以上かかってしまうので、軽めのプロジェクトにおけるCIには向いてないと思いました。
DockerHubからイメージをPullして実行する方法であれば、40秒くらいでテストの実行が開始できることが分かったのでこの方法を用いています。
メモ
別コンテナにMySQLとか用意してコンテナ同士でやり取りする方法もあるようですが仕組みが難しすぎて実現できませんでした。
Rails環境で上手く実現できたらいいなーって思ってます。