GitHub Actions で Release PR を自動作成・更新する
背景
PKSHA Technology でソフトウェアエンジニアをしている林です。
私が所属している PKSHA Speech Insight 開発チームでは、ブランチベースでリリースを行なっています。
develop・staging・master ブランチの内容が、それぞれ develop・staging・production 環境に対応しています。
開発は通常以下の流れで進めています。
- develop ブランチから feature ブランチを派生させて機能開発
- 完成したら feature → develop へ PR を作成してマージ
- staging リリース時に develop → staging へ PR を作成してマージ
- 本番リリース時に staging → master へ PR を作成してマージ
これまでは、 develop → staging と staging → master の PR を手動で作成していました。しかし、手間がかかるのと、その Release PR にどの変更 (Feature PR) が含まれているのかわかりにくい問題がありました。
そこで、GitHub Actions で Release PR を自動作成する仕組みを導入しました。
また、その Release に含まれる Feature PR の一覧を Release PR の body へ記載するようにしました。
実装
前提条件: GitHub Token の設定
この Actions を動作させるには、Personal Access Token が必要です。
個人のユーザーで発行すると、チームから離れたときに動かなくなるので、システムユーザーで発行するようにしています。
-
Repository permissions
- Contents: Read and write(リポジトリの内容を読み書きするため)
- Pull requests: Read and write(PR の作成・更新・一覧取得のため)
- Metadata: Read only(リポジトリ情報の取得のため、自動的に付与される)
-
Organization permissions
- Members: Read only(PR 作成時にチームを Reviewer に設定するため)
作成したトークンを、リポジトリの Settings から、GH_TOKEN という名前で登録します。
Actions の実装
以下が PR を作成/更新する Actions の YAML です。
name: Create PRs
on:
pull_request:
types: [closed]
jobs:
deploy_to_staging_pr:
runs-on: blacksmith-2vcpu-ubuntu-2404
if: github.event.pull_request.merged == true
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
steps:
- name: Check Existing PRs
id: check_prs
run: |
existing_prs=$(gh pr list --repo my-org/my-repo --state open --base staging --head develop)
if [[ -n $existing_prs ]]; then
echo "PR from develop to staging already exists. Exiting..."
echo "pr_exists=true" >> $GITHUB_ENV
else
echo "No existing PR from develop to staging found. Proceeding..."
echo "pr_exists=false" >> $GITHUB_ENV
fi
- name: Create PR
if: env.pr_exists == 'false'
run: |
if \
gh pr create \
--repo my-org/my-repo \
--base staging \
--head develop \
--label "automated" \
--reviewer "my-org/repo-owner" \
--title "deploy to staging" \
--body "develop -> staging"
then
echo "pr_exists=true" >> $GITHUB_ENV
else
echo "Failed to create PR."
fi
- name: Update PR body
if: env.pr_exists == 'true'
run: |
pr_number=$(
gh pr list --json number --repo my-org/my-repo --state open --base staging --head develop --jq ".[0].number"
)
body=$(
gh api graphql -f query='
query($owner: String!, $repo: String!, $prNumber: Int!, $endCursor: String) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $prNumber) {
commits(first: 100, after: $endCursor) {
pageInfo{ hasNextPage, endCursor }
nodes {
commit {
messageHeadline
}
}
}
}
}
}' \
-F owner='my-org' -F repo='my-repo' -F prNumber=$pr_number \
--paginate \
--jq '.data.repository.pullRequest.commits.nodes.[].commit.messageHeadline | select(. | contains("Merge pull request #"))' \
| sed -e "s/^/- /g"
)
pr_id=$(
gh api graphql -f query='
query($owner: String!, $repo: String!, $prNumber: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $prNumber) {
id
}
}
}' \
-F owner='my-org' -F repo='my-repo' -F prNumber="$pr_number" \
--jq '.data.repository.pullRequest.id'
)
gh api graphql \
-f query='
mutation($prId: ID!, $body: String!) {
updatePullRequest(input: {
pullRequestId: $prId,
body: $body
}) {
pullRequest {
body
}
}
}' \
-F prId=$pr_id -F body="$body"
deploy_to_master_pr:
...
Create PR の step では、Release PR が存在しないときに PR を作成しています。
Update PR body の step では、PR に含まれるすべてのマージコミットを取得し、それをリスト形式で PR の本文に設定しています。
PR の作成 (gh pr create) や PR の一覧取得 (gh pr list) は gh CLI を利用しています。
PR に含まれる merge commit の一覧取得や、PR の更新は GraphQL API を利用しています。
PR の本文に、含まれるすべてのマージコミット(=マージされた PR)が一覧表示されます。
- Merge pull request #1234 from feature/add-user-api
- Merge pull request #1235 from fix/login-bug
- Merge pull request #1236 from feature/update-payment-flow
GitHub 上では、PR # のところに PR のタイトルが表示されるようになっているので、このデプロイには何が含まれるのかが一目でわかるようになっています。

まとめ
GitHub Actions と GraphQL API を組み合わせることで、環境間のデプロイ PR を自動作成し、デプロイ内容を可視化する仕組みを構築しました。
この仕組みにより、手動作業の削減やデプロイ内容の明確化が実現でき、開発チームの生産性向上に貢献しています。
Discussion