RailsアプリにCircleCI2.1でCI/CDを導入する設定ファイル【初心者向け】

こんにちは、[ペーパーエンジニアのよしこ](https://twitter.com/K2_Yoshiko)です。

自作RailsアプリにCircleCIを使ってCI/CDを導入してから数週間が経過して、導入当初と比較して動作が安定しました。

私の場合、[CircleCI公式ドキュメント](https://circleci.com/docs/ja/2.0/)を基本として自分の環境を構築しましたが、
当時はCircleCI version: 2.1の新機能※ に対応した他環境の設定ファイルを参考にしたいと思ってました。

> ※ CicleCI vertsion: 2.1の新機能
> orbs / commands / executors

> 機能の説明は次の連載記事が分かりやすかったです。
> [「エンジニアのためのCI/CD再入門」連載一覧](https://codezine.jp/article/corner/754)


そこで今回、CI/CDを導入したい初心者エンジニア向けに、CircleCI2.1に対応した設定ファイルを公開したいと思います。



# 環境

```
Ruby  2.6.3
Rails  5.1.6
PostgreSQL  12.2
CircleCI  2.1
デプロイ先はHeroku
```

# CI/CDの全体像

`$ git push origin HEAD`でCircleCI作動
>1. bundle（依存関係）のインストール・リストア
2. 静的コード解析 RuboCop
2. テスト実行 RSpec
3. Herokuにデプロイ（masterブランチのみ）


# 設定ファイル（コメントなし）

`./.circleci/config.yml`に記述。
次項にコメント（個人メモ）ありver.

``` config.yml
version: 2.1
orbs:
  ruby-orbs: sue445/ruby-orbs@1.6.0
  heroku: circleci/heroku@1.0.1
workflows:
  build_test_and_deploy:
    jobs:
      - build
      - rubocop_job:
          requires: 
            - build
      - rspec_job:
          requires: 
            - build
      - deploy:
          requires:
            - rubocop_job
            - rspec_job
          filters:
            branches:
              only:
                - master
executors:
  default:
    working_directory: ~/repository
    docker:
      - image: circleci/ruby:2.6.3-stretch-node
        environment:
          BUNDLE_PATH: vendor/bundle
          RAILS_ENV: test
  extended:
    working_directory: ~/repository
    docker:
      - image: circleci/ruby:2.6.3-stretch-node
        environment:
          BUNDLE_PATH: vendor/bundle
          PGHOST: 127.0.0.1
          PGUSER: postgres
          RAILS_ENV: test
      - image: circleci/postgres:12-alpine
        environment:
          POSTGRES_USER: postgres
          POSTGRES_DB: app_name_test
jobs:
  build:
    executor: default
    steps:
      - checkout
      - bundle-install
  rubocop_job:
    executor: default
    steps:
      - preparate
      - run:
          name: 静的コード解析を実行（RuboCop）
          command: bundle exec rubocop
  rspec_job:
    executor: extended
    steps:
      - preparate
      - run:
          name: DBの起動まで待機
          command: dockerize -wait tcp://localhost:5432 -timeout 1m
      - run:
          name: DBをセットアップ
          command: bin/rails db:schema:load --trace
      - 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 --profile 10 \
                              --format RspecJunitFormatter \
                              --out test_results/rspec.xml \
                              --format progress \
                              $TEST_FILES
      - store_test_results:
          path: /tmp/test-results
      - store_artifacts:
          path: /tmp/test-results
          destination: test-results
  deploy:
    executor: heroku/default
    steps:
      - checkout
      - heroku/install
      - heroku/deploy-via-git
commands:
  bundle-install:
    steps:
      - ruby-orbs/bundle-install:
          bundle_clean: true
          bundle_extra_args: ''
          bundle_gemfile: Gemfile
          bundle_jobs: 4
          bundle_path: vendor/bundle
          bundle_retry: 3
          cache_key_prefix: v1-bundle-dependencies
          restore_bundled_with: true
  preparate:
    steps:
      - checkout
      - bundle-install
```

# 設定ファイル（個人メモあり）

``` config.yml
# CircleCI 2.1 を使用
version: 2.1
# 公開されているCircleCI設定を読み込む。version: 2.1以上
orbs:
  ruby-orbs: sue445/ruby-orbs@1.6.0
  heroku: circleci/heroku@1.0.1

# CI/CD工程の全体像
workflows:
  build_test_and_deploy:
    jobs:
      - build
      - rubocop_job:
          requires: 
            - build
      - rspec_job:
          requires: 
            - build
      - deploy:
          requires:
            - rubocop_job
            - rspec_job
          filters:
            branches:
              only:
                - master

# 実行環境
executors:
  default:
    # コマンドを実行するディレクトリ（Gitリポジトリ名）を指定
    working_directory: ~/repository
    docker:
      - image: circleci/ruby:2.6.3-stretch-node
        environment:
          # デフォルトはBUNDLE_PATH=/usr/local/bundleで設定。上書きが必要
          BUNDLE_PATH: vendor/bundle
          RAILS_ENV: test
  extended:
    working_directory: ~/repository
    docker:
      - image: circleci/ruby:2.6.3-stretch-node
        environment:
          BUNDLE_PATH: vendor/bundle
          PGHOST: 127.0.0.1
          # config/database.ymlの内容と一致させる
          PGUSER: postgres
          RAILS_ENV: test
      # $ psql -V で確認したバージョンと合わせる。-alpineが軽量版のため望ましい
      - image: circleci/postgres:12-alpine
        environment:
          # config/database.ymlの内容と一致させる
          POSTGRES_USER: postgres
          POSTGRES_DB: app_name_test

# 各工程の定義
jobs:
  build:
    executor: default
    steps:
      # ソースコードを作業ディレクトリにチェックアウトする特別なステップ
      - checkout
      # 依存関係とバンドルの処理
      - bundle-install
  rubocop_job:
    executor: default
    steps:
      - preparate
      # 静的コード解析を実行
      - run:
          name: 静的コード解析を実行（RuboCop）
          command: bundle exec rubocop
  rspec_job:
    executor: extended
    steps:
      - preparate
      # DBの起動まで待機
      - run:
          name: DBの起動まで待機
          command: dockerize -wait tcp://localhost:5432 -timeout 1m
      # DBをセットアップ
      - run:
          name: DBをセットアップ
          command: bin/rails db:schema:load --trace
      # テストを実行
      - 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 --profile 10 \
                              --format RspecJunitFormatter \
                              --out test_results/rspec.xml \
                              --format progress \
                              $TEST_FILES
      # テスト結果を保存
      - store_test_results:
          path: /tmp/test-results
      - store_artifacts:
          path: /tmp/test-results
          destination: test-results
  deploy:
    executor: heroku/default
    steps:
      - checkout
      - heroku/install
      - heroku/deploy-via-git

# 処理など。version: 2.1以上
commands:
  # 依存関係の処理（Orbsを利用）
  bundle-install:
    steps:
      - ruby-orbs/bundle-install:
          bundle_clean: true
          bundle_extra_args: ''
          bundle_gemfile: Gemfile
          bundle_jobs: 4
          bundle_path: vendor/bundle
          bundle_retry: 3
          cache_key_prefix: v1-bundle-dependencies
          restore_bundled_with: true
  # 各jobの準備工程
  preparate:
    steps:
      - checkout
      - bundle-install
```


# 参考ドキュメント（日本語）

構築から少なくとも導入初期までは公式ドキュメントがオススメです。

>[言語ガイド：Ruby（Rails）](https://circleci.com/docs/ja/2.0/language-ruby/)
[データベースの設定例](https://circleci.com/docs/ja/2.0/postgres-config/#section=configuration)
[CircleCI を設定する（設定リファレンス）](https://circleci.com/docs/ja/2.0/configuration-reference/#section=configuration)



CircleCIの用語やCI/CDの全体像を把握するのに役に立ったネット記事です。参考程度に。

>[「エンジニアのためのCI/CD再入門」連載一覧](https://codezine.jp/article/corner/754)


Orbsの導入は、CircleCIドキュメントやGitHubなどを参考にするほうがオススメです。

>sue445/ruby-orbs 
[CircleCI](https://circleci.com/orbs/registry/orb/sue445/ruby-orbs)
[GitHub](https://github.com/sue445/circleci-ruby-orbs)

>circleci/heroku
[CircleCI](https://circleci.com/orbs/registry/orb/circleci/heroku)
[GitHub](https://github.com/CircleCI-Public/heroku-orb)

参考までに私の記事もどうぞ。

>[既存RailsアプリにCircleCIを導入した手順](https://qiita.com/K2_Yoshiko/items/3e2a768880cccb8dc273)
[RailsアプリにDockerとCircleCIを導入した際、DB周りでエラーになったときの対処法](https://qiita.com/K2_Yoshiko/items/2b6f11a655218d9a747d)