目的
ブランチ名=環境定義名
とした場合にその環境名のブランチへのPRがマージされたときに
デリバリー(デプロイ)フローにおける環境差異をEnvironmentsに定義したVariableやSecretを参照できるようにするフローを検討する。
※環境定義名とはデプロイに環境を使用するに記載された環境定義により参照する変数・シークレットなどを切り替えられる機能です。(それだけの機能ではないですが、詳細はリンク先を参照)
なお、この機能は無料アカウントでは、publicなリポジトリしか利用できない機能です。
GitHub Teams/Proなどの有料アカウントではprivateリポジトリでも利用可能。
TL;DR
PRがマージされたときにベースブランチ
また環境名のブランチを選択して手動でワークフローを実行(workflow_dispatch)する場合にも対応する。
※前提条件として、環境名のブランチにはProtecionにより直接のプッシュができないように設定してあるものとします。
name: Build and Deploy
on:
# PRのマージCLOSEで実行(マージの条件はここにはかけないのでジョブの起動条件ifで絞る)
pull_request:
branches:
- development
- staging
- production
types:
- closed
# 手動実行時(任意のブランチを選択された環境名にデプロイできるようにする)
workflow_dispatch:
inputs:
# デプロイする環境
deploy_target:
description: Environment to deploy
required: true
type: choice
options:
- development
- staging
- production
jobs:
build-deploy:
# 環境別にシークレット(secrets.*)や変数(vars.xxxx)を切り替える定義
environment: ${{ (github.event_name == 'pull_request' && github.ref_name) || inputs.deploy_target }}
runs-on: ubuntu-latest
if: github.event.pull_request.merged || github.event_name == 'workflow_dispatch'
steps:
# チェックアウト
- name: Checkout resources
uses: actions/checkout@v3
# ビルドステップなどをここに記載
- name: Build
run: echo "dummy build process"
# デプロイをステップなどを記載
- name: Deploy
run: |
echo "Deploy to ${{ env.TARGET_RESOURCE_NAME }}"
# ログ上はマスキングされてしまうが、実際の処理では参照可能
echo "Access key=${{ env.TARGET_RESOURCE_API_KEY }}"
# 例としてここに環境定義にしたシークレットや変数(Variable)を環境変数として設定
env:
TARGET_RESOURCE_NAME: ${{ vars.TARGET_RESOURCE_NAME }}
# 対象環境のリソースにデプロイするためのAPIKeyとかシークレットなどを
TARGET_RESOURCE_API_KEY: ${{ secrets.RESOURCE_API_KEY }}
# 処理完了通知をSlackに
- name: slack-send
uses: slackapi/slack-github-action@v1.23.0
with:
payload: |
{
"text": "GitHub Action build-deploy result: ${{ job.status }}\ntarget:${{ vars.TARGET_RESOURCE_NAME }}\nkey:${{ secrets.RESOURCE_API_KEY }}"
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
ポイントとしてはこれができるのは github.ref_name
で環境名に対応するブランチ名が設定されているイベントの場合のみということになります。
イベント毎にブランチ名を分ける必要がある場合は、(条件 && 合致した場合) || 合致しない場合
みたいな書き方をネストさせればなんとかなるとは思いますが、可読性が悪そうなので別途コメント書いておいたほうがよいでしょう。
ただし、ここで利用できるのはあくまでもGitHubActionsが起動したときに確定している変数(Context)の値のみであるはずです。チェックアウトしたり、Stepで処理した変数や環境変数を設定することはできないと思われます。(未検証)
検証作業記録
イベント別のブランチ名の参照方法
イベント毎に違うことは理解していてもいつも忘れるのでメモしておきます。
ここでは、feature/hogehoge
ブランチを作成後に以下の操作が行われたこととします。
- ローカルで開発・テストが完了したfeatureブランチをプッシュする
- featureブランチからdevelopmentブランチへPRを作成する
- 作成したPRのレビューの指摘を受けて修正コミット+プッシュをする
- ワークフローを手動実行
- 作成したPRがマージする
- PRのマージによるpull_requestのイベント
- PRのマージによるベースブランチがへのプッシュイベント
No | イベント | github.event_name | github.event.action | github.event.pull_request.merged | github.ref_name | github.head_ref | github.base_ref |
---|---|---|---|---|---|---|---|
1 | featureブランチへプッシュ | push | feature/hogehoge | ||||
2 | PR作成時 | pull_request | opened | false | 2/merge | feature/hogehoge | development |
3 | 作成済PRに追加コミット(push)時 (レビューの指摘結果反映など) |
pull_request | opened | false | 2/merge | feature/hogehoge | development |
4 | 手動実行(feature/hogehogeブランチを選択して実行) | workflow_dispatch | feature/hogehoge | ||||
5-1 | PRのマージ(headブランチ側のpull_request) | pull_request | closed | true | development | feature/hogehoge | development |
5-2 | PRのマージ(baseブランチ側のpush) | push | development |
pushイベントやworkflow_dispacthイベントは github.ref_name
で対象のブランチが取得できますが、紛らわしいのがpull_requestイベント。
open/syncronizedの場合は github.ref_name
にはGitHub内部で自動生成されるマージ作業用?一時的なブランチが設定されますが、マージ後の場合はpushイベントと同じで github.ref_name
がマージされたブランチ=ベースブランチなりました。
ブランチ名検証ワークフロー
name: Confirm branch name
on:
push:
pull_request:
types:
- opened
- synchronize
- closed
workflow_dispatch:
jobs:
show-variable:
runs-on: ubuntu-latest
steps:
- name: Checkout resource
uses: actions/checkout@v3
- name: Show github context
run: |
echo "github.event_name=${{ github.event_name }}"
echo "github.event.pull_request.merged=${{ github.event.pull_request.merged}}"
echo "github.ref_name=${{ github.ref_name }}"
echo "github.head_ref=${{ github.head_ref }}"
echo "github.base_ref=${{ github.base_ref }}"
ブランチ名検証ワークフロー実行結果
push(featureブランチをプッシュしたとき)
github.event_name=push
github.event.action=
github.event.pull_request.merged=
github.ref_name=feature/hogehoge
github.head_ref=
github.base_ref=
pull_request-作成時(action=opened)
github.event_name=pull_request
github.event.action=opened
github.event.pull_request.merged=false
github.ref_name=2/merge
github.head_ref=feature/hogehoge
github.base_ref=development
pull_request-作成後の追加コミットなど(action=synchronize)
ithub.event_name=pull_request
github.event.action=synchronize
github.event.pull_request.merged=false
github.ref_name=2/merge
github.head_ref=feature/hogehoge
github.base_ref=development
手動実行(workflow_dispatch)
github.event_name=workflow_dispatch
github.event.action=
github.event.pull_request.merged=
github.ref_name=feature/hogehoge
github.head_ref=
github.base_ref=
pull_request-マージ(headブランチ側のpull_requestイベント)
github.event_name=pull_request
github.event.action=closed
github.event.pull_request.merged=true
github.ref_name=development
github.head_ref=feature/hogehoge
github.base_ref=development
※ポイントとしてpull_requestのマージで発生するトリガーの場合 github.ref_name
はbaseブランチと同じになります。
pull_request-マージ(baseブランチ側のpushイベント)
github.event_name=push
github.event.action=
github.event.pull_request.merged=
github.ref_name=development
github.head_ref=
github.base_ref=
環境切り替えワークフロー実行結果
それぞれの環境の変数とシークレットには以下を設定した状態とします
変数/シークレット名 | development | staging | production |
---|---|---|---|
TARGET_RESOURCE_NAME | xxx-deplopment | yyy-staging | zzz-production |
RESOURCE_API_KEY | development-key | staging-key | production-key |
別途:SLACK_WEBHOOK_URL
はリポジトリ共通としてリポジトリ全体のシークレットに設定
※以下、ログ上のシークレット文字列は ***
でマスキングされてしまうのでログでは確認できませんが、最後のSlack通知のPayloadに含めているkey部分はちゃんと環境別の値が送信されました。
featureブランチ->developmentブランチへマージ
Run echo "Deploy to xxx-deplopment"
echo "Deploy to xxx-deplopment"
# ログ上はマスキングされてしまうが、実際の処理では参照可能
echo "Access key=***"
shell: /usr/bin/bash -e {0}
env:
TARGET_RESOURCE_NAME: xxx-deplopment
TARGET_RESOURCE_API_KEY: ***
Deploy to xxx-deplopment
Access key=***
developmentブランチ->stagingブランチへマージ
Run echo "Deploy to yyy-staging"
echo "Deploy to yyy-staging"
# ログ上はマスキングされてしまうが、実際の処理では参照可能
echo "Access key=***"
shell: /usr/bin/bash -e {0}
env:
TARGET_RESOURCE_NAME: yyy-staging
TARGET_RESOURCE_API_KEY: ***
Deploy to yyy-staging
Access key=***
stagingブランチ->productionブランチへのマージ
Run echo "Deploy to zzz-production"
echo "Deploy to zzz-production"
# ログ上はマスキングされてしまうが、実際の処理では参照可能
echo "Access key=***"
shell: /usr/bin/bash -e {0}
env:
TARGET_RESOURCE_NAME: zzz-production
TARGET_RESOURCE_API_KEY: ***
Deploy to zzz-production
Access key=***
手動実行時にdevelopmentブランチを選択して、ターゲットにstagingを選択して実行
Run echo "Deploy to yyy-staging"
echo "Deploy to yyy-staging"
# ログ上はマスキングされてしまうが、実際の処理では参照可能
echo "Access key=***"
shell: /usr/bin/bash -e {0}
env:
TARGET_RESOURCE_NAME: yyy-staging
TARGET_RESOURCE_API_KEY: ***
Deploy to yyy-staging
Access key=***
ちゃんとenvironmentsの三項演算子的な記述の部分がハンドリングされて、inputs.deploy_targetの選択した環境が選択されていることが確認できた。