テンプレートファイルからプルリクエストを作るGitHub Actionsワークフロー
やりたいこと
次のような操作でプルリクエスト (PR) を作りたい。
- リポジトリ内にテンプレートファイルがあるとして、そのファイル内のプレースホルダーを所与の値で置換する
- その置換済みのファイルをコミットしたブランチに基づいて、PRを作る
- GitHub Actions (GHA) を使って、上述したファイルのコミットとPRの作成をWeb UIの操作だけで済ませる
- 自動でコミットやPRを作るので、マシンユーザーを作成者とする
たとえば次のようなファイル
# ${PR_TITLE}
<!-- ここに本文を書いてね -->
がリポジトリ内にテンプレートとして用意されているとする。このとき、Web UIから${PR_TITLE}
に与える値として「サンプル記事」という文字列を渡すと、
# サンプル記事
<!-- ここに本文を書いてね -->
というファイルが新しいブランチにコミットされ、PRが作られるようにしたい。
実現方法
次の手順でやりたいことを実現できる。
- 「github-actions[bot]」アカウントとしてPRを作るreusable workflowを定義する
- Web UIから実行できるワークフローを定義し、その中でPRを作るreusable workflowを呼ぶ
この手順は、PR作成ロジックとワークフロー実行インタフェースの分離を意識している。
「github-actions[bot]」アカウントとしてPRを作るreusable workflowを定義する
「github-actions[bot]」アカウントとして、テンプレートから生成したファイルをコミットしてPRを作るワークフロー。reusable workflowとして定義することで、Web UIからのPR作成とは別のユースケースでも再利用できる。
name: reusable-create-pr
on:
workflow_call:
inputs:
title:
type: string
default: "title"
required: false
description: PR title
template:
type: string
default: "path/to/template.md"
required: false
description: |
Path to the template file. Use $PR_TITLE in the template to replace it with the actual PR title.
secrets:
token:
required: true
description: GitHub token
outputs:
pr_number:
description: PR number
value: ${{ jobs.create-pr.outputs.pr_number }}
jobs:
create-pr:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
env:
BRANCH: ${{ github.actor }}-${{ github.run_id }}
TITLE: ${{ inputs.title }}
ASSIGNEE: ${{ github.actor }}
GITHUB_TOKEN: ${{ secrets.token }}
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-git # 後述のsetup-gitの説明を参照のこと
- name: Create a pull request
id: create_pr
run: |
# PRを作るために、ブランチを作って空コミットをプッシュする
git switch -c "${BRANCH}"
git commit --allow-empty -m "Prepare for ${BRANCH}"
git push origin "${BRANCH}"
# gh CLIでPRを作り、出力としてPRのURLを得る
PR_URL=$( \
gh pr create \
--head "${BRANCH}" \
--title "${TITLE}" \
--draft \
--assignee "${ASSIGNEE}" \
)
echo "pr_url=${PR_URL}" >> "${GITHUB_OUTPUT}"
- name: Commit the template
id: commit-template
env:
PR_URL: ${{ steps.create_pr.outputs.pr_url }}
TEMPLATE: ${{ inputs.template }}
PR_TITLE: ${{ inputs.title }}
run: |
# 例として、<PR番号.md>というファイル名でテンプレートをコピーしてくる
echo "::group::Copy template"
export PR_NUMBER
PR_NUMBER=$(echo "${PR_URL}" | grep -oE "[0-9]+$")
FILE_PATH="path/to/${PR_NUMBER}.md"
cp "${TEMPLATE}" "${FILE_PATH}"
echo "::endgroup::"
# envsubstを使って、テンプレート内のプレースホルダーを入力値で置換する
echo "::group::Replace variables in template"
envsubst '${PR_TITLE}' < "${FILE_PATH}" > "${FILE_PATH}.tmp"
mv "${FILE_PATH}.tmp" "${FILE_PATH}"
echo "::endgroup::"
# 変更をコミットしてPRにプッシュする
echo "::group::Commit and push template"
git add "${FILE_PATH}"
git commit -m "Set up a file"
git push origin "${BRANCH}"
echo "::endgroup::"
echo "pr_number=${PR_NUMBER}" >> "${GITHUB_OUTPUT}"
outputs:
pr_number: ${{ steps.commit-template.outputs.pr_number }}
テンプレートからファイルを作るときに、プレースホルダー${PR_TITLE}
だけを置換対象にするため、envsubstにプレースホルダー名を含む文字列'${PR_TITLE}'
を引数として渡している1。
ワークフローの見通しをよくするために、「github-actions[bot]」アカウントになるためのGitのセットアップはアクションに切り出す。このアクションの置き場は .github/actions/setup-git/action.yaml を想定している。description
記載のリンク先のページにもあるとおり、「github-actions[bot]」としてコミットを作るための公式(?)ハックを使っている。
name: Set up Git as github-actions[bot]
description: |
cf. <https://github.com/actions/checkout/blob/v4/README.md#push-a-commit-using-the-built-in-token>
runs:
using: composite
steps:
- name: Set up Git
shell: bash
env:
USERNAME: github-actions[bot]
EMAIL: 41898282+github-actions[bot]@users.noreply.github.com
run: |
git config --global user.name "${{ env.USERNAME }}"
git config --global user.email "${{ env.EMAIL }}"
Web UIから実行できるワークフローを定義し、その中でPRを作るreusable workflowを呼ぶ
GHAのWeb UI(リポジトリ配下の/actions/workflows/<ワークフローファイル名>
のパスでアクセスできる画面)からPRを作るreusable workflowを実行するために、手動実行可能なワークフローを次のように定義する。
name: Create pull request
on:
workflow_dispatch:
inputs:
title:
description: PR title
required: true
default: "[WIP]"
jobs:
create-pr:
uses: ./.github/workflows/reusable-create-pr.yaml
with:
title: ${{ github.event.inputs.title }}
secrets:
token: ${{ secrets.GITHUB_TOKEN }}
permissions:
contents: write
pull-requests: write
これで、Web UIから、テンプレートをもとに生成したファイルを含むPRが作れるようになる。
脚注
-
envsubstがこのような仕様になっている経緯については、次の記事を参照のこと: envsubstの本来の使い方はテンプレートエンジンではなくシェルスクリプト用の国際化機能 #ShellScript - Qiita ↩