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


やること

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

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

ソースコード

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

CircleCI

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

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