CircleCIでRubocopとRSpecを走らせてECSにデプロイする

#この記事で扱うこと
- CircleCIでRubocopとRSpecを使用した自動テスト
- CircleCI orbsを使用したCI/CDパイプラインの構築

#扱わないこと
- CircleCIの初期設定
- RubocopやRSpecの導入方法

#config.ymlの完成形
以下の公式ページを参考にしています
[https://circleci.com/docs/ja/2.0/configuration-reference/#requires](o)

```
version: 2.1

orbs:
  aws-ecr: circleci/aws-ecr@6.12.2
  aws-ecs: circleci/aws-ecs@1.3.0

references:
  defaults: &defaults
    working_directory: ~/myqpp

  ruby-docker-image: &ruby-docker-image
    #steps共通のプライマリコンテナ
    image: circleci/ruby:2.6.4-node-browsers
    #プライマリコンテナの環境変数
    environment:
      RAILS_ENV: test
      MYSQL_HOST: 127.0.0.1
      MYSQL_USERNAME: "db_name"
      MYSQL_PASSWORD: ""
      MYSQL_PORT: 3306

  mysql-docker-image: &mysql-docker-image
    image: circleci/mysql:8.0.19
    command: [--default-authentication-plugin=mysql_native_password]
    environment:
      MYSQL_ALLOW_EMPTY_PASSWORD: true
      MYSQL_ROOT_HOST: "%"

jobs:
  checkout_code:
    <<: *defaults
    docker:
      - *ruby-docker-image
      - *mysql-docker-image
    steps:
      - checkout
      - save_cache:
          key: v1-repo-{{ .Environment.CIRCLE_SHA1 }}
          paths:
            - ~/project

  test:
    <<: *defaults
    docker:
      - *ruby-docker-image
      - *mysql-docker-image
    steps:
      #ソースコードをworking dirにチェックアウト
      - checkout
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "Gemfile.lock" }}
            - v1-dependencies-
      #ruby依存関係
      - run: gem install bundler -v 2.1.4
      - run: bundle install --jobs=4 --retry=3 --path vendor/bundle
      - save_cache:
          key: vi-dependencies-{{ checksum "Gemfile.lock" }}
          paths:
            - ./vendor/bundle
      #DBの待機/セットアップ
      - run: mv -f ./config/database.yml.ci ./config/database.yml
      - run: dockerize -wait tcp://127.0.0.1:3306 -timeout 120s
      - run: bundle exec rails db:create db:schema:load --trace
      #Rubocop自動化
      - run:
          name: start RuboCop
          command: bundle exec rubocop
      #RSpec自動化
      - run:
          name: start RSpec
          command: |
            mkdir /tmp/test-reports
            TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | \
              circleci tests split --split-by=timings)"
            bundle exec rspec \
              --format progress \
              --format RspecJunitFormatter \
              --out /tmp/test-results/rspec.xml \
              --format progress \
              $TEST_FILES
      #レポートと結果を保存
      - store_artifacts:
          path: /tmp/test-reports
          destination: tr1
      - store_test_results:
          path: /tmp/test-reports

workflows:
  version: 2.1
  test_code:
    jobs:
      - checkout_code
      - test:
          requires:
            - checkout_code

  # ECRとECSを使用してRailsのデプロイ
  build-and-deploy-rails:
    jobs:
      - aws-ecr/build-and-push-image:
          filters:
            branches:
              only: master
          account-url: AWS_ECR_ACCOUNT_URL
          region: AWS_REGION
          aws-access-key-id: AWS_ACCESS_KEY_ID
          aws-secret-access-key: AWS_SECRET_ACCESS_KEY
          extra-build-args: "--build-arg RAILS_MASTER_KEY=${RAILS_MASTER_KEY}"
          create-repo: true
          dockerfile: ./Dockerfile
          repo: "${AWS_RESOURCE_NAME_PREFIX_WEB}"
          tag: "${CIRCLE_SHA1}"
      - aws-ecs/deploy-service-update:
          requires:
            - aws-ecr/build-and-push-image
          family: "${ECS_TASK}"
          cluster-name: "${ECS_ARN}"
          service-name: "${ECS_SERVICE}"
          container-image-name-updates: "container=${AWS_RESOURCE_NAME_PREFIX_WEB},tag=${CIRCLE_SHA1}"

  #nginxのデプロイ
  build-and-deploy-nginx:
    jobs:
      - aws-ecr/build-and-push-image:
          filters:
            branches:
              only: master
          account-url: AWS_ECR_ACCOUNT_URL
          region: AWS_REGION
          aws-access-key-id: AWS_ACCESS_KEY_ID
          aws-secret-access-key: AWS_SECRET_ACCESS_KEY
          create-repo: true
          dockerfile: ./nginx/Dockerfile
          repo: "${AWS_RESOURCE_NAME_PREFIX_NGINX}"
          tag: "${CIRCLE_SHA1}"
      - aws-ecs/deploy-service-update:
          requires:
            - aws-ecr/build-and-push-image
          family: "${ECS_TASK}"
          cluster-name: "${ECS_ARN}"
          service-name: "${ECS_SERVICE}"
          container-image-name-updates: "container=${AWS_RESOURCE_NAME_PREFIX_NGINX},tag=${CIRCLE_SHA1}"

```
jobsで２つの実行処理を設定して、workflowで２つのjobの並列実行を定義しています。

#自動テスト
##RSpecを実行する
以下の公式リファレンスが有用です。
[https://circleci.com/docs/ja/2.0/language-ruby/](o)

このとき注意する必要があるのは、MySQL8以上を使用している方です。
8.0以降で認証方法が変わったようなので以下を追加することで対応します。

```
image: circleci/mysql:8.0.19
    command: [--default-authentication-plugin=mysql_native_password] #追加
```


#orbsを使用したビルド＆デプロイ
以下の公式リファレンスを読めばECSにデプロイできます
[https://circleci.com/docs/ja/2.0/ecs-ecr/](o)

ここで気をつけることはCircleCIで設定した環境変数をしっかり対応させることです。
環境変数さえ正しく設定できていればCI/CDパイプラインの構築ができます。

#config.ymlをリファクタリングする
繰り返し使用している箇所に関しては、可読性を高めるためにリファクタリングしています。

```&(アンカー)``` で定義
```*(エイリアス)``` で定義したものを実行


#おまけ
以下の公式からCircleCI CLIをインストール。
[https://circleci.com/docs/ja/2.0/local-cli/](o)

```
(Mac/Linuxの場合)
curl -fLSs https://circle.ci/cli | bash
```
このCircleCI CLIで設定ファイルが有効かチェックすることができます。

```
$ circleci config validate
```

#記事を読んでいただきありがとうございました
CircleCIは日本語のドキュメントもあり設定ファイルの書き方、
さらにはRSpec等のテスト実行の設定に関してもしっかり記載があります。

日本語ドキュメントが用意されているありがたみを感じながらこの記事も書きました。

#参考
[https://discuss.circleci.com/t/solved-mysql-8-0-without-mysql2-authentication-plugin-caching-sha2-password-cannot-be-loaded/25791](o)

[https://patorash.hatenablog.com/entry/2018/06/24/122210](o)

[https://circleci.com/docs/ja/2.0/configuration-reference/#requires](o)

[https://circleci.com/docs/ja/2.0/workflows/](o)