テンプレートファイルからプルリクエストを作る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 ↩