Fun Done Run

yazawa's tech blog

CircleCI でリモートリポジトリにプッシュした時にRSpec を実行する

f:id:yazawa_tech:20190720171857p:plain

今回はCircleCI でリモートリポジトリにプッシュしたら自動でテスト(RSpec)を実行するための設定をしてみた。その時の知見やyaml ファイルの書き方をまとめておく。

設定ファイル

.circleci/config.yml は以下のように記述した。

version: 2.1

jobs:
  build:
    docker:
      - image: circleci/ruby:2.5-stretch-node-browsers-legacy
        environment:
          BUNDLE_JOBS: 3
          BUNDLE_RETRY: 3
          BUNDLE_PATH: vendor/bundle
          BUNDLER_VERSION: 2.0.1
          PGHOST: 127.0.0.1
          PGUSER: circleci
          RAILS_ENV: test
      - image: circleci/postgres:11-alpine-postgis-ram
        environment:
          POSTGRES_USER: circleci
          POSTGRES_DB: taskleaf
          POSTGRES_PASSWORD: password
    working_directory: ~/taskleaf
    steps:
      - checkout
      - run:
          name: setup bundler
          command: |
            sudo gem update --system
            sudo gem uninstall bundler
            sudo rm -f /usr/local/bin/bundle
            sudo rm -f /usr/local/bin/bundler
            sudo gem install bundler
      - run: bundle install
      - run: bundle exec rake db:create
      - run: bundle exec rake db:schema:load
      - run: bundle exec rspec

タグの書き方について、各キーワードと、何をしているかを以下にまとめておく。

解説

version: CircleCI のバージョンを指定する

version: 2.1

version キーには、使用するCircleCI のバージョンを指定する。現在は2, 2.0, 2.1 のうちのどれかを指定。ここに指定したバージョンが将来的に非推奨になったり、大きな変更があった場合に警告を出すかどうかの判断に使われるようだ。

jobs: ジョブの集合を表す

jobs:
  build:

CircleCI では実行ステップをjob という単位で区切っていて、jobs 配下に各ジョブ名を記述していく。今回は build というジョブのみ定義してある状態。Workflows というジョブの実行を制御できる仕組みがあるが、今回はこの設定は使用しないので割愛。

circleci.com

このWorkflows の設定を行わない場合、jobs の中に必ず build という名前のジョブを定義する必要があるので注意。build の他にも任意の名前のジョブを定義することができる。

docker: ジョブ実行の際にDocker Executor を使う

ジョブの実行にはExecutor を使い、現在はdocker, machine, macos の3種類から選んで使用することができる。

circleci.com

  build:
    docker:
      - image: circleci/ruby:2.5-stretch-node-browsers-legacy
        environment:
          BUNDLE_JOBS: 3
          BUNDLE_RETRY: 3
          BUNDLE_PATH: vendor/bundle
          BUNDLER_VERSION: 2.0.1
          PGHOST: 127.0.0.1
          PGUSER: circleci
          RAILS_ENV: test
      - image: circleci/postgres:11-alpine-postgis-ram
        environment:
          POSTGRES_USER: circleci
          POSTGRES_DB: taskleaf
          POSTGRES_PASSWORD: password

docker キーに指定できるオプションの中で、今回は必須であるimage と任意のオプションenvironment を指定している。image では使用するDocker イメージを指定し、 environment ではコンテナ内部で使用する環境変数マッピングを定義している。

今回は BUNDLER_VERSION: 2.0.1 を記述している。対象のアプリのRuby のバージョンが 2.5.5 であり、後のジョブのステップ実行の中でbundler を使うシーンがあるのだが、bundler のバージョンを指定しないでジョブを実行した場合、以下のようなエラーが出たためバージョン指定をしている。

$ #!/bin/bash -eo pipefail
bundle exec rake db:create
You must use Bundler 2 or greater with this lockfile.
Exited with code 20

使用するDocker イメージについてはCircleCI が提供しているビルド済みイメージがDocker Hub に公開されている。ビルド済みイメージについてのドキュメントは以下。

circleci.com

docker キーに指定できるオプションは以下に詳しい記述がある。

circleci.com

working_directory: steps の実行場所を指定する

    working_directory: ~/taskleaf

この後に記述されているsteps を実行するディレクトリを指定する。もしディレクトリが存在しない場合には、自動で作成される。

steps: 実行する内容を列挙する

    steps:
      - checkout
      - run:
          name: setup bundler
          command: |
            sudo gem update --system
            sudo gem uninstall bundler
            sudo rm -f /usr/local/bin/bundle
            sudo rm -f /usr/local/bin/bundler
            sudo gem install bundler
      - run: bundle install
      - run: bundle exec rake db:create
      - run: bundle exec rake db:schema:load
      - run: bundle exec rspec

steps の後には実行したいコマンドなどを列挙していき、ジョブの内容を組み立てていく。 checkout コマンドはソースコードworking_directory で指定したディレクトリにチェックアウト(=git clone のようなもの)するためのヘルパー関数。試しにstepscheckout の記述の後に以下のような記述を足してみる。

    steps:
      - checkout
      - run: pwd
      - run: ls -la
      - run: git remote -v

こうした場合にCircleCI のダッシュボード画面でコマンドの実行結果を見てみる。

f:id:yazawa_tech:20190721164529p:plain

### pwd の実行ログ
$ #!/bin/bash -eo pipefail
pwd
/home/circleci/taskleaf

### ls -la の実行ログ
$ #!/bin/bash -eo pipefail
ls -la
total 100
drwxr-xr-x 15 circleci circleci 4096 Jul 21 07:38 .
drwxr-xr-x  6 circleci circleci 4096 Jul 21 07:38 ..
drwxr-xr-x  2 circleci circleci 4096 Jul 21 07:38 .circleci
drwxr-xr-x  8 circleci circleci 4096 Jul 21 07:38 .git
-rw-r--r--  1 circleci circleci  620 Jul 21 07:38 .gitignore
-rw-r--r--  1 circleci circleci   22 Jul 21 07:38 .rspec
-rw-r--r--  1 circleci circleci    6 Jul 21 07:38 .ruby-version
-rw-r--r--  1 circleci circleci 2314 Jul 21 07:38 Gemfile
-rw-r--r--  1 circleci circleci 6882 Jul 21 07:38 Gemfile.lock
-rw-r--r--  1 circleci circleci  374 Jul 21 07:38 README.md
-rw-r--r--  1 circleci circleci  227 Jul 21 07:38 Rakefile
drwxr-xr-x 10 circleci circleci 4096 Jul 21 07:38 app
drwxr-xr-x  2 circleci circleci 4096 Jul 21 07:38 bin
drwxr-xr-x  5 circleci circleci 4096 Jul 21 07:38 config
-rw-r--r--  1 circleci circleci  130 Jul 21 07:38 config.ru
drwxr-xr-x  3 circleci circleci 4096 Jul 21 07:38 db
drwxr-xr-x  4 circleci circleci 4096 Jul 21 07:38 lib
drwxr-xr-x  2 circleci circleci 4096 Jul 21 07:38 log
-rw-r--r--  1 circleci circleci   66 Jul 21 07:38 package.json
drwxr-xr-x  2 circleci circleci 4096 Jul 21 07:38 public
drwxr-xr-x  4 circleci circleci 4096 Jul 21 07:38 spec
drwxr-xr-x  2 circleci circleci 4096 Jul 21 07:38 storage
drwxr-xr-x  2 circleci circleci 4096 Jul 21 07:38 tmp
drwxr-xr-x  2 circleci circleci 4096 Jul 21 07:38 vendor

### git remote -v のログ
$ #!/bin/bash -eo pipefail
git remote -v
origin  git@github.com:yazawatech/taskleaf.git (fetch)
origin  git@github.com:yazawatech/taskleaf.git (push)

pwd コマンドのログにはworking_directory で指定したディレクトリが出力され、ls -la コマンドのログにはRails アプリのディレクトリ構造が出力され、git remote -v のログでそのディレクトリ構造のファイル群がクローンされたリポジトリが表示されている。

run: 実行するコマンドを記述

      - run:
          name: setup bundler
          command: |
            sudo gem update --system
            sudo gem uninstall bundler
            sudo rm -f /usr/local/bin/bundle
            sudo rm -f /usr/local/bin/bundler
            sudo gem install bundler
      - run: bundle install
      - run: bundle exec rake db:create
      - run: bundle exec rake db:schema:load
      - run: bundle exec rspec

複数のrun キーを列挙することで、上から順にコマンドを実行することができる。今回の目標は最後のbundle exec rspec を実行し、テストケースが全てパスすること。ここまでエラーなどがなく最後までジョブの実行が完了すると、ダッシュボードで以下の画面のようにsuccess のタグが付く。

f:id:yazawa_tech:20190721170114p:plain

bundle exec rspec の実行結果を見てみると、ローカルホストで rspec コマンドを実行した時のようなメッセージが出力されている。

$ #!/bin/bash -eo pipefail
bundle exec rspec
Capybara starting Puma...
* Version 3.12.1 , codename: Llamas in Pajamas
* Min threads: 0, max threads: 4
* Listening on tcp://127.0.0.1:46559
.....

Finished in 4.19 seconds (files took 1.52 seconds to load)
5 examples, 0 failures

これでリモートリポジトリにプッシュしてRSpec を実行させることができた。

まとめ

  • CircleCI を使ってテストの実行を自動化してみた
  • CircleCI のドキュメントがかなり充実しているし日本語版もあるので、最初は全くわからなかったが丁寧に読めば実現できる
  • 次はブランチを指定してのジョブの実行や、オートデプロイも実現できるようにしたい