PR の差分を取得する [GitHub Actions]
概要
PR の差分を取得する方法あれこれ。
GitHub CLI がおすすめです。
各ワークフローは on.pull_request
, on.pull_request_target
を前提にしています。
git diff
steps:
- uses: actions/checokut@v3
with:
fetch-depth: 0
- run: git diff origin/${GITHUB_BASE_REF}...origin/${GITHUB_HEAD_REF}
- run: git diff --name-only origin/${GITHUB_BASE_REF}...origin/${GITHUB_HEAD_REF}
分岐を特定するために fetch-depth: 0
で履歴をすべて取得する必要があります。
..
ではなく ...
なのがミソです。
..
: コミット同士の差分(ベースブランチの変更が含まれる)
...
: 分岐からの差分(ベースブランチの変更が含まれない = PR の Files changed)
以下の 2 つは同じです。
git diff A...B
git diff $(git merge-base A B) B
以下の 2 つは同じです。
git diff A..B
git diff A B
こちらも参考に。
ファイル名だけでいい場合は --name-only
オプションを付けます。
追加/変更/削除は区別されないので注意してください。
他にも様々なオプションがあるので応用が効きます。
ファイル数の上限はなさそう。(5,555 ファイルの差分が取得できることは確認)[1]
GitHub CLI
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
number: ${{ github.event.number }}
steps:
- run: gh pr diff ${number}
- run: gh pr diff ${number} --name-only
API から取得するのでチェックアウトは不要ですが、チェックアウトしている場合は GH_REPO
を省略できます。
ファイル名だけでいい場合は --name-only
オプションを付けます。
追加/変更/削除は区別されないので注意してください。
ファイル数の上限はなさそう。(5,555 ファイルの差分が取得できることは確認、差分が多いと API サーバーが処理しきれない可能性はあり)[1:1]
GitHub API
GraphQL API での取得方法は分からなかったので REST API のみ。
差分
steps:
- run: |
curl -sS \
-H "Accept: application/vnd.github.v3.diff" \
-H "Authorization: Bearer ${token}" \
${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/pulls/${number}
env:
token: ${{ github.token }}
number: ${{ github.event.number }}
steps:
- run: |
gh api \
-H "Accept: application/vnd.github.v3.diff" \
/repos/${GITHUB_REPOSITORY}/pulls/${number}
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
number: ${{ github.event.number }}
Custom media types という特殊なヘッダーがあります。
PR の情報を取得する API で Accept: application/vnd.github.v3.diff
ヘッダーを指定すると差分が取得できるようになります。
パブリックリポジトリでは Authorization ヘッダーを省略できます。
ファイル数の上限はなさそう。(5,555 ファイルの差分が取得できることは確認、差分が多いと API サーバーが処理しきれない可能性はあり)[1:2]
ファイル名
steps:
- run: |
curl -sS \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${token}" \
${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/pulls/${number}/files \
| jq -r '.[].filename'
env:
token: ${{ github.token }}
number: ${{ github.event.number }}
steps:
- run: gh api /repos/${GITHUB_REPOSITORY}/pulls/${number}/files --jq '.[].filename'
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
number: ${{ github.event.number }}
filename
以外にも patch
(ファイル毎の差分)など様々な情報が含まれるので応用が効きます。
ただし 3,000 ファイルが上限であることに注意してください。
パブリックリポジトリでは Authorization ヘッダーを省略できます。
Accept: application/vnd.github+json
ヘッダーは付けておくのが推奨ですが省略可能です。
GitHub API (パブリックリポジトリ)
steps:
- run: |
json=$(curl -sS \
-H "Accept: application/vnd.github+json" \
${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/pulls/${number})
curl -sS -L $(echo "${json}" | jq -r '.diff_url')
env:
number: ${{ github.event.number }}
steps:
- run: curl -sS -L $(gh api /repos/${GITHUB_REPOSITORY}/pulls/${number} --jq '.diff_url')
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
number: ${{ github.event.number }}
アンドキュメントですが PR の情報を取得する API に diff_url
というプロパティがあってそこへアクセスすると差分を取得できます。
パブリックリポジトリ限定のようです。
Accept: application/vnd.github+json
ヘッダーは付けておくのが推奨ですが省略可能です。
JSON で返ってくる URL はこちらなのですがリダイレクトされるので -L
オプションを付けています。
最初からこの URL に直接アクセスすることもできそうですがアンドキュメントなものなので予告なく変更される可能性がありそうです。
https://github.com/${GITHUB_REPOSITORY}/pull/${number}.diff
https://patch-diff.githubusercontent.com/raw/${GITHUB_REPOSITORY}/pull/${number}.diff
ファイル数の上限はなさそう。(5,555 ファイルの差分が取得できることは確認、差分が多いと API サーバーが処理しきれない可能性はあり)[1:3]
サードパーティアクション
たくさんあってキリがないのでここでは個別の紹介はしません。
依存と学習コストは少ない方がいいので基本的には上記で紹介した方法を推奨しますが物足りないときは探してみるといいかもしれません。
追加/変更/削除を区別したいケースなどでは便利そうです。(自分でコードを書けば git diff
や GitHub API でも実装できるとは思いますが)
Discussion