CicleCIでRspecとRubocop通すまでにつまずいたところとその解決法

転職活動用のポートフォリオをCircleCIで自動テストできるように設定しました。

CircleCIの設定は`.circleci/config.yml`だけだから簡単だと思ったら大間違いでした。
思いのほか時間がかかりました。
自分がつまずいたところを備忘録として残しておきます。

# 最初に設定した.circleci/config.yml
「CircleCI Rails MySQL」等で検索して、他の人たちが.circleci/config.ymlをどのように書いているのか探して参考にしようと思いました。

最初はこちらのQiita記事 [CircleCIでSystemSpec(RSpec)とRubocopを走らせる] (https://qiita.com/YK0214/items/bbed63ea7ca5367dae2f) を参考にしましたが、rubocopのところでエラーが出ました（エラーは後述）。

```rury:.circleci/config.yml
version: 2.1

orbs:
  ruby: circleci/ruby@1.1.0

jobs:
  build:
    docker:
      - image: circleci/ruby:2.5.1-node-browsers
        environment:
          BUNDLER_VERSION: 2.1.4
    steps:
      - checkout
      - ruby/install-deps

  # 時間短縮のためテストを並列実行する
  test:
    parallelism: 3
    docker:
      - image: circleci/ruby:2.5.1-node-browsers
        environment:
          DB_HOST: 127.0.0.1
          RAILS_ENV: test
          BUNDLER_VERSION: 2.1.4
      - image: circleci/mysql:5.6
        command: --default-authentication-plugin=mysql_native_password
        environment:
          MYSQL_ALLOW_EMPTY_PASSWORD: 'true'
          MYSQL_ROOT_HOST: '%'
    steps:
      - checkout
      - ruby/install-deps
      - run: mv config/database.yml.ci config/database.yml 
      - run:
          name: Wait for DB
          command: dockerize -wait tcp://localhost:3306 -timeout 1m   
      - run: bundle exec rake db:create
      - run: bundle exec rake db:schema:load
      # Run rspec in parallel
      - ruby/rspec-test
      - ruby/rubocop-check

workflows:
  version: 2
  build_and_test:
    jobs:
      - build
      - test:
          requires:
            - build
```
## Rubocopが起動できない

```
#!/bin/bash -eo pipefail
mkdir -p /tmp/rubocop-results
bundle exec rubocop . --out /tmp/rubocop-results/check-results.xml --format progress
```
rubocopがインストールされておらず起動されていないのではないかと思います。
`command`を指定して起動できると考えやってみましたが、どうしても解決できませんでした。

# その次に参考にした記事
[【circleCI】Railsアプリでgithubと連携してrubocopとrspecテストを走らせる](https://qiita.com/AK4747471/items/b2161784065f21cd1645#configdatabaseymlci%E3%81%AE%E8%A8%98%E8%BF%B0)

今度はこちらの記事を参考にしました。
rubyのバージョン、アプリのディレクトリ、bundlerのバージョンのところだけ変えてやりました。

## .circleci/config.ymlの修正

```rury:.circleci/config.yml
# Ruby CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-ruby/ for more details
#
version: 2
jobs:
  build:
    docker:
      # specify the version you desire here
      - image: circleci/ruby:2.5.1-node-browsers
        environment:
          - BUNDLER_VERSION: 2.1.4
          - RAILS_ENV: 'test'
      
      - image: circleci/mysql:5.6
        environment:
          - MYSQL_ALLOW_EMPTY_PASSWORD: 'true'
          - MYSQL_ROOT_HOST: '%'

      # Specify service dependencies here if necessary
      # CircleCI maintains a library of pre-built images
      # documented at https://circleci.com/docs/2.0/circleci-images/
      # - image: circleci/postgres:9.4

    working_directory: ~/projects/pfc-master

    steps:
      - checkout

      # Download and cache dependencies
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "Gemfile.lock" }}
            # fallback to using the latest cache if no exact match is found
            - v1-dependencies-

      - run:
          name: install dependencies
          command: |

            gem install bundler -v 2.1.4
            bundle install --jobs=4 --retry=3 --path vendor/bundle

      - save_cache:
          paths:
            - ./vendor/bundle
          key: v1-dependencies-{{ checksum "Gemfile.lock" }}

      - run: mv config/database.yml.ci config/database.yml 

      # Database setup
      - run: bundle exec rake db:create
      - run: bundle exec rake db:schema:load

# rubocopを走らせる記述です。
      - run:
          name: Rubocop
          command: bundle exec rubocop

      # run tests!
      - run:
          name: run tests
          command: |
            mkdir /tmp/test-results
            TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | \
              circleci tests split --split-by=timings)"

            bundle exec rspec \
              --format progress \
              --format RspecJunitFormatter \
              --out /tmp/test-results/rspec.xml \
              --format progress \
              $TEST_FILES

      # collect reports
      - store_test_results:
          path: /tmp/test-results
      - store_artifacts:
          path: /tmp/test-results
          destination: test-results
```
## YAMLの文法エラー

```
Unable to parse YAML
YAMLを解析できません

while parsing a block mapping
ブロックマッピングを解析中です
ブロックマッピングは、-runのひとまとまりのことを指しているのだろう

 in 'string', line 41, column 11:
              name: install dependencies
              ^

expected <block end>, but found '<scalar>'
ブロックの終わりがあるべきなのに、次のブロックの始まり（scalar:-runの「-」のこと）が見つかりません

 in 'string', line 44, column 13:
                gem install bundler -v 2.1.4
```

これの原因は、途中にコメントアウトのテキストを挟んで記述していたからでした。
他の記事からそのままペーストして使おうとするとこういうエラーが発生するようなので注意が必要ですね。
コメントアウトの記述を消してくっつけて記述したら解決しました。

## Rubocopで修正が必要な箇所を指摘される

Rubocopはコードを検査して「ここは修正した方がいいよ」と教えてくれるツールです。
なんと300個くらい指摘されてしまいました。

300個もあると1つ1つ修正してたら途方もないので、一気に修正してくれるコマンドを使いました。

こちらの記事 [Rubocopをインストールして、Rails本家の設定を使う方法](https://k-koh.hatenablog.com/entry/2019/11/18/231410#Rubocop%E3%81%A8%E3%81%AFRuby%E3%81%AE%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92%E8%87%AA%E5%8B%95%E4%BF%AE%E6%AD%A3%E3%81%97%E3%81%A6%E3%81%8F%E3%82%8C%E3%82%8B%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%83%E3%82%BF%E3%83%BC) に教えてもらったのですが、下記のコマンドを使うと、指摘された箇所のほとんどを一気に修正してくれます。

```
bundle exec rubocop --auto-correct
```
ただ、これで全部は解決されず、私の場合2つは自分で修正する必要がありました。
そのどちらも、「使われてない変数があります（Lint/UselessAssignment）」という指摘だったので、コメントアウトしても問題ないことを確認してから、その部分の記述を消して解決しました。

## Rubocopのファイルがloadされない

```
cannot load such file -- rubocop-packaging
cannot load such file -- rubocop-performance
cannot load such file -- rubocop-rails
```
Gemfileの`group :development, :test do`にgem "rubocop"を加えてbundle installすると、`.rubocop.yml`に

```
require:
  - rubocop-packaging
  - rubocop-performance
  - rubocop-rails
```
となるので、これでこれら3つのファイルは読み込まれてくれるのかと思っていましたが、読み込まれてくれませんでした。

結局このようにGemfileに書き加えてbundle installしたら解決しました。

```ruby:Gemfile
group :development, :test do
  gem "rubocop"
  gem "rubocop-packaging"
  gem "rubocop-performance"
  gem "rubocop-rails"
end
```

# 最終的にうまくいった.circleci/config.ymlのコード

```rury:.circleci/config.yml
# Ruby CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-ruby/ for more details
#
version: 2
jobs:
  build:
    docker:
      - image: circleci/ruby:2.5.1-node-browsers
        environment:
          - BUNDLER_VERSION: 2.1.4
          - RAILS_ENV: 'test'
     
      - image: circleci/mysql:5.6
        environment:
          - MYSQL_ALLOW_EMPTY_PASSWORD: 'true'
          - MYSQL_ROOT_HOST: '%'

      # Specify service dependencies here if necessary
      # CircleCI maintains a library of pre-built images
      # documented at https://circleci.com/docs/2.0/circleci-images/
      # - image: circleci/postgres:9.4

    working_directory: ~/projects/pfc-master

    steps:
      - checkout

      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "Gemfile.lock" }}
            # fallback to using the latest cache if no exact match is found
            - v1-dependencies-

      - run:
          name: install dependencies
          command: |
            gem install bundler -v 2.1.4
            bundle install --jobs=4 --retry=3 --path vendor/bundle

      - save_cache:
          paths:
            - ./vendor/bundle
          key: v1-dependencies-{{ checksum "Gemfile.lock" }}

      - run: mv config/database.yml.ci config/database.yml 

      # Database setup
      - run: bundle exec rake db:create
      - run: bundle exec rake db:schema:load

      - run:
          name: run rubocop
          command: bundle exec rubocop

      # run tests!
      - run:
          name: run tests
          command: |
            mkdir /tmp/test-results
            TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | \
              circleci tests split --split-by=timings)"

            sudo gem install bundler
            sudo gem install rspec
            sudo gem install rspec-core
            bundle exec rspec \
              --format progress \
              --format RspecJunitFormatter \
              --out /tmp/test-results/rspec.xml \
              --format progress \
              $TEST_FILES

      # collect reports
      - store_test_results:
          path: /tmp/test-results
      - store_artifacts:
          path: /tmp/test-results
          destination: test-results
```

## config/database.yml.ciの設定

```
run: mv config/database.yml.ci config/database.yml 
```
`config/database.yml.ci`のパスを`config/database.yml`に変更しています。

`config/database.yml.ci`を`config/database.yml`として認識させている＝`config/database.yml.ci`を反映させている、ということだと思います。

```ruby:config/database.yml.ci
test:
  adapter: mysql2
  encoding: utf8
  pool: 5
  username: 'root'
  port: 3306
  host: '127.0.0.1'
  database: ci_test
```

```ruby:config/database.yml
test:
  adapter: mysql2
  encoding: utf8
  database: pfc-master_test
  pool: 5
  username: 'root'
  password: password
  host: '127.0.0.1'
```