【CircleCI】設定とエラー対処法　自分用メモ

とりあえずCIのみで、デプロイとかの処理はしていないです。
CircleCI内にDocker内に環境を作ってRSpecを回すところまでの設定です。
拾い物のconfigファイルを改造してとりあえず動くようにしたものなので、いろいろと足りていないような気はします。そして、ただのメモなので記事として全く整理していません。

## 環境

```
CircleCI  2.1
Bundler  2.1.4
Ruby  2.5.3
Rails  5.2.4.2
MySQL  8.0.19
```
ローカルとDocker内のバージョンは揃えています。

## 最初の設定

いろいろと不備がある設定です。

```yml:.circleci/config.yml
version: 2.1
orbs:
  ruby: circleci/ruby@0.1.2

jobs:
  build:
    working_directory: ~/circleci-demo-ruby-rails
    docker:
      - image: circleci/ruby:2.5.3-node-browsers-legacy
        environment:
          DB_HOST: 127.0.0.1
          RAILS_ENV: test
          BUNDLER_VERSION: 2.1.4
      - image: circleci/mysql:8.0.19-ram
        environment:
          MYSQL_USER: root
          MYSQL_DB: circle_test

    steps:
      - checkout

      # Restore bundle cache
      - restore_cache:
          keys:
            - rails-demo-{{ checksum "Gemfile.lock" }}
            - rails-demo-

      - run:
          name: Which bundler?
          command: bundle -v

      - run:
          name: bundle install
          command: |
            bundle install --jobs=4 --retry=3 --path vendor/bundle

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

      # Database setup
      - run: cp -v config/database.ci.yml config/database.yml
      - run: bundle exec rails db:create
      - run: bundle exec rails db:schema:load

      # RSpec
      - run:
          name: run rspec
          command: |
            bundle exec rspec --profile 10 \
                              --format RspecJunitFormatter \
                              --out test_results/rspec.xml \
                              --format progress \
                              $(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)

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

## エラー
### You must use Bundler 2 or greater with this lockfile.

```
#!/bin/bash -eo pipefail
bundle install --jobs=4 --retry=3 --path vendor/bundle
You must use Bundler 2 or greater with this lockfile.

Exited with code exit status 20
```

#### 解決法

```yml:.circleci/config.yml
      # Which bundler?の前に追加
      - run:
          name: setup bundler
          command: |
            sudo gem update --system
            sudo gem uninstall bundler
            sudo rm /usr/local/bin/bundle
            sudo gem install bundler
```

参考：["You must use Bundler 2 or greater with this lockfile" に対応する](https://qiita.com/tanakaworld/items/e15ff9dbdd4b628378c2)

### Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2 "No such file or directory")

```
#!/bin/bash -eo pipefail
bundle exec rake db:create

Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2 "No such file or directory")
Couldn't create 'circle_test' database. Please check your configuration.
rake aborted!
Mysql2::Error::ConnectionError: Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2 "No such file or directory")
...
```

#### 解決法
`config/database.ci.yml`を追加する。

```yml:config/database.ci.yml
default: &default
  adapter: mysql2
  encoding: utf8mb4
  charset: utf8mb4
  collation: utf8mb4_general_ci
  pool: 5
  host: 127.0.0.1
  port: 3306
  username: root # .circleci/config.yml のMYSQL_USERと揃える。
  password:

test:
  <<: *default
  database: circle_test # .circleci/config.yml のMYSQL_DBと揃える。
```

### Authentication plugin 'caching_sha2_password' cannot be loaded

```
#!/bin/bash -eo pipefail
bundle exec rails db:create

Authentication plugin 'caching_sha2_password' cannot be loaded: /usr/lib/x86_64-linux-gnu/mariadb18/plugin/caching_sha2_password.so: cannot open shared object file: No such file or directory
Couldn't create 'circle_test' database. Please check your configuration.
rails aborted!
Mysql2::Error: Authentication plugin 'caching_sha2_password' cannot be loaded: /usr/lib/x86_64-linux-gnu/mariadb18/plugin/caching_sha2_password.so: cannot open shared object file: No such file or directory
```

#### 解決法

```yml:.circleci/config.yml
      - image: circleci/mysql:8.0.19-ram
        command: [--default-authentication-plugin=mysql_native_password] # この行を追加
        environment:
          MYSQL_USER: root
          MYSQL_DB: circle_test
```

参考：[CircleCI MySQL8.0 認証方式の変更](https://qiita.com/M_S_0525/items/5c2a4f4bfa70e00b4341)

ちなみに、これを変更したcommitでは動かなかったのですが、その後runを独立させてcommitすると動きました。
時差があったからなのか、runを独立させたからなのか、多分前者だと思います。

### LoadError: cannot load such file -- rspec_junit_formatter

```
#!/bin/bash -eo pipefail
bundle exec rspec --profile 10 \
                  --format RspecJunitFormatter \
                  --out test_results/rspec.xml \
                  --format progress \
                  $(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)
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
...
```

#### 解決法

Gem`'rspec_junit_formatter'`を追加する。

```:Gemfile
group :test do
  gem 'rspec_junit_formatter'  # 追加
end
```

参考：[CircleCI 2.0 移行時に直面した問題とその解決方法 for Rails Project](https://qiita.com/tetsuya/items/83e18713928d0b4bcc41)


## CircleCI内でスペックが落ちる

ローカルでは通るが、CircleCIでは落ちる。

```
"tweetedAt"=>"2020-06-01T00:00:00.000+09:00"
```
↑こうなってほしいのに、↓こうなっている。

```
"tweetedAt"=>"2020-06-01T09:00:00.000+09:00"
```

### 原因と解決法

タイムゾーンが日本時間になっていないので、Dockerのタイムゾーンを指定する。

```.circleci/config.yml
jobs:
  build:
    docker:
      - image: circleci/ruby:2.5.3-node-browsers-legacy
        environment:
          DB_HOST: 127.0.0.1
          RAILS_ENV: test
          BUNDLER_VERSION: 2.1.4
          TZ: "Japan" # 追加する
```

## 最終的な設定

```yml:.circleci/config.yml
version: 2.1
orbs:
  ruby: circleci/ruby@0.1.2

jobs:
  build:
    working_directory: ~/circleci-demo-ruby-rails
    docker:
      - image: circleci/ruby:2.5.3-node-browsers-legacy
        environment:
          DB_HOST: 127.0.0.1
          RAILS_ENV: test
          BUNDLER_VERSION: 2.1.4
          TZ: "Japan"
      - image: circleci/mysql:8.0.19-ram
        command: [--default-authentication-plugin=mysql_native_password]
        environment:
          MYSQL_USER: root
          MYSQL_DB: circle_test

    steps:
      - checkout

      - run:
          name: wait for database
          command: dockerize -wait tcp://127.0.0.1:3306 -timeout 3m

      # Restore bundle cache
      - restore_cache:
          keys:
            - rails-demo-{{ checksum "Gemfile.lock" }}
            - rails-demo-

      - run:
          name: setup bundler
          command: |
            sudo gem update --system
            sudo gem uninstall bundler
            sudo rm /usr/local/bin/bundle
            sudo gem install bundler

      - run:
          name: Which bundler?
          command: bundle -v

      - run:
          name: bundle install
          command: |
            bundle install --jobs=4 --retry=3 --path vendor/bundle

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

      - run:
          name: setup database
          command: |
            cp -v config/database.ci.yml config/database.yml
      
      - run: mysql_config --socket
      - run: bundle exec rails db:create
      - run: bundle exec rails db:schema:load

      - run:
          name: run rspec
          command: |
            bundle exec rspec --profile 10 \
                              --format RspecJunitFormatter \
                              --out test_results/rspec.xml \
                              --format progress \
                              $(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)

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