[Rails6・Heroku]CircleCIの導入手順

### 前提
記事を書いている私は現役のエンジニアではなくエンジニアを目指して学習中の者です。
よって、気をつけてはいますが記述内容には誤った内容が含まれている危険性があります。
その為この記事は参考程度に読んで頂き詳しい内容は公式の記述を参考にすることをおすすめします。

### この記事で実装すること
Rails6系・Herokuにデプロイ済みのアプリにCircleCiを使用して
・mainブランチにpush時にrubocopとrspecの実行
・pull requestをmergeした時に自動デプロイを実行
の2つを実装する手順をまとめます。

### 使用技術
Ruby 3.1.2
Rails 6.1.6
Heroku


### 実装手順
細かい設定などについては以下の公式のチュートリアルにわかりやすく説明があるので参考にしてみてください。
[公式のチュートリアル](https://circleci.com/docs/ja/config-intro)


##### 1, CircleCIのサイトにアクセスしてサインアップを行う
以下の公式サイトからサインアップを行います。
料金プランは無料のものでも月に最大 6,000 分使えるので個人開発レベルではこれで十分だと思います。
[公式サイト](https://circleci.com/ja/)
CircleCiのアカウントとGithubのアカウントを連結させるとアプリのProjectsタブに自分のアプリが表示されるようになります。
[![Image from Gyazo](https://i.gyazo.com/3ae126cc7f321e09f3dcc0380c6a906a.png)](https://gyazo.com/3ae126cc7f321e09f3dcc0380c6a906a)

##### 2, アプリに設定ファイルを追加する
アプリの一番上のディレクトリに **.circleci** というディレクトリを作成して、その中に**config.yml**ファイルを作成します。
[![Image from Gyazo](https://i.gyazo.com/43a792312a9f246d38a170f623050e95.png)](https://gyazo.com/43a792312a9f246d38a170f623050e95)
このファイルの中に実行したい処理を書いていきます。Railsアプリの中で使用するファイルはこれだけなのでシンプルですね！

##### 3, CircleCi上でリポジトリの登録を行う
CircleCiのProjectsタブに対象のリポジトリ名が表示されていると思うので、そのリポジトリの**Set Up Project**を選択します。
リポジトリ内に先ほど作成した設定ファイルがあるとSet Up可能になるのでリポジトリとブランチを確認してからSet Upボタンを押します。
[![Image from Gyazo](https://i.gyazo.com/07574a25e03b70000820bf05581909a1.png)](https://gyazo.com/07574a25e03b70000820bf05581909a1)
これでCircle Ciの実行は可能な状態になりました。あとはconfig.ymlファイルに実行したい処理のコードを書いていきます。

##### 4, config.ymlファイルを編集する
先にコードの完成系を貼ります。ここからは下はコードの役割等の説明になるので必要な部分だけ読んでください。
```yml
version: 2.1
orbs:
  ruby: circleci/ruby@1.1.0
  node: circleci/node@2
  browser-tools: circleci/browser-tools@1.1

jobs:
  build:
    docker:
      - image: cimg/ruby:3.1-browsers
    steps:
      - checkout
      - ruby/install-deps
      - node/install-packages:
          pkg-manager: yarn
          cache-key: "yarn.lock"
  rubocop:
    parallelism: 3
    docker:
      - image: cimg/ruby:3.1-browsers
      - image: circleci/postgres:9.5-alpine
        environment:
          POSTGRES_USER: user_name
          POSTGRES_DB: your_db_name
          POSTGRES_PASSWORD: ""
    steps:
      - checkout
      - ruby/install-deps
      - node/install-packages:
          pkg-manager: yarn
          cache-key: "yarn.lock"
      - run:
          name: run rubocop
          command: bundle exec rubocop
  test:
    parallelism: 3
    docker:
      - image: cimg/ruby:3.1-browsers
      - image: circleci/postgres:9.5-alpine
        environment:
          POSTGRES_USER: user_name
          POSTGRES_DB: your_db_name
          POSTGRES_PASSWORD: ""
    environment:
      BUNDLE_JOBS: "3"
      BUNDLE_RETRY: "3"
      PGHOST: 127.0.0.1
      PGUSER: user_name
      PGPASSWORD: ""
      RAILS_ENV: test
    steps:
      - browser-tools/install-browser-tools
      - checkout
      - ruby/install-deps
      - node/install-packages:
          pkg-manager: yarn
          cache-key: "yarn.lock"
      - run:
          name: rails db:migrate
          command: bundle exec rails db:migrate
      - run:
          name: Database setup
          command: bundle exec rails db:schema:load --trace
      - run:
          name: Rspec
          command: bundle exec rspec
  deploy:
    docker:
      - image: cimg/ruby:3.1-browsers
    steps:
      - checkout
      - run:
          name: 'Install Heroku CLI, if necessary'
          command: |
            if [[ $(command -v heroku) == "" ]]; then
              curl https://cli-assets.heroku.com/install.sh | sh
            else
              echo "Heroku is already installed. No operation was performed."
            fi
      - run:
          name: Deploy to Heroku_Production
          command: |
            git push https://heroku:$HEROKU_API_KEY@git.heroku.com/$HEROKU_APP_NAME_PRD.git main
      - run:
          name: db migration
          command: |
            heroku run rails db:migrate --app ${HEROKU_APP_NAME_PRD}
workflows:
  version: 2
  build_and_rubocop_and_test:
    jobs:
      - build
      - rubocop
      - test:
          requires:
            - build
            - rubocop
  deploy:
    jobs:
      - deploy:
          filters:
              branches:
                  only:
                  - main
```

##### versionとorbsについて
```yml
version: 2.1
orbs:
  ruby: circleci/ruby@1.1.0
  node: circleci/node@2
  browser-tools: circleci/browser-tools@1.1
```
**version：**
circleci自体のバージョンのことです。
**orbs:**
バージョン2.1から使用できるようになった便利ツール的なものらしいです。これを使用すると繰り返しのプロセスを使用できたりサードパーティ製ツールとの連携も簡単になるそうです。
**ruby: circleci/ruby@1.1.0:**
railsのアプリなのでrubyを指定しています。
**node: circleci/node@2:**
railsの6系ではwebpackを使用するのでnodeも使用します。
**browser-tools: circleci/browser-tools@1.1:**
Rspecでcapybaraを使用したブラウザテストを実行するために必要になります。

##### jobsについて
```yml
jobs:
  build:
    docker:
      - image: cimg/ruby:3.1-browsers
```
**jobs:** 
cirlcle CIで行ってほしい挙動をこの中に書くイメージだと思います。
**build:** 
これはjobの名前なので`my-job`とか好きな形で大丈夫です。
**docker:** 
ここでジョブを実行する実行環境を指定しています。
他にもmachineやmacosというものがあるらしいが公式の例がdockerだったので特別な理由がなければ基本的にdockerで良さそうかなと思います。
**image:** 
imageはdocker環境を指定した場合に必須で必要となるオプションで。ここで使用するdockerイメージの名前を指定します。
**cimg/ruby:3.1-browsers:**
CircleCIが作成してくれたDockerイメージでRuby一式とgemコマンド, bundlerなどが含まれています。記事を探しているとここの部分が`circleci/ruby:2.7`のような形になっているものもありますが**circleci/ruby**を新しくしたものが**cimg/ruby**だそうです。
3.1の部分はご自身のアプリで使用しているRubyのバージョンに合わせて変更してください。
**browsersオプション**
node.js、java、selenum、ブラウザーも一緒にインストールしてくれるオプションです。systemスペックでブラウザを使用するので今回はこちらを指定します。
この辺の詳しい説明は公式の以下のページに書かれていたので気になる方はそちらを見てください。
[公式サイトの該当部分](https://circleci.com/developer/ja/images/image/cimg/ruby)

##### stepsについて
```yml
    steps:
      - checkout
      - ruby/install-deps
      - node/install-packages:
          pkg-manager: yarn
          cache-key: "yarn.lock"
```
**checkout:**
アプリのソースコードをジョブのworkin_directoryという場所にチェックアウトしてくレています。
**ruby/install-deps:**
circleci/rubyのおかげでこのコードでRuby関連のものをインストールできるようになっています。
**node/install-packages:
  pkg-manager: yarn
  cache-key: "yarn.lock"**
rubyと同じくnode関連のコードを読み込んでくれています。

##### rubocopについて
```yml
rubocop:
    parallelism: 3
    docker:
      - image: cimg/ruby:3.1-browsers
      - image: circleci/postgres:9.5-alpine
        environment:
          POSTGRES_USER: user_name
          POSTGRES_DB: db_name
          POSTGRES_PASSWORD: ""
    steps:
      - checkout
      - ruby/install-deps
      - node/install-packages:
          pkg-manager: yarn
          cache-key: "yarn.lock"
      - run:
          name: run rubocop
          command: bundle exec rubocop
```
**parallelism:**
jobを並列して実行してくれるので処理の時間が短縮されるらしいです。詳しくは書いてある部分のリンクも貼っておきます。
[公式サイトの該当部分](https://circleci.com/docs/ja/parallelism-faster-jobs)
**run:**
run以下で実際に実行するコマンドを指定します。
**name:**
実行するコマンドの名前を指定します。
**command:**
rubocopのコマンドを実行しています。


##### rspecについて
```yml
test:
    parallelism: 3
    docker:
      - image: cimg/ruby:3.1-browsers
      - image: circleci/postgres:9.5-alpine
        environment:
          POSTGRES_USER: user_name
          POSTGRES_DB: db_name
          POSTGRES_PASSWORD: ""
    environment:
      BUNDLE_JOBS: "3"
      BUNDLE_RETRY: "3"
      PGHOST: 127.0.0.1
      PGUSER: user_name
      PGPASSWORD: ""
      RAILS_ENV: test
    steps:
      - browser-tools/install-browser-tools
      - checkout
      - ruby/install-deps
      - node/install-packages:
          pkg-manager: yarn
          cache-key: "yarn.lock"
      - run:
          name: rails db:migrate
          command: bundle exec rails db:migrate
      - run:
          name: Database setup
          command: bundle exec rails db:schema:load --trace
      - run:
          name: Rspec
          command: bundle exec rspec
```
**environment:**
テストを実行する環境のDB情報を指定してあげています。
**run:**
dbの状態を最新にしてからRspecを実行しています。


##### デプロイについて
```yml
deploy:
    docker:
      - image: cimg/ruby:3.1-browsers
    steps:
      - checkout
      - run:
          name: 'Install Heroku CLI, if necessary'
          command: |
            if [[ $(command -v heroku) == "" ]]; then
              curl https://cli-assets.heroku.com/install.sh | sh
            else
              echo "Heroku is already installed. No operation was performed."
            fi
      - run:
          name: Deploy to Heroku_Production
          command: |
            git push https://heroku:$HEROKU_API_KEY@git.heroku.com/$HEROKU_APP_NAME_PRD.git main
      - run:
          name: db migration
          command: |
            heroku run rails db:migrate --app ${HEROKU_APP_NAME_PRD}
```
**$HEROKU_API_KEY:**
こちらの実装方法に関しては以下の記事にわかりやすくまとめてあったのでそちらを参考にしてみてください。
[herokuへの設定方法](https://qiita.com/gakinchoy7/items/ae31107ef56efb16fe7e?utm_campaign=popular_items&utm_medium=feed&utm_source=popular_items#3heroku%E3%81%AB%E8%87%AA%E5%8B%95%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4)

以上でRailsアプリでCircleCiを使用した自動デプロイ・テスト・Lintチェックが実行できるようになっていると思います！
初学者なので間違った記述等があった場合はコメントで報告頂けると助かります。