🧑‍💻

#142 GitHub ActionsでPRに画像をコメントしてみた

に公開

はじめに

ここ数か月、Fletに関する記事を書いてきましたが、実行ファイルのビルドをGitHubActionsに任せてmainにmergeされる度に自動で各環境向けの実行ファイルがビルドされる仕組みを作りたいと考えていました。
そこでまず手始めにGitHubActionsで遊んでみようということで、PRを作成時に特定の画像をPRにコメントできるのかというのを試行錯誤してみました。

目標

画像ファイルをPRに含ませたうえでコメントするというのは少し面白みに欠けたので、
PlantUML で作成したファイルを乗せてPRを作成時に画像を生成→PRに生成した画像をコメントする。
というのを目指します。

※ PlantUML とは、UMLやダイアグラムの作成をテキストベースで簡単に行えるツールです。

Base64エンコード

結論から書くと、PR内のコメントに画像を添付するのは「何らかの外部ストレージに画像をアップした上でURLをPRコメントに埋め込む」というのが一番現実的なアプローチでした。
もしかすると他にも良いアプローチ方法などがあるかもしれませんが、分かり易く実現可能な範囲では今回のような方法になるかと思います。

まず生成した画像を base64 でエンコードし、エンコード結果をMarkdownで埋め込むというアプローチを検証しました。

※ 例:

  1. 画像( sample.png )をbase64エンコード
    base64 -w 0 sample.png
  2. Markdownで埋め込み
    ![Image](data:image/png;base64,エンコード結果)

検証したところ、通常のMarkdownファイルでは以上の書き方で埋め込み可能でしたが、GitHubで使われている GitHubFlavoredMarkdown ではBase64での画像埋め込みはできないようでした。

外部ストレージ

直接PR上に画像を添付してコメントするようなAPIは提供されていないようでしたが、外部ストレージにアップロードした画像URLを取得し、Markdownで埋め込むことで表示することは可能でした。
外部ストレージサービスはAWS S3をはじめ色々とありますが、今回はできるだけGitHub内で完結すること、リポジトリの可視性に追従する形を目指していたので本来の使い方とは逸れますがRelease内のassetsにアップロードし、そのURLを埋め込むことにします。

workflow

以下が今回の要件を実現したworkflowです。

create-uml-images.yml
name: Create UML Images

on:
  pull_request:

permissions:
  contents: write
  issues: write
  pull-requests: write

jobs:
  build:
    name: Run Build
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      # 必要なパッケージをインストール
      - name: Install Dependencies
        run: |
          sudo apt-get update -y
          sudo apt-get install -y default-jdk graphviz gh

      - name: Download PlantUML
        run: wget -O plantuml.jar https://github.com/plantuml/plantuml/releases/download/v1.2025.2/plantuml.jar

      # PlantUMLを実行
      - name: Execute PlantUML
        run: java -jar plantuml.jar sample.pu

      # Releaseに画像をアップロード
      - name: Upload to GitHub Releases
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          RELEASE_TAG="pr-${{ github.event.pull_request.number }}-uml-images"
          gh release create $RELEASE_TAG --notes "Generated Image Upload" || true
          gh release upload $RELEASE_TAG sample.png --clobber

      # アップロードしたURLを取得しコメントに埋め込み投稿
      - name: Comment PR with Image URL
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          RELEASE_TAG="pr-${{ github.event.pull_request.number }}-uml-images"
          IMAGE_URL="https://github.com/${{ github.repository }}/releases/download/${RELEASE_TAG}/sample.png"
          gh issue comment ${{ github.event.pull_request.number }} --body "![Generated Image](${IMAGE_URL})"

全体的なフローとしては

  1. PRを作成時に実行
  2. plantUMLにの実行に必要な環境をセットアップ
  3. GitHubCLIをセットアップ
  4. Releaseに画像をアップロード
  5. 作成されたPRのコメントに画像を埋め込み投稿

となります。
それでは次は各フローを抽出したコードを記載します。

plantUMLの実行に必要な環境をセットアップ

特別な記載などは特にないですが、

  1. javaのインストール
  2. graphvizのインストール
  3. plantuml.jar のダウンロード

を以下部分で行います。

create-uml-images.yml
      # 必要なパッケージをインストール
      - name: Install Dependencies
        run: |
          sudo apt-get update -y
          sudo apt-get install -y default-jdk graphviz gh

      - name: Download PlantUML
        run: wget -O plantuml.jar https://github.com/plantuml/plantuml/releases/download/v1.2025.2/plantuml.jar

画像を埋め込み投稿

下記記載で、

  1. Releaseに画像をアップロード
  2. 画像のURLを取得
  3. 取得した画像URLをコメントに埋め込み投稿

ということを行っています。

create-uml-imgaes.yml
      # PlantUMLを実行
      - name: Execute PlantUML
        run: java -jar plantuml.jar sample.pu

      # Releaseに画像をアップロード
      - name: Upload to GitHub Releases
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          RELEASE_TAG="pr-${{ github.event.pull_request.number }}-uml-images"
          gh release create $RELEASE_TAG --notes "Generated Image Upload" || true
          gh release upload $RELEASE_TAG sample.png --clobber

      # アップロードしたURLを取得しコメントに埋め込み投稿
      - name: Comment PR with Image URL
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          RELEASE_TAG="pr-${{ github.event.pull_request.number }}-uml-images"
          IMAGE_URL="https://github.com/${{ github.repository }}/releases/download/${RELEASE_TAG}/sample.png"
          gh issue comment ${{ github.event.pull_request.number }} --body "![Generated Image](${IMAGE_URL})"

本来、Releaseの使用方法としてこのような使い方を想定していないと思うので、Release Tagなどは申し訳程度に分かり易くしている程度ですが、pr-{number}-uml-imagesと命名し、画像をアップロードしています。

こうすることで、以下画像のように sample.pu を自動で sample.png として出力し、releaseにアップロード、PR内のコメントに埋め込みます。

また、アップロードされたassetsはリポジトリの可視性に引っ張られるため、プライベートリポジトリの場合にはURLを知っていれば画像のみアクセスされるということもありません。

おわりに

もう少し複雑になるかと思っていましたが思ったよりも少ない記述で達成することができました。
試せてはいませんが、別の手段としてseleniumなどで直接アップロードすることでreleaseを介せずともコメントに埋め込むことが可能だとは思います。
また、現状は sample.pu => sample.png という状態なので差分で検知したファイルのみを変換し投稿するという風にすることや、mergeされたら自動で対象のreleaseを削除するなどとするとより実用性が高そうです。
ここまで読んでいただきありがとうございました。

Discussion