GitHubのAPIを利用して、プルリクを楽にしてみる

## はじめに
現在運用しているサービスでは、マイクロサービスで開発を行っています。
GitHubを使ってコードの管理を行っているのですが、masterへのマージ時に対象リポジトリが複数あるとGUIの操作では時間がかかってしまい面倒くさい！
それを解消するために、今回はGitHubのAPIを利用して複数のリポジトリへのプルリクエストを行ってみたいと思います。

## 開発環境
今回はnodeでコマンドラインツールを作ります。
プルリクエストを行いたいリポジトリ一覧をjson形式のファイルで定義し、それを読み込んでGitHub APIへリクエストする形にします。

# 1. 読み込むjsonファイルの形式を決める
```json
{
  "access-token": "xxxxxxxxxxxxxxxxxx",
  "owner": "xxxx",
  "repos": [
    {
      "name": "xxxxxx",
      "pull-request": {
        "title": "test",
        "body": "hogehoge",
        "head": "develop",
        "base": "master",
        "reviewers": ["taro"],
        "assignees": ["taro"],
      }
    }
  ]
}
```
#### access-token
APIアクセス時の認証に必要です。
[ここ](https://help.github.com/ja/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line)を参照し、アクセストークンを取得してください。
#### owner
リポジトリのオーナー名
ユーザー名や組織名です。
#### repos.head
マージ元のブランチ名
#### repos.base
マージ先のブランチ名

# 2. npmプロジェクトの作成
```sh
mkdir hub-request
cd hub-request
npm init -y
```

# 3. package.jsonの編集
今回は最小構成で記述します。
binの部分がコマンドラインで実行される対象ファイルになります。

```json
{
  "name": "hub-request",
  "version": "1.0.0",
  "bin": "index.js"
}

```

# 4. 依存パッケージのインストール

```sh
npm install axios
npm install ora
```
# 5. index.jsの実装

APIの詳しい仕様については[こちら](https://developer.github.com/v3/)を参照してください。

```js
#!/usr/bin/env node

const axios = require('axios');
const ora = require('ora');
const fs = require('fs');

const GITHUB_API_BASE_URL = 'https://api.github.com'

// 引数のパスからJSONファイルを読み込む
const json = JSON.parse(fs.readFileSync(process.argv[2], 'utf8'));

for (let repo of json.repos) {

  pullRequest(json['access-token'], json['owner'], repo)

}

async function pullRequest(accessToken, owner, repo) {

  const spinner = ora(`Processing pull request ${owner}/${repo.name}`).start();

  const repoUrl = `${GITHUB_API_BASE_URL}/repos/${owner}/${repo.name}`

  const pullRequest = repo['pull-request']

  try {

    // プルリクエスト
    const res = await axios.post(`${repoUrl}/pulls`, {
      title: pullRequest.title,
      body : pullRequest.body,
      head : pullRequest.head,
      base : pullRequest.base
    },
    {
      headers: {
        Authorization: `token ${accessToken}`
      }
    })

    // reviewersの追加
    await axios.post(`${repoUrl}/pulls/${res.data.number}/requested_reviewers`, {
      reviewers: pullRequest.reviewers,
    },
    {
      headers: {
        Authorization: `token ${accessToken}`
      }
    })

    // assigneesの追加
    await axios.post(`${repoUrl}/issues/${res.data.number}/assignees`, {
      assignees: pullRequest.assignees,
    },
    {
      headers: {
        Authorization: `token ${accessToken}`
      }
    })

  } catch(err) {

    spinner.fail(`Failed pull request ${owner}/${repo.name}`)

    console.error(err)

    return

  }

  spinner.succeed(`Completed pull request ${owner}/${repo.name}`)

}
```

# 6. 実行してみる
```sh
# まずグローバルに作成したnpmパッケージをインストールする
sudo npm install -g ./hub-request
# 対象リポジトリが記載されているjsonファイルのパスを引数として実行
hub-request ./target.json
```

# 7. まとめ
作っている最中で気づいたのですが、hubコマンドというものがあるらしく、それを使ったほうが良いかもしれないと思いました。
しかし途中で方向転換する気にもなれなかったので、今回はaxiosを使いAPIへリクエストを投げて見ました。

作成したパッケージは[GitHub](https://github.com/gen6414/hub-request)にアップしています。

おわり