create-react-appで作成したreactアプリをCircleCI2.0でS3にデプロイする

create-react-appで作成したreactアプリをCircleCI2.0でS3にデプロイしようとしたときにハマったのでメモ。

S3側の設定などは[create-react-appのREADMEのS3のデプロイ](https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md#s3-and-cloudfront) でも言及されている[blog post](https://medium.com/@omgwtfmarc/deploying-create-react-app-to-s3-or-cloudfront-48dae4ce0af) が参考になります。

## ハマった点

ハマった点は２点あります。

### 1. deployのjobとbuildのjobを分けてしまうとbulidのjobで作成した生成物が引き継がれない

上述のblog postには

1. Install the AWS CLI.
2. Create security credentails
3. Configure the CLI with `aws configure`.

とあるので、CircleCIのビルドjobに上記のコマンドを入れましたが、うまくいきませんでした。
そのときのymlは以下のとおりです。

```wrong.yml
# Javascript Node CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-javascript/ for more details
#
version: 2
jobs:
  build:
    docker:
      # specify the version you desire here
      - image: circleci/node:9.11

      # Specify service dependencies here if necessary
      # CircleCI maintains a library of pre-built images
      # documented at https://circleci.com/docs/2.0/circleci-images/
      # - image: circleci/mongo:3.4.4

    working_directory: ~/repo

    steps:
      - checkout

      # Download and cache dependencies
      - restore_cache:
          keys:
          - v1-dependencies-{{ checksum "package.json" }}
          # fallback to using the latest cache if no exact match is found
          - v1-dependencies-

      - run: yarn install

      - save_cache:
          paths:
            - node_modules
          key: v1-dependencies-{{ checksum "package.json" }}

      # run tests!
      - run: yarn test

      # build
      - run: yarn run build

  deploy-master:
    machine:
      enabled: true

    working_directory: ~/repo

    steps:
      - run: ls -alt  # ☆何もない
      - run: aws s3 sync ./build s3://production.example.com --delete

  deploy-staging:
    machine:
      enabled: true

    working_directory: ~/repo

    steps:
      - run: ls -alt  # ☆何もない
      - run: aws s3 sync ./build s3://staging.example.com --delete

workflows:
  version: 2
  build-deploy:
    jobs:
      - build
      - deploy-master:
          requires:
            - build
          filters:
            branches:
              only: master
      - deploy-staging:
          requires:
            - build
          filters:
            branches:
              only: develop
```

build, deploy-master, deploy-stagingの３つのjobを定義して、ワークフローでブランチがmasterだったらdeploy-masterのjobを実行、ブランチがdevelopだったらdeploy-stagingのjobを実行するというにしています。しかしこれだとうまく動作しませんでした。
buildのjobはうまく動作しますが、deploy-masterまたはdeploy-stagingのlsコマンドの結果はファイルなしでした。buildしたパッケージはありませんでした。
jobをまたいでbuildパッケージを利用できない、つまりbuildのjobでbuildしたパッケージを他のjobで利用できないため、別のやり方に変更しなければいけません。

### 2.  CircleCIのnodeのイメージを利用したときawscliのインストールに手間取った

↑のymlでawsコマンドがないとエラーになりました。awscliをインストールする必要があります。
awscliのインストールをしようとしたらpipがないとのエラーが出たのでpython3をインストールしたもののpipのパスが通っていないとのエラーになりました。
そのため` PATH=$PATH:/home/circleci/.local/bin; export PATH` をjobのタスクに追加することで解決しました。
awscliがインストールされてあるカスタムしたDockerイメージを使えばいいのですが、今回はCircleCIのイメージで頑張ってみました。

なお、AWSのクレデンシャルをCircleCIで設定するのを忘れずに。
S3にアップロードできる権限が必要なので、IAMでユーザを作成してアクセスキーIDとシークレットアクセスキーをCircleCIに登録しておきます。

## .circleci/config.yml

最終的なymlは以下になります。

```.circleci/config.yml
# Javascript Node CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-javascript/ for more details
#
version: 2
jobs:
  build:
    docker:
      # specify the version you desire here
      - image: circleci/node:9.11

      # Specify service dependencies here if necessary
      # CircleCI maintains a library of pre-built images
      # documented at https://circleci.com/docs/2.0/circleci-images/
      # - image: circleci/mongo:3.4.4

    working_directory: ~/repo

    steps:
      - checkout

      # Download and cache dependencies
      - restore_cache:
          keys:
          - v1-dependencies-{{ checksum "package.json" }}
          # fallback to using the latest cache if no exact match is found
          - v1-dependencies-

      - run: yarn install

      - save_cache:
          paths:
            - node_modules
          key: v1-dependencies-{{ checksum "package.json" }}

      # run tests!
      - run: yarn test

      # build
      - run: yarn build

      - deploy:
          command: |
            PATH=$PATH:/home/circleci/.local/bin; export PATH
            sudo apt-get -y -qq update
            sudo apt-get -y -qq install python3 python3-dev
            sudo curl -O https://bootstrap.pypa.io/get-pip.py
            python3 get-pip.py --user
            pip install awscli --upgrade --user
            if [ "${CIRCLE_BRANCH}" == "master" ]; then
              aws s3 sync ./build s3://production.example.com --delete
            elif [ "${CIRCLE_BRANCH}" == "develop" ]; then
              aws s3 sync ./build s3://staging.example.com --delete
            fi
```

workflowを定義せず、buildのjobにdeployのタスクを含めました。
そうすることによってyarn buildでbuildしたパッケージを参照することができます。
pushされたブランチに応じてデプロイ先のS3バケットを変更してデプロイしています。

以上、create-react-appで作ったアプリケーションのS3デプロイの参考になれば幸いです。