はじめに
CI/CDでE2Eテストの結果スクリーンショットをGitHub Issueに自動投稿したい。
そんな単純な要件なのに、実現しようとすると意外な壁にぶつかりました。GitHubにはIssueコメントに画像をアップロードするAPIが存在しないのです。
Web UIでは普通にドラッグ&ドロップで画像を貼り付けられるのに、APIからはできない。この制限を補うために作ったのが gh-attach です。
作ったもの
gh-attach は、GitHub Issue/PRのコメントに画像をアップロードするCLIツールです。
# 基本的な使い方
gh-attach --issue 123 --image ./screenshot.png
# コメント本文と一緒に
gh-attach --issue 123 --image ./e2e.png --body "E2E test result:"
# 複数画像をアップロード
gh-attach --issue 123
--image ./before.png
--image ./after.png
--body 'Before: <!-- gh-attach:IMAGE:1 -->
After: <!-- gh-attach:IMAGE:2 -->'
なぜAPIで画像をアップロードできないのか
GitHubのIssueコメントAPIは body パラメータにMarkdownテキストを受け取るだけで、ファイルをアップロードする機能がありません。
Web UIで画像を貼り付けると https://user-images.githubusercontent.com/... のようなURLに変換されますが、このアップロード先 uploads.github.com はOAuthトークンでの認証を受け付けず、ブラウザのセッションCookieが必要です。
つまり、公式にはAPI経由での画像アップロードはサポートされていないのです。
解決策: playwright-cliでブラウザを自動操作
APIがダメならブラウザを使えばいい。そこで playwright-cli を使ってブラウザを自動操作する方法を取りました。
処理の流れは以下の通りです:
- プレースホルダー付きのコメントをAPIで作成
- playwright-cliでGitHubをブラウザで開く
- コメントの編集画面で画像をアップロード
- アップロードされた画像URLを取得
- APIでコメントを更新し、プレースホルダーを画像に置換
ヘッドレスモードで動作するため、CI環境でも問題なく使えます。初回のみ --headed オプションでブラウザを表示してGitHubにログインすれば、以降はセッションが保持されます。
セッション情報はPlaywrightのユーザーデータディレクトリ(~/.playwright-cli/)に保存されます。共有環境で使用する場合はアクセス権限にご注意ください。
技術的なポイント
プレースホルダーによる画像位置の制御
複数画像をアップロードする際、どこに画像を挿入するかを制御できるようにしました:
テスト結果:
<!-- gh-attach:IMAGE:1 -->
修正後:
<!-- gh-attach:IMAGE:2 -->
プレースホルダーがない場合は、コメントの末尾に画像が追加されます。
GitHub Enterpriseサポート
--host オプションでGitHub Enterpriseにも対応しています。ホストを指定しない場合は、現在のリポジトリの設定から自動検出します。
gh-attach --issue 123 --image ./result.png --host github.mycompany.com
画像サイズの固定
アップロードされた画像は <img> タグで挿入され、デフォルトで幅500pxに固定されます。--width オプションで変更可能です。
インストール
Homebrewでインストールできます:
brew tap atani/tap
brew install gh-attach
# 初回はブラウザでGitHubにログイン
gh-attach --issue 1 --image ./test.png --headed
おわりに
「APIにない機能はブラウザ自動化で補完する」という力技ですが、実用上は問題なく動作しています。
なお、ブラウザ自動化は自身のアカウントでの操作に限定し、過度なリクエストを避けるなど、GitHubの利用規約に配慮した使い方を心がけてください。
CI/CDでのスクリーンショット投稿、テスト結果の可視化など、自動化の幅が広がるツールになりました。
リンク
- GitHub: https://github.com/atani/gh-attach
- Homebrew Formula: https://github.com/atani/homebrew-tap

