AndroidアプリのQA実施に必要な作業を自動化する

> この記事は[VASILY DEVELOPERS BLOG](http://tech.vasily.jp/entry/android_qa_automation)にも同じ内容で投稿しています。よろしければ他の記事もご覧ください。

こんにちは、Androidエンジニアの堀江([@Horie1024](https://twitter.com/horie1024))です。VASILY DEVELOPERS BLOGは新年2回目の更新になります。ちなみに去年の更新回数は53回だったようです。

また、Androidチームのトピックスとしては、先日[ベストイノベーティブアプリ大賞](https://japan.googleblog.com/2016/12/google-play-2016-2016.html)を受賞した際にいただいたトロフィーがオフィスに届きました。今年も賞をいただけるようVASILY全員で頑張ります。

[Google Playtime「ベストイノベーティブアプリ」大賞のトロフィーが届きました！](http://company.vasily.jp/170117_playtime)


# はじめに

Android版iQONのリリースは約1~2週間に1回行っており、リリース前には社内QAを実施しています。QAを実施するために必要な作業は定型な作業ですが、手動で行うと思いの外時間が掛かりますし、作業の抜け漏れが起きる事もあります。

そこで、タイトルにもあるようにQAの実施に必要な作業を自動化しました。一度自動化してしまえば作業に抜け漏れがなくなり、自分たちの時間も節約できます。

今回は具体的にどのように自動化したのかご紹介しようと思います。

# 自動化の方法

VASILYでは、以前から[Heroku](https://www.heroku.com/)上にホストした[Hubot](https://github.com/github/hubot)を[Slack](https://slack.com/)と連携させ利用しています。したがって、今回もSlackとHubotを使い自動化を行っていきます。Slackから特定の文字列を入力するとHubotが反応し、QA実施に必要な作業を自動的に実行するようにします。

この記事ではHerokuやHubotの設定は紹介しませんが、Web上に良い記事が多くありますので参考にしてみてください。

![techblog_2017_01_19_2.png](https://qiita-image-store.s3.amazonaws.com/0/43438/c7fde9ac-189b-eb6d-5b95-052b02b94e77.png "techblog_2017_01_19_2.png")


# QA終了までの流れの整理

まず、今までのQA開始からQA終了までの流れを整理し書き出しました。QAは毎回以下のような流れで開始され終了します。

1. QAの開始・終了日時をSlackで全員に通知
2. GoogleスプレッドシートでQAシートを作成
3. Qiitaチームにリリースノートを作成
4. APKを作成しBetaで社内に配布
5. SlackでQA依頼
6. QA終了日時を過ぎたらSlackにQA終了報告とお礼を投稿

次にこれらをどこまで自動化するのかを考えます。

# 自動化する範囲

どこまで自動化するかを考え易くするために先程整理したQAの流れを**QA予告**、**QA準備**、**QA開始**、**QA終了**の4つのフェーズに分類してみました。

![techblog_2017_01_19.png](https://qiita-image-store.s3.amazonaws.com/0/43438/3c036ec6-b382-a232-23af-53af49dd15f5.png "techblog_2017_01_19.png")

分類する中で気づいたのは、QA準備以外のフェーズは全てSlackへの投稿という点です。これらのQA実施に関する連絡は、柔軟に対応できるようにした方が使い勝手が良さそうに思えます。

例えば、QAをお願いする時に一言添えたいかもしれませんし、QAの終了日時が伸びるかもしれません。また、QAでたくさんのフィードバックをもらえてお礼の文言を変えたい場合もあるかもしれません。

したがって、**QA準備**フェーズの自動化にフォーカスします。

# コマンドの設計

SlackからHubotを使い自動化するには、Hubotに反応させるコマンドを決める必要があります。シンプルに`android qa`としてみました。

Slackで`android qa`と入力するとHubotが反応し以下の作業を実行するようにします。

1. GoogleスプレッドシートでQAシートを作成
2. Qiitaチームにリリースノートを作成
3. APKを作成しBetaで社内に配布

# どう自動化するか？

QAシート、リリースノートの作成、APK配布を自動化するにはどうすれば良いでしょうか。各作業について考えていきます。

## 1. GoogleスプレッドシートでQAシートを作成

QAシートは以下のフォーマットを利用しています。

![techblog_2017_01_19_4.png](https://qiita-image-store.s3.amazonaws.com/0/43438/5d6b6fc0-49c8-dceb-cce8-e7c1cfb4c604.png "techblog_2017_01_19_4.png")

[Sheets API](https://developers.google.com/sheets/)を使うことでフォーマット通りのスプレッドシートを作れますが、コードが複雑になるため予め用意したスプレッドシートをマスターにし、それを[Drive API](https://developers.google.com/drive/)でコピーしてQAシートを作ります。

**追記**

マスタースプレッドシートの共有にサービスアカウントを追加する必要があります。


## 2. Qiitaチームにリリースノートを作成

Qiitaチームへのリリースノートの作成には[Qiita API v2](https://qiita.com/api/v2/docs)を使用し、[POST /api/v2/items](https://qiita.com/api/v2/docs#post-apiv2items)を使うことで投稿することができます。リリースノートのフォーマットは以下の通りで、記事のタイトルには「Android バージョン番号 リリースノート」、タグには「リリースノート」、「Android」を付けます。

```
# リリース日

# QA
* 期限
* QAシート

# 更新内容
```

タイトルのバージョン番号やリリース日、QAの期限はSlackを通じて対話的に入力できるようにします。また、更新内容にはGitHub APIの[Repository/Releases](https://developer.github.com/v3/repos/releases/)を使用し、[GitHubのリリース機能](https://help.github.com/articles/creating-releases/)で記載した内容を取得するようにします。そして、QAシートの項目には、作成したQAシートのURLを記載します。

## 3. APKを作成しBetaで社内に配布

AndroidチームではCIに[Wercker](http://www.wercker.com/)を使用しています。以下のQiitaの記事にまとめていますが、Wercker APIでビルドを実行しAPKの作成とBetaでの配布を行います。

[SlackからAPKを配布する](http://qiita.com/Horie1024/items/3eb517836c82837ab91c)

記事内でも紹介していますが、Wercker APIをHubotから使用するためのAPI ClientをOSSとして公開しています。

[horie1024/wercker-client](https://github.com/horie1024/wercker-client)

以下のように簡単にWercker APIを使用することが可能です。

```javascript

const Wercker = require('wercker-client').default;
const wercker = new Wercker({
  token: 'your_token'
});

wercker.Runs
  .getAllRuns({applicationId: "your_application_id"})
  .then((res) => {
    console.log(res);
  }).catch((err) => {
    console.log(err);
  });

```

# 全体の流れ

Slackに`android qa`と入力してからの処理の流れを図にすると以下のようになります。

① Slackに`android qa`と入力<br/>
② Hubotが反応<br/>
③ Drive APIを使いQAシートを作成<br/>
④ Qiitaチームにリリースノートを投稿<br/>
⑤ Wercker APIを使いビルドを開始<br/>
⑥ WerckerがGitHubからアプリのコードを取得しAPKを作成<br/>
⑦ BetaでAPKを配布<br/>
⑧ 配布の完了をSlackに通知<br/>

![techblog_2017_01_19_3.png](https://qiita-image-store.s3.amazonaws.com/0/43438/b0b5208a-ad81-3378-96e0-fb98a92656b8.png "techblog_2017_01_19_3.png")

# 実装

上記の流れを実装したサンプルコードです。

[horie1024/qa-automation-sample](https://github.com/horie1024/qa-automation-sample)

サンプルコードでは以下の流れで処理を行っています。

1. Google APIクライントの初期化
1. `android qa`コマンドを定義
2. リリースするVersion Nameを入力
3. マスターとなるシートをコピーしてQAシートを作成
4. QAシートのタイトルをVersion Nameを含めたタイトルに更新
5. QAシートのアクセス権限を特定のdomainに属するアカウントのみ編集できるよう変更
6. GitHubのrepositoryからリリースノートを取得
7. リリース日を入力
8. QA期間を入力
9. リリースノートをQiitaに投稿
10. Wercker APIを使いビルドを開始

# ローカルで実行

実行中の様子はこのようになります。

![techblog_2017_01_19_8.gif](https://qiita-image-store.s3.amazonaws.com/0/43438/6603d426-218d-ad50-4262-29d6caa4f1f7.gif "techblog_2017_01_19_8.gif")

リリースノートもテンプレート通りに投稿されています。

![techblog_2017_01_19_9.png](https://qiita-image-store.s3.amazonaws.com/0/43438/3b439ca6-376c-f793-8b64-7c8b48ad7792.png "techblog_2017_01_19_9.png")

# 実装する上で困った点

## Google APIクライントの初期化

HubotからDrive APIを操作するには[google/google-api-nodejs-client](https://github.com/google/google-api-nodejs-client)を使うのですが、認証・認可についての情報が少なく困りました。

手順としては、最初にAPIマネージャーからGoogle Drive APIを有効にします。

[https://console.cloud.google.com/apis/api/drive/overview](https://console.cloud.google.com/apis/api/drive/overview)

![techblog_2017_01_19_6.png](https://qiita-image-store.s3.amazonaws.com/0/43438/d50a741e-daf8-83d1-46d6-6e8b8f62d635.png "techblog_2017_01_19_6.png")

次に[コンソール](https://console.cloud.google.com/apis/credentials/serviceaccountkey)にアクセスし、**サービスアカウント名**と**サービスアカウントID**を入力してサービスアカウント新規作成します。役割には、スプレッドシートの編集を行う必要があるため**編集者**を指定します。役割の詳細は[こちら](https://cloud.google.com/iam/docs/understanding-service-accounts?hl=ja)から確認できます。

キーのタイプにJSONを選択し、作成をクリックするとJSONファイルがダウンロードされます。

![techblog_2017_01_19_7.png](https://qiita-image-store.s3.amazonaws.com/0/43438/2cd17990-76b2-ede5-b13e-a2d2fd66e1df.png "techblog_2017_01_19_7.png")

ダウンロードしたJSONを使用し認証・認可を行います。[こちら](https://github.com/google/google-api-nodejs-client#using-jwt-service-tokens)を参考に、以下のようにgoogleapisモジュールのJWT(JSON Web Token)メソッドを使いクライアントを作成します。

JSONファイル中に`client_email`と`private_key`というフィールドがあるので、それを以下の`SERVICE_ACCOUNT_EMAIL`、`SERVICE_ACCOUNT_KEY`に当てはめます。

```javascript
const jwtClient = new google.auth.JWT(
  SERVICE_ACCOUNT_EMAIL,
  null,
  SERVICE_ACCOUNT_KEY,
  ['https://www.googleapis.com/auth/drive'],
  null);
```

これでDrive APIを使用できるようになります。

`SERVICE_ACCOUNT_KEY`をHerokuの環境変数から読み込むとクライアントの初期化に失敗する場合があるので、以下の記事にまとめています。

[環境変数からprivate_keyを読み込んだ際にJWT Clientを初期化出来ない場合の対処方法](http://qiita.com/Horie1024/items/d65abeebaf803beae18b)

## Hubotとの対話的な入力

リリースするVersion Name、リリース日、QA期間はHubotと対話的に入力するようにしています。今回は、[hubot-conversationモジュール](https://www.npmjs.com/package/hubot-conversation)を使用しました。

VersionNameを入力させるには以下のようなコードになります。

```javascript
// Slackに通知
msg.reply("リリースするVersion Nameを入力してください。");

// Version Nameの入力を待機
var dialog = conversation.startDialog(msg);
dialog.addChoice(/([0-9]*\.[0-9]*\.[0-9]*)/, (conversationMsg) => {
  // 入力された文字の取得
  console.log(conversationMsg.match[1]);
});
```

## Drive APIでのファイルのパーミッション変更方法

ファイルのパーミッションを変更するには、[Permissions](https://developers.google.com/drive/v3/reference/permissions)の[createメソッド](https://developers.google.com/drive/v3/reference/permissions/create)を使用します。

パーミッションは`role`と`type`の組み合わせで指定します。例えば、編集権限をvasilyドメインのユーザーに付与するなら以下のように指定します。

```javascript
{
  role: "writer",
  type: "domain",
  domain: "vasily"  
}
```
[google/google-api-nodejs-client](https://github.com/google/google-api-nodejs-client)では、Request Bodyを[resourceパラメータで指定](https://github.com/google/google-api-nodejs-client#specifying-request-body)するのでファイルのアクセス権限を変更するコードは以下のようになります。

```javascript
drive.permissions.create({auth: jwtClient, fileId: sheetsId,
  resource: {
    role: "writer",
    type: "domain",
    domain: "vasily"
  }}, (err, res) => {});
```

# まとめ

自動化した結果、QAの準備が自動的に完了するようになりとても楽になりました。また、作業の抜け漏れも無くなりスムーズにQAを行うことができています。GitHubのリリース機能でリリース内容を書くのを忘れる事があるのが課題です。