GitHubのRESTAPIをもちいてclosedされたプルリクエスト中の、削除されていないfeatureブランチを列挙する方法

# 目的
GitHubを何も考えず運用していくと、featureブランチが増えていく傾向がある。
今回は、closedされたプルリクエストのブランチを列挙して削除して良いかを検討するためのツールを作成する。

実はGitHubはREST API経由で操作を行うことができ、今回はそれを利用するものとする。
https://docs.github.com/en/rest

# 前提
以下の環境があること

 - Node.js(v12.20.1)が使用できること
 - [GitHubのアクセストークンが存在すること](https://docs.github.com/ja/github/authenticating-to-github/creating-a-personal-access-token)

# コード
## インストールするライブラリ

 - request
 - request-promise

## GitHubの操作を行うクラス

```js:GitHubCtrl.js
const rp = require('request-promise');

class GitHubCtrl {
  constructor (userId, token, repoName) {
    this.userId = userId;
    this.token = token;
    this.repoName = repoName;
    this.baseUrl = 'https://api.github.com/repos';
  }
  /**
   * https://docs.github.com/en/rest/reference/pulls
   * @param {string} state all or open or closed
   * @returns 
   */
  getPullRequests (page=1, state='all') {
    const url = `${this.baseUrl}/${this.repoName}/pulls?state=${state}&per_page=100&page=${page}`;
    return this.getApi(url);
  }
  async getAllPullRequest (state='all') {
    let page = 1;
    let result = [];
    while (true) {
      const pageRet = await this.getPullRequests(page, state).catch(ex => {
        console.error(ex)
      });
      if (!pageRet || pageRet.length === 0) return result;
      result = result.concat(pageRet)
      ++page
    }
  }
  getBranches (page = 1) {
    const url = `${this.baseUrl}/${this.repoName}/branches?per_page=100&page=${page}`;
    return this.getApi(url);
  }
  async getAllBranches (state='all') {
    let page = 1;
    let result = [];
    while (true) {
      const pageRet = await this.getBranches(page).catch(ex => {
        console.error(ex)
      });
      if (!pageRet || pageRet.length === 0) return result;
      result = result.concat(pageRet)
      ++page
    }
  }
  getPullRequest (no) {
    const url = `${this.baseUrl}/${this.repoName}/pulls/${no}`;
    return this.getApi(url);
  }
  getApi (url) {
    return rp(
      {
        method: 'GET',
        uri: url,
        json: true,
        headers: {
          Authorization: `token ${this.token}`,
          'user-agent': 'node.js'
        }
      }
    );
  }
  get (url) {
    return rp(
      {
        method: 'GET',
        uri: url,
        auth: {
          user: this.user,
          pass: this.token          
        }
      }
    );
  }
}
module.exports = GitHubCtrl;

```

## closedのプルリクエスト中で、featureブランチが存在しているものを列挙

```js
const GitHubCtrl = require('./GitHubCtrl');
const user = 'ユーザー名';
const token = 'GitHubのアクセストークン';
const repoName = '組織名・ユーザ名/レポジトリ名'

async function main () {
  const ctrl = new GitHubCtrl(user, token, repoName);
  const branches = await ctrl.getAllBranches(1)
  const requests = await ctrl.getAllPullRequest('closed')
  for (const req of requests) {
    // console.log(req.number, req.title, req.user.login, req.created_at, req.updated_at, req.head.ref)
    const branch = branches.find((b)=>b.name === req.head.ref)
    if (branch) {
      console.log(` - ${branch.name} [${req.number} ${req.title}](${req._links.html.href}) ${req.updated_at} ${req.user.login}` )
    }
  }
}

main()
```

# まとめ
GitHubにはREST APIが公開されており、容易にその操作を行える。
今回は、リスクを考慮して参照しか行っていないが、これを利用することで削除まで行うことも可能と考えられる。

また、以下のようにGitHub APIを使用してプルリクエストのチェックツールを作成して、英単語、コードクローン、複雑度のチェックを行うこともできる。

https://github.com/mima3/check_pullreq