local で CircleCI を動かす

なぜ local で CircleCI を動かしたいと思ったのか

リモートの CircleCI 上でよく落ちるテストがあるが、ローカルでbundle exec rspecではほぼ再現しないことがあった。
『push デバックは辛いな』『Docker の設定で、低スペック状態にして確認することもできるし』という思いから、local で CircleCI でテストできる環境を整えようということからやってみた

結論、まだローカルではうまく行ってない!
テストの実行自体は問題ないのだがスクリーンショットが.... 😭

各種インストール

Docker

Dockerのサイトにアクセスし、Docker Desktopをダウンロードします。 f:id:ashita-team:20210218145450p:plain 今回は開発環境がMacだったので、Download for mac でダウンロードを行います。Docker.dmg ファイルがダウンロードされる。

ダウンロード完了後、Docker.dmg を開き、Docker を Applicationsフォルダに drag and drop を行う。 f:id:ashita-team:20210218145523p:plain

CircleCI

local で CircleCI を動かすために、CircleCI CLI のインストールを行う。
今回は Homebrew を利用してインストールを行います。

$ brew install circleci 

# Docker インストール済みの場合はこちら
$ brew install --ignore-dependencies circleci

CircleCI用の設定ファイル

CircleCI CLI では、config のバージョンが2.1だとこのJob実行が行えないとのことでした。
このプロダクトでは既に CircleCI を利用しており、config を確認したところバージョンが2.1であったため、バージョンが2の設定ファイルを用意する必要があります。

.circleci/config.yml

version: 2.1
executors:
  default:
    docker:
      - &base_docker
        image: circleci/xxxxxxxxxx
        environment:
          LANG: ja_JP.UTF-8
          LANGUAGE: "ja_JP:ja"
          RAILS_ENV: "test"
          REVIEWDOG_VERSION: "0.10.2"
          RUBYOPT: "-EUTF-8"
          TZ: Asia/Tokyo
     
commands:
  bundle_install_and_cache:
    steps:
      # Download and cache dependencies
      - restore_cache:
          keys:
            - v3-dependencies-{{ checksum "Gemfile.lock" }}
            # fallback to using the latest cache if no exact match is found
            - v3-dependencies-
      - bundle_install
      - save_cache:
          paths:
            - ./vendor/bundle
          key: v3-dependencies-{{ checksum "Gemfile.lock" }}

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

  install_nodejs:
    steps:
      # https://circleci.com/docs/2.0/circleci-images/#best-practices
      - run:
          name: "Update Node.js and npm"
          command: |
            curl -sSL "https://nodejs.org/dist/v12.19.0/node-v12.19.0-linux-x64.tar.xz" \
            | sudo tar --strip-components=2 -xJ -C /usr/local/bin/ node-v12.19.0-linux-x64/bin/node
            curl https://www.npmjs.com/install.sh | sudo bash

  node_version:
    steps:
      - run:
          name: node version
          command: node --version

  yarn_version:
    steps:
      - run:
          name: yarn version
          command: yarn --version

  yarn_install:
    steps:
      - restore_cache:
          keys:
            - v1-yarn-packages-{{ checksum "yarn.lock" }}
            - v1-yarn-packages-
      - run:
          name: yarn install
          command: yarn install --frozen-lockfile --ignore-optional --cache-folder ~/.cache/yarn
      - save_cache:
          paths:
            - ~/.cache/yarn
          key: v1-yarn-packages-{{ checksum "yarn.lock" }}
jobs:
  build:
    executor: default
    working_directory: ~/repo
    steps:
      - checkout
      - bundle_install_and_cache
      - install_nodejs
      - node_version
      - yarn_version
      - yarn_install

      - persist_to_workspace:
          root: ~/repo
          paths:
            - ./vendor/bundle
            - ./node_modules
            - ./public/assets
            - ./tmp/cache/assets
circleci config process .circleci / config.yml > .circleci / process.yml

上記のコマンドで、バージョン2.1の設定ファイルの内容をバージョン2に整形し、process.yml(ファイル名は任意)というファイルに出力させる。

注意 : save_cache/restore_cache/store_artifacts の記述があるが、CircleCi CLI では利用できない。そのため、ローカルで実行時には警告が表示されます。また、workflow にも対応していません。

.circleci/process.yml 
`save_cache` と `restore_cache`の記述に関しては削除済み

version: 2
jobs:
  build:
    docker:
    - image: circleci/xxxxxxxxxx
      environment:
        LANG: ja_JP.UTF-8
        RAILS_ENV: test
        REVIEWDOG_VERSION: 0.10.2
        RUBYOPT: -EUTF-8
        TZ: Asia/Tokyo
    working_directory: ~/repo
    steps:
    - checkout
    - run:
        name: install dependencies
        command: |
          bundle install --clean --jobs=4 --retry=3 --path vendor/bundle
    - run:
        name: Update Node.js and npm
        command: |
          curl -sSL "https://nodejs.org/dist/v12.19.0/node-v12.19.0-linux-x64.tar.xz" \
          | sudo tar --strip-components=2 -xJ -C /usr/local/bin/ node-v12.19.0-linux-x64/bin/node
          curl https://www.npmjs.com/install.sh | sudo bash
    - run:
        name: node version
        command: node --version
    - run:
        name: yarn version
        command: yarn --version
    - run:
        name: yarn install
        command: yarn install --frozen-lockfile --ignore-optional --cache-folder ~/.cache/yarn
    - persist_to_workspace:
        root: ~/repo
        paths:
        - ./vendor/bundle
        - ./node_modules
        - ./public/assets
        - ./tmp/cache/assets
circleci local execute -c .circleci/process.yml

# config にバージョン2で設定しているとき
circleci local execute

上記のコマンドで CircleCI の build をローカルで実行することができます。
build 以外のジョブを実行する際には、--job JOB_NAME のオプションをつけることで実行することができます。

features テストが失敗した時スクリーンショットを撮りたい!

gem 'capybara-screenshot' を入れて、失敗した時に勝手にスクリーンショットをとってくれる様にする。

group :test do
  gem 'capybara-screenshot'
end

テストを実行する時のみgem 'capybara-screenshot'が必要なので、テスト実行時のみパッケージがインストールされるようにする。

capybara-screenshotの設定を追加する。

Capybara::Screenshot.register_filename_prefix_formatter(:rspec) do |example|
  "screenshot_#{example.description.tr(' ', '-').gsub(%r{^.*/spec/}, '')}"
end

GitHub と CircleCI を連携している場合は、font をインストールしていないとお豆腐(□)が大量発生します。
commands に font のインストールについて追加し、そのコマンドをテストを実行しているジョブに追記します。
commands に追記せずそのまま steps に記載でも👍  知らんけど

commands:
  install_font:
    steps:
      - run:
          name: apt-get update
          command: sudo apt-get update
      - run:
          name: Install fonts
          command: |
            sudo apt-get install -y fonts-ipaexfont fonts-noto-cjk &&
            sudo fc-cache -fv
            
job:
  test:
    steps:
       - install_font

ここではfonts-ipaexfont fonts-noto-cjkを入れていますが、お好みのフォントをどうぞ。

これでリモートでは綺麗なスクリーンショットが撮られる様になります。
最後にstore_artifactsをテスト実行後に追加するのを忘れずに

- store_artifacts:
    path: tmp/capybara/

f:id:ashita-team:20210218145643p:plain

CircleCI の ARTIFACTS から失敗した際の画面のスクリーンショットを確認することができる様になります。
スクリーンショットpng)と HTML の両方で失敗原因について確認することができる様になります。

最後に

Dockerの設定でボリュームをマウントしてるが、ローカルにはなかった。
確認したところテストの実行が終了した段階でプロジェクトのファイルがなくなる様になっているみたいです。
そもそもスクリーンショット/home/circleci/repo/tmp/capybara/配下に格納される様になってました。
格納場所をそもそも勘違いしてました。馬鹿ですねぇw

no_output_timeout:で止めている間にコンテナに入って、スクリーンショットが取れていることは確認できた。ただどんなスクリーンショットが撮られているかまでは確認してないけどね!!
docker cp コンテナ:tmp/capybara ローカルパスでローカルにcapybara配下に格納されているスクリーンショットをローカルに
ってところで、この記事の期日が来てしまった...

ローカルでもうまくできたらまた会おう