プッシュ時にRSpec+Rubocopを自動でするようにCircleCIでbuildする【Rails】

#はじめに
Railsでアプリを作っている初学者です。
アプリ内にCircleCIを使った自動テストを入れたい！と思い、導入してみましたので、その時に詰まったことをまとめました。

同じようにアプリにCircleCIを入れたいなと思っている方の参考になれば嬉しいです！！

また、間違い等がありましたらご指摘いただけますと幸いです。

##バージョン
Ruby:2.6.6
Rails:5.2.4
Mysql:5.7
環境構築にDocker使用


##前提
以下は題名のことをしたい場合＆CircleCIを理解する上で必要です！

・Dockerを使用したことがある
・Rspecを導入済
・Rubocopを導入済
・Githubアカウントがある


まず、CircleCIの公式入門ガイドをすることをおすすめします！自分は実際の挙動があまりイメージ出来なかったのですが、これでざっくり理解することができました。

CircleCI入門ガイド:https://circleci.com/docs/ja/2.0/getting-started/



そして入門ガイドをしたところで、CircleCIをアプリに加えてみます。
ルートディレクトリに .circleci フォルダを作成してコンフィグを作る。
そしてデータベースを作る、とできるはず！


#うまくいかなかったパターン

参考：CircleCIでSystemSpec(RSpec)とRubocopを走らせる
https://qiita.com/YK0214/items/bbed63ea7ca5367dae2f

まず、こちらのQiitaの記事を参考にしましたが、自分の環境ではうまくいきませんでした。
ですが、こちらの経緯も記録しておきます。


config.ymlを作る

>```ruby:.circleci\config.yml
version: 2.1

>orbs:
  ruby: circleci/ruby@1.1.0

>jobs:
  build:
    docker:
      - image: circleci/ruby:2.6.6-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.7
        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
```
>引用：CircleCIでSystemSpec(RSpec)とRubocopを走らせる
https://qiita.com/YK0214/items/bbed63ea7ca5367dae2f

database.yml.ciを作る

すでにconfig内にdatabase.ymlがあるけど、それとは別で新規で作ります。
新規のDockerfileを使うのでデータベースも新しくなります。


>```ruby:config\database.yml.ci
test:
  adapter: mysql2
  encoding: utf8
  pool: 5
  username: 'root'
  port: 3306
  host: '127.0.0.1'
  database: ci_test
```
>引用：CircleCIでSystemSpec(RSpec)とRubocopを走らせる
https://qiita.com/YK0214/items/bbed63ea7ca5367dae2f

Githubへプッシュして、マージするとCircleCIで自動でBuildされます
失敗している！！！


![Qiita用画像CircleCI1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619687/39b6d87b-4092-7b83-3d6b-a51602fe3684.png)


Bundleのバージョンが違うみたい。

ちょっと変更


```ruby:.circleci\config.yml

version: 2.1

orbs:
  ruby: circleci/ruby@1.1.0

jobs:
  build:
    docker:
      - image: circleci/ruby:2.6.6-node-browsers
        environment:
          BUNDLER_VERSION: 1.17.2
    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.7
        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
```

`BUNDLER_VERSION: 1.17.2`に変更して再Push


![Qiita用画像CircleCI3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619687/20c5c8a1-6218-a83f-48c0-e2ed9a355649.png)

これでできた！！！と思ってshow all checkをクリックして確認すると、
途中でbuildが止まっています...！

![qiita circleCI1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619687/a802fd8c-39e8-374e-3e7d-809388f6351d.png)

よくよく見たらこんな記載が。

![Qiita用画像CircleCI.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619687/1e624daa-f5fb-037e-15a3-375833eaf999.png)

これは有料枠にしろということですね！？
無料枠ではコンテナ1つでないと動かないのですが、このコードは2つのDockerを起動させようとしています。
なので途中で止まっていたんだなあということがわかりました...

というわけで修正を行います

#うまくいったパターン

今度はこちらの記事を参考に、config.ymlを作成します。
エラーがいくつか出たので最終的には細かく修正を加えています。

参考：CicleCIでRspecとRubocop通すまでにつまずいたところとその解決法
https://qiita.com/naota7118/items/056770bcf53136e94788



>```ruby:.circleci/config.yml
# CircleCIのバージョンのことで、「2」、「2.0」、「2.1」のうちのどれかを指定します。
version: 2.1

>orbs:
  ruby: circleci/ruby@1.1.0

># jobsは、実行処理の単位です。
jobs:
  build:
    # DockerでRubyのイメージを作成します。Dockerfileもしくはローカル環境とVersionは合わせること。
    docker:
      - image: circleci/ruby:2.6.6-node-browsers
        environment:
          # Dockerで作った、circleCI上で'bundle install'します
          BUNDLER_VERSION: 1.17.2
    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.7
        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
```
>引用：CicleCIでRspecとRubocop通すまでにつまずいたところとその解決法
https://qiita.com/naota7118/items/056770bcf53136e94788




公式:CircleCI-Public/circleci-demo-ruby-rails
https://github.com/CircleCI-Public/circleci-demo-ruby-rails/blob/master/config/database.yml

参考：【CircleCI】Railsアプリに導入（設定ファイルについて）
https://qiita.com/Daiki-Abe/items/d90599d904c2b1370d10

というわけで修正

##①bundle exec rake:db migrateを追加
マイグレーションされていないというエラーが出ているので、上記のファイルの中に
`bundle exec rake:db migrate`を追加します

##②細かすぎるgemまで見ているのでRubocopを編集

migrateが無事されましたが、今度はRubocopでエラーがでました。
エラー文は以下。

```
For more information: https://docs.rubocop.org/rubocop/versioning.html 
vendor/bundle/ruby/2.6.0/gems/msgpack-1.3.3/.rubocop.yml: Lint/Eval has the wrong namespace - should be Security 
Error: RuboCop found unsupported Ruby version 2.3 in `TargetRubyVersion` parameter (in vendor/bundle/ruby/2.6.0/gems/msgpack-1.3.3/.rubocop.yml). 2.3-compatible analysis was dropped after version 0.81. 
Supported versions: 2.4, 2.5, 2.6, 2.7, 3.0
```

Rubocop.ymlでrubyバージョンの指定をすることで解決しました

```
AllCops:
  # Rubyバージョン指定
  TargetRubyVersion: 2.6
```


参考：原因と対応「Error: RuboCop found unsupported Ruby version 2.1」
https://blog.mothule.com/ruby/rubocop/ruby-rubocop-found-unsupported-ruby-version


buildには失敗してるけどRubocopは通っています！

次はRSpecですがここでもエラーが出ています。

##③RSpecのmysql2::Error::ConnectionError:を解消する


②のエラーを直したあとにrspecを実行すると、エラーがでるようになりました
rspecの実行結果は以下です。

```terminal
PS C:\Users\> rspec
An error occurred while loading ./spec/features/toppage_spec.rb.
Failure/Error: ActiveRecord::Migration.maintain_test_schema!

Mysql2::Error::ConnectionError:
  Unknown MySQL server host 'db' (0)
# ./spec/rails_helper.rb:28:in `<top (required)>'
# ./spec/features/toppage_spec.rb:1:in `<top (required)>'

Top 0 slowest examples (0 seconds, 0.0% of total time):

Finished in 0.00009 seconds (files took 3 minutes 27 seconds to load)

0 examples, 0 failures, 1 error occurred outside of examples

```


databese.ymlに以下を加えることで解決しました。

```databese.yml
test:
  <<: *default
  database: Music-record_test
  host: <%= ENV['MYSQL_ROOT_HOST'] || '127.0.0.1' %>
```




参考：ローカル環境のCircleCIでMysql2::Error::ConnectionError: Unknown MySQL server host 'db' (-2)が出る
https://qiita.com/mitsu1208g/questions/c9681d1204a1b878f987



##④RSpecのエラー LoadError: cannot load such file -- rspec_junit_formatterの解消

次はCircleCIでのRSpecでエラーがでました。


```

Error reading historical timing data: file does not exist
Requested weighting by historical based timing, but they are not present. Falling back to weighting by name.
No examples found.
bundler: failed to load command: rspec (/home/circleci/repo/vendor/bundle/ruby/2.6.0/bin/rspec)
LoadError: cannot load such file -- rspec_junit_formatter
  /home/circleci/repo/vendor/bundle/ruby/2.6.0/gems/rspec-core-3.9.3/lib/rspec/core/formatters.rb:235:in `require'
  /home/circleci/repo/vendor/bundle/ruby/2.6.0/gems/rspec-core-
・
・
・

  /home/circleci/repo/vendor/bundle/ruby/2.6.0/gems/rspec-core-3.9.3/lib/rspec/core/runner.rb:45:in `invoke'
  /home/circleci/repo/vendor/bundle/ruby/2.6.0/gems/rspec-core-3.9.3/exe/rspec:4:in `<top (required)>'
  /home/circleci/repo/vendor/bundle/ruby/2.6.0/bin/rspec:23:in `load'
  /home/circleci/repo/vendor/bundle/ruby/2.6.0/bin/rspec:23:in `<top (required)>'

Exited with code exit status 1
CircleCI received exit code 1

Uploading test results
0s

Uploading artifacts
0s

```

`LoadError: cannot load such file -- rspec_junit_formatter`
この1文がエラーの原因のようです。

`rspec_junit_formatter`がないということで以下の記事を参考にGemを追加します。

参考：CI/CD環境を作った時に起きたエラー備忘録[Rails + CircleCI +Capistrano +AWS]
https://qiita.com/orangeupup90027/items/6f83850d1842adf3c09a

>① rspec_junit_formatterがないと言われる
>テストを走らせた時に出たエラー

>Error reading historical timing data: file does not exist
>Requested weighting by historical based timing, but they are not present. Falling back to >weighting by name.
>No examples found.
>bundler: failed to load command: rspec (/home/circleci/circleci-demo-ruby->rails/vendor/bundle/ruby/2.5.0/bin/rspec)
>LoadError: cannot load such file -- rspec_junit_formatter

>結論としてはrspec_junit_formatterをgemfileに追加する。



Gemfileに`rspec_junit_formatter`を追加します。

```ruby:Gemfile
group :test do
  # Adds support for Capybara system testing and selenium driver
  gem 'capybara', '>= 2.15'
  gem 'selenium-webdriver'
  # Easy installation and use of chromedriver to run system tests with Chrome
  # gem 'chromedriver-helper'
  gem 'rspec_junit_formatter' #追加
  gem 'webdrivers', '~> 3.0'
end
```

これでGithubにプッシュするとCircleCIの画面はこのようになりました。

![CircleCIde.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619687/761149b2-546d-2016-3d38-813c4cff44f0.png)




長くなりましたが、これでCircleCIでBuildができました！

#最終的なコード

細かな修正を入れた結果が以下です。

※CircleCIはインデントに厳しい＆文字列のブロックの別れ方がシビアなので、実際にコードをコピー・記載するときはコメントなしの方が良いです。

```.circleci\config.yml
# CircleCIのバージョンのことで、「2」、「2.0」、「2.1」のうちのどれかを指定します。
version: 2

jobs:
  build:
    docker:
      - image: circleci/ruby:2.6.6-node-browsers
        environment:
          - RAILS_ENV: 'test'
          - MYSQL_HOST: 127.0.0.1
          - MYSQL_USERNAME: 'root'
          - MYSQL_PASSWORD: ''
          - MYSQL_PORT: 3306
      - image: circleci/mysql:5.7
        environment:
          - MYSQL_ALLOW_EMPTY_PASSWORD: 'true'
          - MYSQL_ROOT_HOST: '%'
    working_directory: ~/repo
    steps:
      - checkout
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "Gemfile.lock" }}
            - v1-dependencies-
      - run:
          name: install dependencies
          command: |
            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
      - run: bundle exec rake db:create
      - run: bundle exec rake db:migrate
      - run: bundle exec rake db:schema:load
      - run:
          name: RuboCop
          command: bundle exec rubocop
      - run:
          name: RSpec
          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

      - store_test_results:
          path: /tmp/test-results
      - store_artifacts:
          path: /tmp/test-results
          destination: test-results

```

```config\database.yml.ci

test: &default
  adapter: mysql2
  encoding: utf8
  pool: 5
  username: <%= ENV.fetch("MYSQL_USERNAME") %>
  password: <%= ENV.fetch("MYSQL_PASSWORD") %>
  host: <%= ENV.fetch("MYSQL_HOST") %>
  port: <%= ENV.fetch("MYSQL_PORT") %>
  database: ci_test

```

ここまでお付き合いいただきありがとうございます！


#参考

【circleCI】Railsアプリでgithubと連携してrubocopとrspecテストを走らせる
https://qiita.com/AK4747471/items/b2161784065f21cd1645


CicleCIでRspecとRubocop通すまでにつまずいたところとその解決法
https://qiita.com/naota7118/items/056770bcf53136e94788


【CircleCI】Railsアプリに導入（設定ファイルについて）
https://qiita.com/Daiki-Abe/items/d90599d904c2b1370d10#databaseymlci%E3%82%92%E4%BD%9C%E6%88%90


【初心者向け】deviseのユーザー登録をRSpecでテストする
https://qiita.com/HiMinmeg/items/37a59cd266c63330797a#%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B32!