Programming Journal

学習したことの整理用です。

CircleCIの導入

CircleCI

githubにpushすると同時にCircleCIが起動し、RSpecテストやrubocopのLintチェックを自動で走らせてくれます。
私はズボラでpush前にrubocopやRSpecを実行するのを忘れがちなので、正しいコードをmergeできるようにCircleCIを導入しました。
詰まりに詰まり、1日かかってしまいました。。とりあえず動いてくれてますが、細かい部分は合っているか謎。
公式のサンプル集からコピーして、Qiita等を参考に切り貼りして、ローカルで実行→エラーを潰していくという流れで進めてしまいました。

環境

config.yml

version: 2.1
orbs:
  ruby: circleci/ruby@0.1.2

jobs:
  build:
    docker:
      - image: circleci/ruby:2.7.2-node-browsers-legacy #rubyのversionに合ったコンテナ
        environment:
          - BUNDLER_VERSION: 2.1.4 # これがないとbundle installできない
          - RAILS_ENV: 'test'
          - DB_HOST: 127.0.0.1
      - image: circleci/mysql:5.7
        environment:
          - MYSQL_ALLOW_EMPTY_PASSWORD: 'true'
          - MYSQL_USER: root
          - MYSQL_DB: ci_test # testのDB名指定
    working_directory: ~/repo
    steps:
      # CI環境上の working_directory の値の場所にGitリポジトリをコピーする。
      - checkout

      # dockerコンテナの立ち上げを待つ(これ不要かも…???)
      - run:
          name: wait for database
          command: dockerize -wait tcp://127.0.0.1:3306 -timeout 5m

      # キャッシュがあれば、リストアする。テスト時間の短縮につながる。keysでリストアするキャッシュを複数指定
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "Gemfile.lock" }}
            - v1-dependencies-

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

      # キャッシュする
      - save_cache:
          key: v1-dependencies-{{ checksum "Gemfile.lock" }}
          paths:
            - vendor/bundle

      # DBのセットアップ
      - run:
          name: Database Setup
          command: |
            bundle exec rake db:create
            bundle exec rake db:schema:load

      # rubocopを実行
      - run:
          name: Rubocop
          command: bundle exec rubocop

      # RSpecを実行
      - run:
          name: Run rspec
          command: |
            bundle exec rspec --profile 10 \
                              --format RspecJunitFormatter \ #gem 'rspec-junit-fomatter'が必要
                              --out test_results/rspec.xml \
                              --format progress \
                              $(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)

      # Save artifacts
      - store_test_results:
          path: /tmp/test-results
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: <%= ENV['DATABASE_DEV_PASSWORD'] %>
  host: localhost
  collation: utf8mb4_bin

# 略
test:
  <<: *default
  database: ci_test  # 名前変更(config.ymlに合わせる)
  host: <%=ENV['DB_HOST'] || '127.0.0.1' %> # 追加

CircleCIをローカルで実行する

私は最初の数回、ローカルで実行できるのを知らず、pushして動作確認していました…
ジョブを実行して、エラーを1つづつ潰していけばOK

store_cache, save_cacheは実行されずスキップします。

# CircleCIのインストール
❯ brew install circleci 

# CircleCIの設定ファイルconfig.ymlの文法チェック
❯ circleci config validate .circleci/config.yml

# 文法間違いがあるときの結果
Error: Unable to parse YAML
mapping values are not allowed here
 in 'string', line 12, column 30:
          - image: circleci/mysql: 5.7

# OKなとき
❯ circleci config validate .circleci/config.yml
Config file at .circleci/config.yml is valid.

#ジョブの実行
❯ circleci local execute --job build

遭遇したエラー①

Step failed
====>> Uploading test results
Error: Unable to save test results from /tmp/test-results
Error path is not valid /tmp/test-results: error accessing path: /tmp/test-results: lstat /tmp/test-results: no such file or directory

テストの結果を入れるファイルを用意していなかった。/tmp/test-resultsを作成。

遭遇したエラー②

# --- Caused by: ---
# Mysql2::Error:
#   Unknown database 'ci_test'
#   ./spec/rails_helper.rb:28:in `<top (required)>'

db名を変えたのに、db:createしていなかった。

❯ rails db:create       
Created database 'ci_test'

これでOK

参考にしたもの

CircleCI のローカル CLI の使用 - CircleCI
ローカルで実行
公式サンプルRuby用
公式サンプルRails&Mysql用
bundler設定を参考
.circleci/config.yml内の用語参考
save_cacheとstore_cacheの説明
エラー参考