CI初心者がCircleCIでRubocopとRSpecの設定をするために急いで学んだこと

## この記事の内容
急に職場でCIツールを扱うことになりました。CIツールはほとんど触ったことがなく...CIツールの設定に必要だったことをまとめました。
なお、扱っているプロジェクトはRailsのプロジェクトですので、設定は基本的にRailsの内容になります。

## 書いたコード
書いたコードを設定ごとに紹介していきます。全体のコードは最後に紹介します。なお全てのコードは`.circleci/config.yml`に記載しています。

また、私のようにYAMLの基本文法からよくわからない！という人のために、CircleCIのために勉強したYAMLの基礎文法を下記にまとめました。

- [【初心者向け】CIツール構築に必要なYAMLの読み方](https://qiita.com/tanutanu/items/7e8ba32e89186e3eb4df)

### versions

CircleCIのバージョンです。後述する**`executor`**を使うために、今回は2.1にしています。

```YAML
version: 2.1
```
- 参考：[CircleCI 2.1のすゝめ](https://qiita.com/yumikokh/items/3c1c6576db55d7db947d)


### 基本文法(jobs ~ steps)
CircleCIの基本文法は下記の通り。

```YAML
jobs:
  job-name: # ジョブの名前が入る。任意の名前でOK
    steps:
      - step1
      - step2
```

- `jobs` ... これ以下に書いた内容が**「ジョブ」**であることを表します。
- `steps` ... ひとつ一つのアクション。これらのアクションを集めると**「ジョブ」**になります。
- ジョブ ... `rspec`や`rubocop`などひとまとまりの処理。

- 参考：[コンセプト](https://circleci.com/docs/ja/2.0/concepts/)

### executors
`executors`では、ジョブのステップを実行する環境を定義します。複数JOB分をまとめて設定できます。設定項目は...

- [docker](https://circleci.com/docs/ja/2.0/configuration-reference/#docker)
- working_directory（実行ディレクトリ）
- environment（環境変数）

などなど。詳細は下記を参照してください。

- 参考：[executors (version: 2.1 が必須)](https://circleci.com/docs/ja/2.0/configuration-reference/#executors-version-21-%E3%81%8C%E5%BF%85%E9%A0%88)

`executor`に関して、実際に書いたコードは下記の通りです。

```YAML
version: 2.1
executors:
  my-executor: # 任意の名前でOK
    docker:
      # 以下略
```

#### Docker
CircleCIの環境構築にはDockerが推奨されているようです。公式サイトの[こちらのページ](https://circleci.com/docs/ja/2.0/circleci-images/#%E8%A8%80%E8%AA%9E%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8)からさまざまなCircleCI用のDockerが利用できます。

- [CircleCI のビルド済み Docker イメージ#言語イメージ](https://circleci.com/docs/ja/2.0/circleci-images/#%E8%A8%80%E8%AA%9E%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8)

今回は`Rails 2.7.3`のプロジェクトだったので、[こちら](https://circleci.com/docs/ja/2.0/circleci-images/#ruby)を参考に以下のように記載しました。railsの場合は、yarnを入れる必要があるので、[node.jsを含むタイプのもの](https://circleci.com/docs/ja/2.0/yarn/)を使用するのがポイントです。

```YAML
docker:
  - image: circleci/ruby:2.7.3-node-browsers
```
また、DBはpostgresを利用していたので、以下のようにも記載しています。

```YAML
  - image: circleci/postgres:13.2
```
PostgresのDockerイメージは、[CircleCIのDockerHub](https://hub.docker.com/search?q=circleci&type=image)から、該当のバージョンを検索して記載します。

なお、[公式サイトの下記の記載](https://circleci.com/docs/ja/2.0/databases/#postgresql-%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9%E3%81%AE%E3%83%86%E3%82%B9%E3%83%88%E4%BE%8B)によると、

- [PostgreSQL データベースのテスト例](https://circleci.com/docs/ja/2.0/databases/#postgresql-%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9%E3%81%AE%E3%83%86%E3%82%B9%E3%83%88%E4%BE%8B)

デフォルトでは環境変数`POSTGRES_USER`に`postgres`が設定されているようでした。
最終的に、`docker`の項で書いたコードは以下の通りです。

```YAML
docker:
  - image: circleci/ruby:2.7.3-node-browsers
    environment:
      BUNDLE_JOBS: 3
          BUNDLE_RETRY: 3
          BUNDLE_PATH: vendor/bundle
          PGHOST: 127.0.0.1
          PGUSER: 任意の名前
          RAILS_ENV: test
      - image: circleci/postgres:13.2
        environment:
          POSTGRES_USER: 任意の名前（上のPGUSERと同じ名前）
          POSTGRES_DB: アプリ名_test
          POSTGRES_PASSWORD: 任意のPW
```

[こちら](https://circleci.com/docs/ja/2.0/language-ruby/?section=examples-and-guides#ruby-on-rails-%E3%81%AE%E3%83%87%E3%83%A2-%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AE%E3%83%93%E3%83%AB%E3%83%89)に書いてあった、Railsプロジェクトの設定コードを参考にしつつ、非推奨となっていたコマンドなどを置き換えています。

- [Ruby on Rails のデモ プロジェクトのビルド](https://circleci.com/docs/ja/2.0/language-ruby/?section=examples-and-guides#ruby-on-rails-%E3%81%AE%E3%83%87%E3%83%A2-%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AE%E3%83%93%E3%83%AB%E3%83%89)
- [データベースの構成例](https://circleci.com/docs/ja/2.0/postgres-config/)

公式ではDBのパソワードについて特に言及がないのですが、比較的最近の変更で[DBにパスワードを設定しないとエラーになる](https://qiita.com/tomopict/items/23cc4332781bb28d2973)ようでしたので、パスワードを設定しています。

- [PostgresのDockerImageに変更があって起動ができなくなった話](https://qiita.com/tomopict/items/23cc4332781bb28d2973)

ベタガキで良いのかは、謎です。。。。

### Steps & 全体像
それぞれのJOBに書いたStepはこちらです。長いので、全体像も合わせて紹介します。基本的には、先に紹介した[こちらの設定](https://circleci.com/docs/ja/2.0/language-ruby/?section=examples-and-guides#ruby-on-rails-%E3%81%AE%E3%83%87%E3%83%A2-%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AE%E3%83%93%E3%83%AB%E3%83%89)をもとに、古くなっていた箇所や、現行の仕様だとエラーになるところを変更しています。

- [Ruby on Rails のデモ プロジェクトのビルド](https://circleci.com/docs/ja/2.0/language-ruby/?section=examples-and-guides#ruby-on-rails-%E3%81%AE%E3%83%87%E3%83%A2-%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AE%E3%83%93%E3%83%AB%E3%83%89)

なお、アプリに固有の設定は除いています。

```YAML
version: 2.1
workflows: # 全体の流れを定義
  your_workflow_name: # ワークフローの名前(任意の名前)
    jobs: # 実行するジョブ(任意の名前)
      - your_job_name

executors: # 各ジョブの初期設定
  working_directory: ~/アプリの名前
  ruby_and_postgres:
    docker:
      - image: circleci/ruby:2.7.3-node-browsers
        environment:
          BUNDLE_JOBS: 3
          BUNDLE_RETRY: 3
          BUNDLE_PATH: vendor/bundle
          PGHOST: 127.0.0.1
          PGUSER: 任意の名前
          RAILS_ENV: test
      - image: circleci/postgres:13.2
        environment:
          POSTGRES_USER: 任意の名前（上のPGUSERと同じ名前）
          POSTGRES_DB: アプリ名_test
          POSTGRES_PASSWORD: 任意のPW

jobs:
  your_job_name:
    executor: ruby_and_postgres
    steps:
      - checkout
      # バンドル キャッシュを復元
      - restore_cache:
          keys:
            - rails-demo-bundle-v2-{{ checksum "Gemfile.lock" }}
            - rails-demo-bundle-v2-
      - run:
          name: バンドル インストール
          command: |
            gem install bundler -v 2.2.15
            bundle install
      # バンドル キャッシュを保存
      - save_cache:
          key: rails-demo-bundle-v2-{{ checksum "Gemfile.lock" }}
          paths:
            - vendor/bundle
      # Yarn の設定
      - restore_cache:
          keys:
            - rails-demo-yarn-{{ checksum "yarn.lock" }}
            - rails-demo-yarn-
      - run:
          name: Yarn のインストール
          command: yarn install --cache-folder ~/.cache/yarn
      # Yarn のキャッシュを保存
      - save_cache:
          key: rails-demo-yarn-{{ checksum "yarn.lock" }}
          paths:
            - ~/.cache/yarn
      # Rubocopの実行
      - run:
          name: Run Lint
          when: always
          command: bundle exec rubocop
      # DB関連の設定
      - run:
          name: DB起動待機
          command: dockerize -wait tcp://localhost:5432 -timeout 1m
      - run:
          name: Create DB
          command: |
            bin/rails db:migrate
            bin/rails db:schema:load --trace
      # テストの実行
      - run:
          name: Run Tests
          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)
      - store_test_results:
          path: /tmp/test-results

```
## その他

### Gemのインストール
Stepsの最後にある`store_test_results`（テストの結果を保存する）を利用するために、[rspec_junit_formatter](https://github.com/sj26/rspec_junit_formatter)をインストールしました。

```ruby:Gemgile
group :test do
  gem 'rspec_junit_formatter'
end
```
### Orbs
使ってみたかった便利な機能...。CircleCIの`2.1`から追加された`Orbs`という機能によって、主な設定ファイルがひとまとめにできるようになたようです。

- 参考：[CircleCI 2.1のすゝめ](https://qiita.com/yumikokh/items/3c1c6576db55d7db947d)

利用可能なOrbsは[こちらのページ](https://circleci.com/developer/orbs)に一覧になっていて、

- 参考：[Orbs（開発者サイト）](https://circleci.com/developer/orbs)

例えば「Rails」で検索すると、

[![Image from Gyazo](https://i.gyazo.com/52f6eaf0f28905e5af4efe7bfa42c819.png)](https://gyazo.com/52f6eaf0f28905e5af4efe7bfa42c819)

Railsの有名企業様達のOrbsが利用できるのでした。。。利用方法も詳しく載っていました。ありがたし。。。

```YAML
orbs:
  rails: medpeer/rails@1.2.0
```
今回は私の実力不足で利用に至らなかったのですが、次回は試してみたいです！


## 終わりに
色々苦労しましたが、勉強になりました。楽しかったので、機会があればもう少し深めてみたいです。
なお、本文中で書いた参考サイト以外にも、こちらの記事に大変お世話になりました！

- [いまさらだけどCircleCIに入門したので分かりやすくまとめてみた](https://qiita.com/gold-kou/items/4c7e62434af455e977c2)

細かなコマンドなどはこちらの記事で確認しながら進めさせていただきました。ありがとうございました。