GitHub Actionsでプルリクのコメントに複数行テキストを投稿する

GitHub Actionsで複数行テキストの取り扱いに苦戦したので、検証結果を残しておく。

目的

GitHub Actionsから、トリガー元のプルリクエストに対して複数行テキストのコメント投稿を実証する。
想定は、CIの実行結果をプルリクエストにコメントで記載するようなユースケース。

検証コード

最初に、テキストを整形するためのfront_matterback_matterを生成している。
その後は2回、set-outputで出力結果を渡すことでプルリクへの書き込みを試みる。

1回目はset-outputを行う前に改行文字をエンコードしていないため、後続処理には1行分のテキストしか渡すことができない。
2回目はset-outputを行う前に改行文字をエンコードしているため、後続処理に複数行のテキストを渡すことができる。

プルリクエストへコメントを投稿するActionsは幾つか存在するが、今回はPR Commentを使用した。

    steps:
      - uses: actions/checkout@v2 

      - name: Generate front_matter and back_matter
        run: |
          echo "# Comment by GitHub Actions
          <pre><details>
          <summary> post_comment_to_pr.yml </summary>
          <code>" > front_matter
          
          echo "</code></details></pre>" > back_matter

      - name: No escape text
        id: no_escape
        run: |
          text=`cat front_matter .github/workflows/post_comment_to_pr.yml back_matter`
          echo "::set-output name=message_body::$text"

      - uses: github-actions-up-and-running/pr-comment@v1.0.1
        with:
          repo-token: ${{ secrets.GITHUB_TOKEN }}
          message: ${{ steps.no_escape.outputs.message_body }}

      - name: Escape newline characters by URL encoding
        id: multiline
        run: |
          text=`cat front_matter .github/workflows/post_comment_to_pr.yml back_matter`
          text="${text//'%'/'%25'}"
          text="${text//$'\n'/'%0A'}"
          text="${text//$'\r'/'%0D'}" 
          echo "::set-output name=message_body::$text"

      - uses: github-actions-up-and-running/pr-comment@v1.0.1
        with:
          repo-token: ${{ secrets.GITHUB_TOKEN }}
          message: ${{ steps.multiline.outputs.message_body }}

ファイル全体はこちら(GitHub)を参照。

検証コードの実行結果

先に検証コードの実行結果から。

プルリクエストには2つのコメントが投稿される。

1つ目はset-outputを行う前に改行文字をエンコードしなかった場合であり、このときのコメントは一行目しか投稿されない。 without-encoding

2つ目はset-outputを行う前に改行文字をエンコードした場合であり、以下のようにコメントが正しく投稿される。 with-encoding

これは、クリックすることで複数行のテキスト部を展開して表示することができる。 details

検証コードでやっていること

set-outputで値を出力し、後続処理で読み出せるようにする

とある処理の実行結果を後続処理で使用したい場合、set-outputという仕組みが利用できる。

以下のコードでは、textに代入した内容をset-outputでmessage_bodyにセットしている。

- name: No escape text
  id: no_escape
  run: |
    text=`cat .github/workflows/post_comment_to_pr.yml`
    echo "::set-output name=message_body::$text"

こうすることで、後続処理ではtextの内容を${{ steps.no_escape.outputs.message_body }}として参照できるようになる。

公式ドキュメント: https://docs.github.com/ja/actions/using-workflows/workflow-commands-for-github-actions#setting-an-output-parameter

改行文字列をURLエンコードする

set-outputでは1行のテキストしか代入できないが、改行文字列をURLエンコードすればこの制限を回避できるようだ。
これはGitHubのSupport Communityに記載されている情報。

検証コードでは以下の箇所が該当する。

text="${text//'%'/'%25'}"
text="${text//$'\n'/'%0A'}"
text="${text//$'\r'/'%0D'}" 

detailsタグ等を使い、見やすくする

(これはGitHub ActionsというよりもMarkdownやHTMLの話であるが)

PRのコメントに書き込む内容が数十行に渡る場合、スクロールが大変になる。
特に、PRの対象ブランチへPushするたびにワークフローが実行される場合は顕著となる。

そのため、検証コードではdetailsタグ等を用いることで表示領域を小さく抑えている。
以下のようにMultiline Textfront_matterback_matterで挟んでPRに投稿している。

# Comment by GitHub Actions
<pre><details>
<summary>post_comment_to_pr.yml</summary>
<code>Multiline 
Text</code>
</details></pre>

注意
ここで書いた検証コードでは、タグのエスケープ処理を行っていない。
そのためfront_matterback_matterの間のテキストにタグが含まれると、以下のように表示が崩れる要因となる。

need-to-escape

CIなどで使う程度であれば実際には問題にならない場合が多いと思われるが、これは一種の脆弱性であるため要注意。
特に、信頼できない人による入力が想定される場合はエスケープ処理を行うこと。

関連記事


  1. 他の人には読めない形式でGitHubのSecretsの値を読み出す
  2. GitHub Actionsでエラーの時だけ特定の処理を実行する
  3. 既存コードへのCheckstyle導入におけるルールの選定
  4. Checkstyleで汎用的に使えそうなルールをピックアップしてみた
  5. JaCoCoでJavaのテストカバレッジのレポートを出力する
  6. Tera Termのマクロで、パスワードを扱う操作を自動化する
  7. HugoテンプレートをOGPやTwitter Cardsに対応する

comments powered by Disqus