GitHub ActionsでPRに同一種類のコメントをUpsertで追加する方法

GitHub ActionsのPull Request (以下PR)イベントトリガーのワークフローにおいて、対象コードのLintやセキュリティスキャン、terraform planやCloudFormation Change Setなどの結果をPRのコメントに表示されると何かと嬉しいですよね？ 本記事では、このPRコメントを、InsertではなくUpsert（なければInsert,あればUpdate）で投稿する方法を紹介する。

もし、コメント内容を意識せずにPR synchronizeイベントなどトリガーでワークフローが走るたびにコメントを投稿するような作りだと同じようなコメントがいくつも投稿されてしまいPRを汚してしまうことになることが想像できるかと思う。で、これをInsertではなくUpsertするには[GitHub API - Review Comments](https://developer.github.com/v3/pulls/comments/)でコメント一覧を取得し、同じコメントに対してUpdateすればよいはず。著者も最初それでやろうとした。でも、GitHub Marketplaceを覗いてみると既にやりたいことを実現してくれる素敵なActionがみつかった。それが、[Sticky Pull Request Comment](https://github.com/marketplace/actions/sticky-pull-request-comment)。 というわけで、以下、このActionを使ってPRコメントをUpsertする方法を簡単に説明する。

## 1.コメント文字列を直接渡す方法

`marocchino/sticky-pull-request-comment@v1`アクションの`message` inputに文字列を渡す。ここでは前のstepでコメント文字列を作成して`set-output`でその後のstepに共有している。また、`header`に渡す文字列によりそのコメントを識別する。同じheaderのコメントであれば、２回目以降はUpsertで更新される。もし別々のコメントして分けたければ、headerの内容を変える必要がある。

```yaml
      - name: "Make PR comment body"
        id: make-pr-comment
        run: | 
          now=$(date "+%s")
          pr-comment-body="It's ${now}" 
          echo ::set-output name=result::${pr-comment-body}
      - name: "PR comment on Updating CFn Change Set"
        uses: marocchino/sticky-pull-request-comment@v1
        with:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          header: header-of-comment
          message: ${{ steps.make-pr-comment.outputs.result }}
```


## 2. コメント文字列をファイルから渡す方法
1と違い、２はコメントの文字列をファイルから渡すアプローチ。サイズが大きめの文字列や、JSONやYAMLなどの文字列を Pretty-print、つまり取得した時の状態を保ち整形表示させたい場合にはファイルから渡すのがよいかと思う。`marocchino/sticky-pull-request-comment@v1`アクションの`path` inputにファイルのパス渡す。
以下のサンプルはAWS CloudFormationのChange Setのdescribeの内容（JSON）をファイルに落とし、次のstepでPR commentとして投稿している。

```yaml
      - name: "Make PR comment body"
        id: make-pr-comment
        run: |
          pr_comment_body=''
          changeset_output=$(aws cloudformation describe-change-set --change-set-name ＄｛changeset_id｝)
          pr_comment_body=$(cat << EOF
          ${pr_comment_body}
          <details><summary><code>${changeset_name}</code></summary> 
     
          \`\`\`json
          ${changeset_output}
          \`\`\`
          </details>
          EOF

          pr_comment_body_file=/tmp/pr_comment_body.txt
          cat << EOF  > ${pr_comment_body_file}
          <strong>CFn Change Set</strong>

          ${pr_comment_body}
          EOF
          echo ::set-output name=result::${pr_comment_body_file}

      - name: "PR comment"
        if: steps.make-pr-comment.outputs.result
        uses: marocchino/sticky-pull-request-comment@v1
        with:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          header: header-of-comment
          path: ${{ steps.make-pr-comment.outputs.result }}
```

実行結果サンプル
![スクリーンショット 2020-07-09 22.14.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103420/ec627877-4805-2ca3-57f9-eb27e25df71f.png)

ということで、結論は、[GitHub API - Review Comments](https://developer.github.com/v3/pulls/comments/)でコメント一覧を取得し、同じコメントを見つけてUpdateしてもいいけど、[Sticky Pull Request Comment](https://github.com/marketplace/actions/sticky-pull-request-comment)を使うと楽でにできるよ・・・でした。