📚

PR上の既存のコメントを更新して情報の氾濫を防ぐ

2024/02/29に公開

こんにちは。最近、確定申告と戦った_yy616 です。

Github Action を使ってワークフローを組む際に、PRに自動でコメントを投稿するケースはよくあるかと思います。例えば自動テスト結果のレポートを投稿したり、ドキュメントの更新をリマインダーしたり、セキュリティスキャンツールの実行結果のレポートを投稿したりする場合です。

しかし、そのようなワークフローがトリガーされる度に、毎回同じようなコメントが投稿されると、PRの可読性が低下したり、古い情報を誤って参照してしまったりする可能性が増えます。

上記のような、コメントの自動投稿による煩わしさは、PR上に既にコメントがある場合はそのコメントを更新し、コメントがない場合は新しくコメントを追加するようにできれば解決しそうです。

そこで今回はPR上の既存のコメントを更新する実装を紹介します。

実装

以下が具体的な実装です。この実装を用いることでコメントを更新できます。

name: Manage PR Comment

on:
  pull_request:
    types: [opened, synchronize, reopened, edited]

jobs:
  manage-pr-comment:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: write
    name: A job to manage PR comments
    steps:
      - name: Checkout
        uses: actions/checkout@v7

      - name: Manage PR Comment
        id: manage-comment
        uses: actions/github-script@v7
        with:
          script: |
            const prNumber = ${{ github.event.pull_request.number }};
            const commentBody = `検索キーワードを更新する`; // ここを適宜修正
            const searchKeyword = '検索キーワード'; // ここを適宜修正

            const comments = await github.rest.issues.listComments({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: prNumber,
            });

            const commentToUpdate = comments.data.find(comment => comment.body.startsWith(searchKeyword));

            if (commentToUpdate) {
              await github.rest.issues.updateComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                comment_id: commentToUpdate.id,
                body: commentBody,
              });
            } else {
              await github.rest.issues.createComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: prNumber,
                body: commentBody,
              });
            }
          github-token: ${{ secrets.GITHUB_TOKEN }}

解説

複雑な実装ではないですが、部分的に説明を加えておきます。

コメントの取得

まず、指定されたPRに対するすべてのコメントを取得します。これはgithub.rest.issues.listComments APIを呼び出すことで実現しています。このAPIは、オーナー名、リポジトリ名、そしてIssue番号(この場合はPR番号)をパラメータとして受け取ります。

          const comments = await github.rest.issues.listComments({
            owner: context.repo.owner,
            repo: context.repo.repo,
            issue_number: prNumber,
          })

更新するかどうかの判定:

特定のキーワードを持つコメントが含まれるかどうかをチャックすることでコメントを更新するか、新しく作成するかを判定しています。単純な文字列一致でキーワード判定を行うので、適切な装飾子をつけるなどして誤発火しないように注意してキーワードを設定します。

const commentToUpdate = comments.data.find(comment => comment.body.startsWith(searchKeyword));

コメントの更新または作成

該当するコメントが既に存在する場合、そのコメントをgithub.rest.issues.updateCommentを使用して更新します。

更新する際には、コメントのIDと新しいコメントの本文(body)が必要です。該当するコメントがない場合は、github.rest.issues.createCommentを使用して新しいコメントを追加します。

          if (commentToUpdate) {
            await github.rest.issues.updateComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              comment_id: commentToUpdate.id,
              body: commentBody,
            });
          } else {
            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: prNumber,
              body: commentBody,
            });
          }

実行結果

以下の画像のような感じでコメントが作成 or 変更されます。

まとめ

地味な小ネタ系 Action ですが、使い所は意外と多いと思うのでぜひ試してみてください!
Composite Action に切り出して使うのもおすすめです。

Discussion