DeployGate + Flutter + CircleCIで作るアプリテスト環境

## やること

Flutterアプリをbuildして、手元のAndroid端末で確認します！
ちなみに、全部無料枠です :ok_hand: 

- FlutterアプリをGitHubでコード管理
- コミットのたびにapkを作成
- masterマージでDeployGateにアップロード
- tag作成でDeployGateでapkを保護

## ソースコード

急いで作ったので、変なところもいっぱいですが参考にしてくだいさい :bow: 

- https://github.com/fnaoto/sample-circleci-deploygate-protect

## CircleCI

- 設定はこんな感じです
    - buildのjobではFlutter sdkの入ったdockerコンテナを使っています
    - buildでapkを作成して、persist_to_workspaceで/tmpに保存して、次のjobに渡しています
    - publishのjobでは受け取ったapkをDeployGateにアップロードしています
    - protectのjobではアップロード数の制限を超えたときに自動削除されないようにpinをつけています
 

```yaml:.circleci/config.yml
version: 2.1

# Flutterのキャッシュはここでcommandに切り出し

commands:
  flutter_restore_cache:
    steps:
      - restore_cache:
          keys: flutter-cache-{{ .Branch }}
  flutter_save_cache:
    parameters:
      root_path:
        type: string
        default: "app"
    steps:
      - save_cache:
          key: flutter-cache-{{ .Branch }}
          paths:
            - "<< parameters.root_path >>/android/.gradle"
            - "<< parameters.root_path >>/android/gradle"
            - "<< parameters.root_path >>/build"
            - /opt/android-sdk-linux/

# いい感じのdocker containerがなかったので、この記事を参考にしました
# https://medium.com/flutter-community/setup-ci-cd-pipeline-for-your-flutter-app-using-circleci-ef07e39982ab

jobs:
  build:
    docker:
      - image: cirrusci/flutter
    steps:
      - checkout
      - flutter_restore_cache
# buildしたapkを/tmpにコピー
      - run:
          working_directory: app
          command: |
            flutter -v build apk
            cp build/app/outputs/apk/app.apk /tmp
      - flutter_save_cache
# /tmpのapp.apkを一時的に保存して、次のjobにわたす
      - persist_to_workspace:
          root: /tmp
          paths:
            - app.apk
  publish:
    docker:
# attach_workspaceでca-certificateが必要なので、circleci/nodeを使用 (alpineとかじゃなければOK)
      - image: circleci/node
    steps:
# /tmp/app.apkを受け取り
      - attach_workspace:
          at: /tmp
# apkをDeployGateにアップロード
# messageにはgitのコミットハッシュを入れています
      - run: |
          curl \
            -X POST \
            -F "token=${DG_TOKEN}" \
            -F "file=@/tmp/app.apk" \
            -F "message=${CIRCLE_SHA1}" \
            "https://deploygate.com/api/users/${DG_USER}/apps" | tee /tmp/result.out
# 次のjobにDeployGateへアップロードしたときのレスポンスを渡す
      - persist_to_workspace:
          root: /tmp
          paths:
            - result.out
  protect:
    docker:
      - image: circleci/node
    steps:
# result.outの受け取り
      - attach_workspace:
          at: /tmp
      - run: |
          APP_ID="$(cat /tmp/result.out | jq -r .results.package_name)"
          REVISION="$(cat /tmp/result.out | jq -r .results.revision)"
          curl \
            -X POST \
            -F "token=${DG_TOKEN}" \
            https://deploygate.com/api/users/${DG_USER}/platforms/android/apps/${APP_ID}/binaries/${REVISION}/protect

workflows:
  version: 2
  flutter:
    jobs:
      - build:
          filters:
            tags:
              only: /.*/
      - publish:
          requires:
            - build
          filters:
            branches:
              only: master
            tags:
              only: /.*/
      - protect:
          requires:
            - publish
          filters:
            branches:
              ignore: /.*/
            tags:
              only: /.*/
```

## DeployGate

CircleCIではDeployGateのAPIを叩くために使うトークンなどを環境変数にして使っています

使っている環境変数

- DG_TOKEN
    - APIを叩くためのトークン

<kbd><img width="584" alt="スクリーンショット 2019-12-16 18.30.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259386/faf62dbb-b8ab-c8f0-af8f-c6a2871a05b5.png"></kbd>

<kbd><img width="978" border="10" alt="スクリーンショット 2019-12-16 18.30.52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259386/258074a1-38c6-8f22-1ec1-846d1037dca2.png"></kbd>


- DG_USER
    - DeployGate登録時のユーザ名

<kbd><img width="544" alt="スクリーンショット 2019-12-16 18.41.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259386/4d7bf94f-81ea-3b9d-b4b3-d2c8a53e4d71.png"></kbd>