3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

放置されたPRを自動的に閉じるGithubActionsを作成する

Last updated at Posted at 2020-04-13

更新日から1週間以上経過したPR(Pull Request)を自動的に閉じるGithubActionを作成しました。

なぜ作ったか

長期間放置されているPRがあり、スッキリさせたかったから。

期待される効果

PRの生存期限を設けることで以下の効果を期待しています。

問題 期待される効果
属人化による、レビュワー不足によるPR放置 ペアプロ
PRの単位が大きくレビュワーへの負担よるPR放置 小さな単位でのPRを意識
タスクの優先度が変わることによるPR放置 今必要ないPRはClose

作る

  • リポジトリにある更新してからX日以上経ったPRをクローズする
  • クローズしたPull Requestを標準出力で返す

作る前にGithubActionsを探してみましたが、なかったので作ります。
GitHub Marketplace · Actions to improve your workflow · GitHub

テンプレ

今回はTypeScriptのテンプレートを使わせていただきました。

テンプレートに加え、以下のライブラリを追加しています。

ライブラリ 概要
@octokit/rest GithubのRestAPI Client
jest-date-mock Dateのモック(テストで使用)

処理の流れ

入力: トークン(リポジトリのアクセストークン)
入力: 有効期限(デフォルトは7日)

更新日から7日以上経過したPRを取得

取得したプルリクエストをClose

出力: メッセージ
出力: プルリクエストのリスト(Json.stringfyで文字列で出力)

作成中に悩んだ箇所

テストでモックが効かない?

child_process.execSync でNodeからshellコマンドを実行できるんですが、以下のようなモックを使ったテストは失敗します。

main.test.ts
test('test runs', async () => {
  jest.spyOn(githubService, 'getDeadlinePullRequest').mockImplementation(() => {
    return Promise.resolve([
      {
        number: 1,
        title: 'テスト1',
        htmlUrl: 'http://test1.com'
      },
    ])
  })
  jest.spyOn(githubService, 'closePullRequests').mockImplementation(() => {
    return Promise.resolve()
  })

  const ip = path.join(__dirname, '..', 'lib', 'main.js')
  const options: cp.ExecSyncOptions = {
    env: process.env
  }
 // Command failed: node xxx/main.js
  console.log(cp.execSync(`node ${ip}`, options).toString())
})

xxx/main.jsを実際に叩いているので、jestのモックは無効となります。

配列の出力について

setOutputの第二引数はstringなので、配列を返すためJSON.stringifyで文字列にして出力した後、使う側でparseして使うことを考えました。

core.setOutput('closedPulls', JSON.stringify(deadlinePullList))

ただ使う側のSlack Notifyではそのような入力は受け付けていません。

また、GithubActionにもループ処理の構文がありませんでした。

仕方なくCloseしたPull Requestのリストをメッセージとして結合して返すことにしました。

main.ts
let message = "";
for (const pull of deadlinePullList) {
  message += `* [${pull.title}](${pull.htmlUrl})\n`
}

core.setOutput('closedPulls', JSON.stringify(deadlinePullList))
core.setOutput('message', message)

使用例

毎日09:00にcronで実行。クローズされたPRがあればSlackに通知。

/.github/workflows/pr.yml
name: Close PR by deadline and slack notification
on:
  schedule:
  # UTC
  - cron: '0 0 * * *'
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Close PR by deadline
        uses: matometaru/pr-deadline@1.0.0
        with:
          token: ${{ secrets.PR_TOKEN }}
          expirationDate: 7
        id: prDeadline
      - name: Slack Notification
        if: steps.prDeadline.outputs.closedPulls != '[]'
        uses: rtCamp/action-slack-notify@master
        env:
          SLACK_CHANNEL: self
          SLACK_ICON: https://github.com/rtCamp.png?size=48
          SLACK_MESSAGE: ${{ steps.prDeadline.outputs.message }}
          SLACK_TITLE: pr-deadline
          SLACK_USERNAME: rtCamp
          SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}

スクリーンショット 2020-04-12 20.29.53.png

参考

https://help.github.com/ja/actions/reference/context-and-expression-syntax-for-github-actions
https://octokit.github.io/rest.js/v17

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?