Edited at

RailsチュートリアルのサンプルにCircleCIを入れる

Railsチュートリアルの発展編としてCircleCIを導入し、Minitest & Rspecを実行するところまで設定しました。 Ruby2.6.1 & CircleCI 2(2.1)対応 & CircleCI Workflow対応 & Orbs活用したものが見当たらなかったので、記録に残しておきます。

完全なファイルはHistory for railstutorial/.circleci/config.ymlを参照下さい。


1. Hello World

Dockerで実行し、echo "hello world"を実行するところまで。


.circleci/config.yaml

version: 2

jobs:
build:
docker:
- image: circleci/ruby:2.6.1-node-browsers
steps:
- run: echo "hello world"


2. bundle install -> rails test 実行まで


.circleci/config.yaml

version: 2

jobs:
build:
docker:
- image: circleci/ruby:2.6.1-node-browsers
steps:
- checkout
- run: bundle install
- run: bundle exec rails db:create db:migrate RAILS_ENV=test
- run: bundle exec rails test


3. bundle installの結果をキャッシュ

bundle installの実行が長いので結果をキャッシュさせる・・・が実は下記は正しく動いていません。キャッシュ対象をvendor/bundleとしているが、インストールパスがvendor/bundleになっていないからです。4で修正します。


.circleci/config.yml

version: 2

jobs:
build:
docker:
- image: circleci/ruby:2.6.1-node-browsers
steps:
# コードのチェックアウト
- checkout

# bundle installのキャシュがあればそれを取ってくる
- restore_cache:
keys:
- gem-cache-{{ arch }}-{{ .Branch }}-{{ checksum "Gemfile.lock" }}
- gem-cache-{{ arch }}-{{ .Branch }}
- gem-cache

# bundle installの実行
- run: bundle install

# bundle installのデータをキャッシュ
- save_cache:
key: gem-cache-{{ arch }}-{{ .Branch }}-{{ checksum "Gemfile.lock" }}
paths:
- ./vendor/bundle

# 初期設定
- run: bundle exec rails db:create db:migrate RAILS_ENV=test

# テストの実行
- run: bundle exec rails test



4. bundle installのインストール先をvendor/bundleに変更

bundle install --path vendor/bundle に変えれば良いだけのはずなのですが、bundle exec rails testを実行すると下記のエラーが出て動きませんでした。結局bundle exec rails testbundle exec rake testにして対処、納得はできていません。どなたか原因わかる方教えて欲しいです。

合わせてDBセットアップとMinitestの実行をCircleCIで確認しやすいように名前をつけました。

#!/bin/bash -eo pipefail

bundle exec rails test
Could not find CFPropertyList-2.3.6 in any of the sources
Run `bundle install` to install missing gems.
Exited with code 1


.circleci/config.yml

version: 2

jobs:
build:
docker:
- image: circleci/ruby:2.6.1-node-browsers
environment:
RAILS_ENV: test
steps:
# コードのチェックアウト
- checkout

# bundle installのキャシュがあればそれを取ってくる
- restore_cache:
keys:
- gem-cache-{{ arch }}-{{ .Branch }}-{{ checksum "Gemfile.lock" }}
- gem-cache-{{ arch }}-{{ .Branch }}
- gem-cache

# bundle installの実行
- run:
name: Bundle Install
command: bundle check --path=vendor/bundle || bundle install --path vendor/bundle --clean --jobs 4 --retry 3

# bundle installのデータをキャッシュ
- save_cache:
key: gem-cache-{{ arch }}-{{ .Branch }}-{{ checksum "Gemfile.lock" }}
paths:
- ./vendor/bundle

# 初期設定
- run:
name: Database setup
command: |
bundle exec rails db:create
bundle exec rails db:migrate

# テストの実行
- run:
name: Rails Test
command: bundle exec rake test



5. Rubocop対応 & Reviewdog対応

Reviewdogはrubocopなどの静的解析ツールで指摘があった事項をpull requestにコメントしてくれるツールです。非常に便利なので合わせて入れました。


circleci/config.yml

version: 2

jobs:
build:
docker:
- image: circleci/ruby:2.6.1-node-browsers
environment:
BUNDLER_VERSION: 2.0.1
RAILS_ENV: test
REVIEWDOG_VERSION: 0.9.11
steps:
# コードのチェックアウト
- checkout

# Bundlerのバージョン確認
- run:
name: Update bundler
command: |
sudo gem update --system
sudo gem uninstall bundler
sudo rm /usr/local/bin/bundle
sudo rm /usr/local/bin/bundler
sudo gem install bundler
- run:
name: Which bundler?
command: bundle -v

# bundle installのキャシュがあればそれを取ってくる
- restore_cache:
keys:
- gem-cache-{{ arch }}-{{ .Branch }}-{{ checksum "Gemfile.lock" }}
- gem-cache-{{ arch }}-{{ .Branch }}
- gem-cache

# bundle installの実行
- run:
name: Bundle Install
command: bundle check --path=vendor/bundle || bundle install --path vendor/bundle --clean --jobs 4 --retry 3

# Reviewdogのインストール
- run:
name: Install Reviewdog
command: |
curl -fSL https://github.com/haya14busa/reviewdog/releases/download/$REVIEWDOG_VERSION/reviewdog_linux_amd64 -o reviewdog && chmod +x ./reviewdog

# bundle installのデータをキャッシュ
- save_cache:
key: gem-cache-{{ arch }}-{{ .Branch }}-{{ checksum "Gemfile.lock" }}
paths:
- ./vendor/bundle

# 初期設定
- run:
name: Database setup
command: |
bundle exec rails db:create
bundle exec rails db:migrate

# テストの実行
- run:
name: Rails Test
command: bundle exec rake test

# Rubocop & Reviewdogの実行
- run:
name: Rubocop & Reviewdog
command: bundle exec rubocop | ./reviewdog -f=rubocop -reporter=github-pr-review



6. Workflow対応

bundle install、Minitest、Rubocopの実行をそれぞれ定義し、実行順序を別途Workflowとして記述しました。


circleci/config.yml

version: 2

defaults: &defaults
working_directory: ~/workspace
docker:
- image: circleci/ruby:2.6.1-node-browsers
environment:
BUNDLE_JOBS: 3
BUNDLE_RETRY: 3
BUNDLE_PATH: vendor/bundle
RAILS_ENV: test
REVIEWDOG_VERSION: 0.9.11

jobs:
bundle_install:
<<: *defaults
steps:
- checkout
- attach_workspace:
at: ~/workspace
- restore_cache:
keys:
- gem-cache-{{ arch }}-{{ .Branch }}-{{ checksum "Gemfile.lock" }}
- gem-cache-{{ arch }}-{{ .Branch }}
- gem-cache
- run:
name: Bundle Install
command: bundle check || bundle install --clean
# bundle installのデータをキャッシュ
- save_cache:
key: gem-cache-{{ arch }}-{{ .Branch }}-{{ checksum "Gemfile.lock" }}
paths:
- ~workspace/vendor/bundle
- persist_to_workspace:
root: .
paths: vendor/bundle

rails_minitest:
<<: *defaults
steps:
- checkout
- attach_workspace:
at: ~/workspace

# 初期設定
- run:
name: Database setup
command: |
bundle exec rails db:create
bundle exec rails db:migrate
- run:
name: Rails Minitest
command: bundle exec rake test

rubocop:
<<: *defaults
steps:
- checkout
- attach_workspace:
at: ~/workspace

# Reviewdogのインストール
- run:
name: Install Reviewdog
command: |
curl -fSL https://github.com/haya14busa/reviewdog/releases/download/$REVIEWDOG_VERSION/reviewdog_linux_amd64 -o reviewdog && chmod +x ./reviewdog
# Rubocop & Reviewdogの実行
- run:
name: Rubocop & Reviewdog
command: bundle exec rubocop | ./reviewdog -f=rubocop -reporter=github-pr-review

workflows:
version: 2
continuous-integration:
jobs:
- bundle_install
- rails_minitest:
requires:
- bundle_install
- rubocop:
requires:
- bundle_install



7. Orbs対応

bundle installの実行とreviewdogの実行をorbsを使うようにしました。

合わせて使用するDockerイメージの指定をexecutorsを使って書き直しています。


circleci/config.yml

version: 2.1

orbs:
ruby-orbs: sue445/ruby-orbs@1.4.3
reviewdog: yasuhiroki/reviewdog@0.0.3

executors:
default:
working_directory: ~/workspace
docker:
- image: circleci/ruby:2.6.1-node-browsers
environment:
RAILS_ENV: test

commands:
lint:
parameters:
lint_result_file_path:
description: Lint result file path
type: string
steps:
- checkout
- run:
name: Rubocop update
command: gem update rubocop
- run: rubocop --out <<parameters.lint_result_file_path>> || true
- store_artifacts:
path: <<parameters.lint_result_file_path>>

jobs:
rails_minitest:
executor:
name: default
steps:
- checkout
- ruby-orbs/bundle-install:
bundle_clean: true
bundle_extra_args: ''
bundle_gemfile: Gemfile
bundle_jobs: 4
bundle_path: vendor/bundle
bundle_retry: 3
cache_key_prefix: v1-bundle
restore_bundled_with: true
# 初期設定
- run:
name: Database setup
command: |
bundle exec rails db:create
bundle exec rails db:migrate
- run:
name: Rails Minitest
command: bundle exec rake test

workflows:
continuous-integration:
jobs:
- rails_minitest
- reviewdog/reviewdog:
linter_image: cagedata/rubocop
reviewdog_format_option: '-f=rubocop'
run_linter_steps:
- lint:
lint_result_file_path: lint_result.txt
lint_result_file_path: lint_result.txt