DeployGateでのAPK配布設定をCircleCI Orbsとして公開する

ZOZOテクノロジーズでAndroidエンジニアとして働いている@Horie1024です。最近[Androidテスト全書](https://peaks.cc/Horie1024/android_testing)という本を執筆しました。

弊社では、開発中のAndroidアプリを社内へ配布する方法として[DeployGate](https://deploygate.com)を使用しています。今回、CircleCI上でDeployGateによってAPKを配布する`.circleci/config.yml`の設定をCircleCI Orbsとして切り出して公開してみました。

公開したOrbはこちらです。
https://circleci.com/orbs/registry/orb/horie1024/deploygate

# Orbとは？

`.circleci/config.yml`での設定内容をパッケージとしてまとめ、再利用可能な形で公開できる機能です。CircleCI 2.1 configuration(2018/12/7時点でプレビュー)で追加されました。Orbとして公開されている設定を組み合わせることで目的のWorkflowをより素早く構築することが可能になります。

# DeployGateでのAPK配布方法

DeployGateでAPKを配布する方法は2種類あります。

- [DeployGate Gradle Plugin](https://github.com/DeployGate/gradle-deploygate-plugin)を使用する方法
- [DeplpyGate API](https://docs.deploygate.com/reference#deploygate-api)を使用する方法

今回はDeplpyGate APIを使用する方法をOrbとしてまとめます。

# どうOrbにするか？

次のコマンドをstepで実行することでAPKの配布を行えます。

```bash
curl \
  -F "token=xxx" \
  -F "file=@sample.apk" \
  -F "message=sample" \
  https://deploygate.com/api/users/_your_name_/apps
```

token、apkのパス、メッセージ、ユーザ名を個別に指定できるようにして次のように実行できると良さそうです。

```yaml

jobs:
  build:
    docker:
      - image: circleci/android:api-28-alpha
    steps:
      - deploygate/distribute:
          token: DEPLOY_GATE_TOKEN
          user_name: DEPLOY_GATE_USER
          apk_path: sample.apk
          message: sample
```

このインターフェースを実現できるようOrbを作成します。

# Orbの作成と公開

## CircleCI CLIのインストール

まずCircleCI CLIをインストールします。[Installing the CLI for the First Time](https://circleci.com/docs/2.0/creating-orbs/#installing-the-cli-for-the-first-time)に従いインストールします。今回はHomebrewでインストールしました。

```bash
$ brew install circleci
```

## Namespaceの作成

次にNamespaceを作成します。Namespaceの作成にはCircleCI CLIを使用し、コマンドの構文は次の通りです。

`circleci namespace create <name> <vcs-type> <org-name> [flags]`

そして、次のようにコマンドを実行するとNamespaceが作成されます。

```bash
$ circleci namespace create horie1024 github horie1024
Namespace `horie1024` created.　Please note that any orbs you publish in this namespace are open orbs and are world-readable.
```

org-nameはGitHubではなく、CircleCIのOrganization名です。

#### Error: Your organization must enable the 'Uncertified Orbs'…と表示されたら

デフォルトではCircleCIに認証されたOrbのみ使用可能になっているため、自作したOrbや認証されていない3rdパーティのOrbを使用したい場合設定を変更する必要があります。
Settings->Securityで`Orb Security Settings`を`Yes`に変更してください。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/43438/db9d1b96-4893-14fe-438b-a3e6542c0878.png)

## Orbの作成

実際にOrbを作成していきます。package構成はシンプルで、srcディレクトリ以下にOrbで公開する設定を記述する`orb.yml`を配置します。

```bash
deploygate
└── src
    └── orb.yml
```

### NamespaceにOrbを作成

`circleci orb create`コマンドを使用し、Namespace内にOrbを作成します。`namespace/orb`となるように指定します。

```bash
$ circleci orb create horie1024/deploygate
Orb `horie1024/deploygate` created.
Please note that any versions you publish of this orb are world-readable.
You can now register versions of `horie1024/deploygate` using `circleci orb publish`.
```

### Orb本体の作成

`src/orb.yml`に次の設定を追加します。

```yaml
version: 2.1

description: Distribute APK with DeployGate

commands:
  distribute:
    description: Execution of distribution
    parameters: 
      token:
        description: token
        type: env_var_name
      user_name:
        description: user name
        type: env_var_name
      apk_path:
        description: apk path
        type: string
      message:
        description: message
        type: string
        default: ""
    steps:
      - run:
          name: Distribution of APK by DeployGate API
          command: |
            curl \
              -F "token=${<<parameters.token>>}" \
              -F "file=@<<parameters.apk_path>>" \
              -F "message=<<parameters.message>>" \
              https://deploygate.com/api/users/${<<parameters.user_name>>}/apps
```

#### パラメータの受け取り

`parameters`というセクションを定義することでOrbのimport側から任意の値を渡すことができます。default値の定義を省略すると必須パラメータとなります。

各パラメータが必須であるか、どのような型を取るかは以下の表の通りです。環境変数を型として指定できるのが面白いですね。`parameter`のシンタックスや指定できる型の種類は[こちら](https://circleci.com/docs/2.0/reusing-config/#parameter-syntax)から確認できます。

|パラメータ|必須|型|
|:-:|:-:|:-:|
|token|◯|環境変数|
|user_name|◯|環境変数|
|apk_path|◯|文字列|
|message||文字列|

パラメータは`<<parameters.token>>`のように記述することで`step`内で展開可能です。

#### orb.ymlのバリデーション

`circleci orb validate`コマンドを使用することで、orb.ymlに対してバリデーションをかけることができます。

```bash
$ circleci orb validate src/orb.yml
Orb at `src/orb.yml` is valid.
```

orb.ymlを編集し`circleci orb validate`を実行するという流れで作成を進めました。


## Orbの公開

Orbの公開は`circleci orb publish`コマンドを使用します。コマンドの構文は次の通りです。

`circleci orb publish <path> <namespace>/<orb>@<version>`

### 開発版の公開

versionに`dev`を指定すると開発版として公開できます。90日間更新が無い場合自動的に削除されます。

```bash
$ circleci orb publish src/orb.yml horie1024/deploygate@dev:first
Orb `horie1024/deploygate@dev:first` was published.Please note that this is an open orb and is world-readable.
Note that your dev label `dev:first` can be overwritten by anyone in your organization.Your dev orb will expire in 90 days unless a new version is published on the label `dev:first`.
```

### 公開版へのプロモート

`circleci orb publish promote`コマンドを使用することで、開発版を公開版へ昇格させることが可能です。コマンドの構文は次のようになっており、`<segment>`で`major`、`minor`、`patch`のどのバージョンをインクリメントするかを指定できます。

`circleci orb publish promote <namespace>/<orb>@<version> <segment>`

Orbのバージョニングの詳細は[こちら](https://circleci.com/docs/2.0/creating-orbs/#semantic-versioning-in-orbs)をご覧ください。

今回は`patch`を指定します。

```bash
$ circleci orb publish promote horie1024/deploygate@dev:first patch
Orb `horie1024/deploygate@dev:first` was promoted to `horie1024/deploygate@0.0.1`.
Please note that this is an open orb and is world-readable.
```

公開が完了しました。

### 公開したOrbの確認

`circleci orb info`コマンドで確認できます。

```bash
$ circleci orb info horie1024/deploygate@0.0.1

Latest: horie1024/deploygate@0.0.1
Last-updated: 2018-12-07T09:05:33.288Z
Created: 2018-12-07T08:29:34.153Z
First-release: 0.0.1 @ 2018-12-07T09:05:33.288Z
Total-revisions: 1

Total-commands: 1
Total-executors: 0
Total-jobs: 0
```

また、`circleci orb source`コマンドを使用するこでOrbの内容を確認可能です。

```bash
$ circleci orb source horie1024/deploygate@0.0.1
version: 2.1

description: Distribute APK with DeployGate

commands:
  distribute:
    description: Execution of distribution
    parameters:
      token:
        description: token
        type: env_var_name
      user_name:
        description: user name
        type: env_var_name
      apk_path:
        description: apk path
        type: string
      message:
        description: message
        type: string
        default: ""
    steps:
      - run:
          name: Distribution of APK by DeployGate API
          command: |
            curl \
              -F "token=${<<parameters.token>>}" \
              -F "file=@<<parameters.apk_path>>" \
              -F "message=<<parameters.message>>" \
              https://deploygate.com/api/users/${<<parameters.user_name>>}/apps
```

# Androidプロジェクトで公開したOrbを使用する

公開したOrbを実際に使用してみます。サンプルとなるAndroidプロジェクトを作成しました。

https://github.com/horie1024/orb_deploygate_android_sample

## Enable build processingを有効化

CircleCI 2.1 configurationは2018/12/7時点でプレビューであるので、プロジェクトのSettings->Advanced Settingsで`Enable build processing`を`On`にする必要があります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/43438/0c8bb2ca-7cae-647c-55f6-6bb80bd666f9.png)

##.circleci/config.ymlの追加

サンプルプロジェクトで次の設定を`.circleci/config.yml`に追加します。

①で先ほど公開したOrbをimportし②で実行しています。

```yaml
version: 2.1

orbs:
    deploygate: horie1024/deploygate@0.0.1 # ①

jobs:
  build:
    docker:
      - image: circleci/android:api-28-alpha
    steps:
      - checkout
      - run:
          name: Download Dependencies
          command: ./gradlew androidDependencies
      - run:
          name: Execute assembleDebug
          command: ./gradlew assembleDebug
      - deploygate/distribute: # ②
          token: DEPLOY_GATE_TOKEN
          user_name: DEPLOY_GATE_USER
          apk_path: app/build/outputs/apk/debug/app-debug.apk
          message: Hello World!
```

## config.ymlの確認

`circleci config process`コマンドでconfig.ymlをCircleCI上で実行される形に変換すると次のようになります。Orbで公開した設定内容が展開されているのがわかります。

```bash
$ circleci config process .circleci/config.yml
# Orb 'horie1024/deploygate@0.0.1' resolved to 'horie1024/deploygate@0.0.1'
version: 2
jobs:
  build:
    docker:
    - image: circleci/android:api-28-alpha
    steps:
    - checkout
    - run:
        name: Download Dependencies
        command: ./gradlew androidDependencies
    - run:
        name: Execute assembleDebug
        command: ./gradlew assembleDebug
    - run:
        name: Distribution of APK by DeployGate API
        command: |
          curl \
            -F "token=${DEPLOY_GATE_TOKEN}" \
            -F "file=@app/build/outputs/apk/debug/app-debug.apk" \
            -F "message=Hello World!" \
            https://deploygate.com/api/users/${DEPLOY_GATE_USER}/apps
workflows:
  version: 2
  workflow:
    jobs:
    - build

# Original config.yml file:
# version: 2.1
#
# orbs:
#     deploygate: horie1024/deploygate@0.0.1
#
# jobs:
#   build:
#     docker:
#       - image: circleci/android:api-28-alpha
#     steps:
#       - checkout
#       - run:
#           name: Download Dependencies
#           command: ./gradlew androidDependencies
#       - run:
#           name: Execute assembleDebug
#           command: ./gradlew assembleDebug
#       - deploygate/distribute:
#           token: DEPLOY_GATE_TOKEN
#           user_name: DEPLOY_GATE_USER
#           apk_path: app/build/outputs/apk/debug/app-debug.apk
#           message: Hello World!%
```

## CircleCIでの実行

`DEPLOY_GATE_TOKEN`、`DEPLOY_GATE_USER`をプロジェクトの環境変数へ登録します。通常通りAdd Projectからサンプルプロジェクトを追加しビルドを実行します。ビルドは無事成功し、次のようにアプリを配信することができました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/43438/a97e625a-434d-043d-4488-b656d2f3319b.png)

# まとめ

DeployGateでAPK配布を配布するOrbを作成して公開してみました。Orb自体もCircleCIを利用してテストしたりデプロイを自動化することをできるようなので試そうと思います。

今回作成したOrbは次のリポジトリで公開しています。

https://github.com/horie1024/orb_deploygate

# 参考資料

- https://circleci.com/docs/2.0/reusing-config/#section=configuration
- https://circleci.com/docs/2.0/creating-orbs/#section=configuration
- https://www.kaizenprogrammer.com/entry/2018/12/01/111145