GitHub Actions、定期実行でプルリクエストを作成してマージする
とあるWebサイトの運営で毎日定時にコードの差分を検出して定期的にデプロイを実行しないといけない場面がありました。そこで毎日定時に develop ブランチと main ブランチの差分を検出してプルリクエストの作成とマージを自動で実施するGitHub Actionsを作成してみました。
事前準備
定期実行するワークフローの実行が終わったらデプロイを実行するGitHub Actionsを用意しておきます。
name: Deploy for production
on:
# 別のワークフローから起動できるようにする
workflow_call:
# pushやpull_requestはGitHubボットが実行した
# PRのマージには反応しないので以下は利用できない
#push:
# branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
# 開発しているアプリに合わせてビルドとデプロイのジョブを作っておく
Pull Requestを自動生成するActions
このジョブが毎日15時に実行されプルリクエストがマージされると、事前準備で設定したデプロイジョブが自動で実行されるようになっています。定期実行ジョブ -> デプロイジョブの順に実行されます。
name: Daily deploy for production
on:
schedule:
# 毎日15:00(UTC6:00)に実行する
- cron: '0 6 * * *'
workflow_dispatch:
jobs:
daily-deploy:
runs-on: ubuntu-latest
outputs:
IS_DISPATCH: ${{ steps.merge_pr.outputs.IS_DISPATCH }}
env:
# GitHubコマンドを実行するために必要な設定
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Set current datetime as env variable
env:
TZ: 'Asia/Tokyo'
run: echo "CURRENT_DATETIME=$(date +'%Y-%m-%d %H:%M:%S')" >> $GITHUB_ENV
- name: Checkout repository
uses: actions/checkout@v4
with:
# この設定がないと差分検出がうまくいかないので注意
fetch-depth: 0
ref: develop
- name: Diff
id: diff
# diffがあるとfailureになる
run: |
git diff origin/main origin/develop --exit-code
# failure時に次のジョブを実行できるようにする
continue-on-error: true
- name: 【定期実行】Create Pull Request
id: create-pull-request
# diffがある時のみPRを作成する
if: steps.diff.outcome == 'failure'
run: |
PULL_REQUEST_URI=$(gh pr create -B main -t "【定期実行】本番リリース ${{ env.CURRENT_DATETIME }}" -l 'daily deploy' -b "")
echo "PULL_REQUEST_URI=$PULL_REQUEST_URI" >> "$GITHUB_OUTPUT"
- name: 【定期実行】Merge Pull Request
id: merge_pr
# diffがある時のみPRをマージする
if: steps.diff.outcome == 'failure'
run: |
gh pr merge ${{steps.create-pull-request.outputs.PULL_REQUEST_URI}} --merge
echo "IS_DISPATCH=TRUE" >> "$GITHUB_OUTPUT"
call-workflow:
# merge_prのステップまで実行できたらdeploy.yamlを起動する
if: needs.daily-deploy.outputs.IS_DISPATCH == 'TRUE'
needs: [daily-deploy]
uses: ./.github/workflows/deploy.yaml
定期実行
定期実行の設定は以下になります。基本は cron コマンドと同じです。
on:
schedule:
# 毎日15:00(UTC6:00)に実行する
- cron: '0 6 * * *'
差分の検出
コードの差分検出は git コマンドを使って行います。git diff コマンドは差分があると failure になるので continue-on-error を設定します。
- name: Diff
id: diff
# diffがあるとfailureになる
run: |
git diff origin/main origin/develop --exit-code
# failure時に次のジョブを実行できるようにする
continue-on-error: true
差分検出後のジョブは Diff が failure すなわち差分があるときだけ実行するようにします。
if: steps.diff.outcome == 'failure'
Pull Requestの作成
Pull Request の作成部分は以下になります。GitHubコマンドを使ってプルリクエストを作成します。次のマージジョブのためにプルリクのURLを PULL_REQUEST_URI 環境変数に設定しておくのがポイントです。
- name: 【定期実行】Create Pull Request
id: create-pull-request
# diffがある時のみPRを作成する
if: steps.diff.outcome == 'failure'
run: |
PULL_REQUEST_URI=$(gh pr create -B main -t "【定期実行】本番リリース ${{ env.CURRENT_DATETIME }}" -l 'daily deploy' -b "")
echo "PULL_REQUEST_URI=$PULL_REQUEST_URI" >> "$GITHUB_OUTPUT"
-l 'daily deploy'
の部分はなくても問題ないです。あとで自動実行したプルリクを追えるようにラベルを設定しています。
Pull Requestのマージ
プルリクのURLを指定してGitHubコマンドでマージします。
- name: 【定期実行】Merge Pull Request
# diffがある時のみPRをマージする
if: steps.diff.outcome == 'failure'
run: |
gh pr merge ${{steps.create-pull-request.outputs.PULL_REQUEST_URI}} --merge
デプロイワークフローの呼び出し
merge_pr のステップまで実行できたらあらかじめ用意しておいた deploy.yaml のワークフローを起動します。
call-workflow:
if: needs.daily-deploy.outputs.IS_DISPATCH == 'TRUE'
needs: [daily-deploy]
uses: ./.github/workflows/deploy.yaml
注意点
GitHub Actions のジョブ内で Pull Request をマージしても他のワークフローがトリガーされない罠があるのでご注意ください。回避策は GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
をやめて自前のデプロイトークンを利用する(GitHubボットに実行させない)か、workflow_run
を使ってトリガーするか、または今回の例のように workflow_call
を使うかの3択です。
Discussion