Github Actionsでpushされた時に特定ブランチとタグでトリガーする
はじめに
Github Actionsしてますか?
CI/CDフローを作成していると特定のブランチにタグを打ったタイミングにだけ処理を走らせたくなりますよね。
main
ブランチのコミットにバージョンタグ(ie. v1.0.0
)が付けられた時だけ本番環境にデプロイしたい etc.
そんな時、Github Actionsでどう実現するかを考えてみました。
結論
こうなりました。
name: Example
on:
push:
tags:
- 'v*'
jobs:
prod_deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout main branch
uses: actions/checkout@v3
with:
ref: main
fetch-depth: 0
- name: Check tagged branch
run: |
BRANCHS=$(git branch --contains ${{ github.ref_name }})
set -- $BRANCHS
for BRANCH in $BRANCHS ; do
if [[ "$BRANCH" == "main" ]]; then
exit 0
fi
done
exit 1
- name: Next step...
run: |
詳細をみていきます。
トリガー Trigger
まずはトリガーについて確認します。
今回のシナリオではpush
イベントに対してジョブを実行したいので、
on:
push:
を使います。
pushイベントに対しては、pushされたブランチやタグの名前でフィルターを記述することができます。
それにより特定のブランチやタグでのみジョブを実行することが可能です。
このフィルターに特定のブランチへの指定のタグ付与という条件を記述できれば解決します。
しかし、Using filters to target specific branches or tags for push eventsの項を読むとbranches
とtags
を単純に併記した場合には、どちらかを満たせばワークフローが実行されるとわかります。
つまり、
on:
push:
branches:
- 'main'
tags:
- 'v*'
としても、
-
main
ブランチにpushされた時 - (どのブランチへのコミットかに関わらず)
v*
タグがpushされた時
のどちらの時にもワークフローが開始されます。
そのため目的の挙動を実現するには、ブランチへのpushで開始されたワークフローの中でタグの有無を確認する、あるいは、タグのpushで開始されたワークフローの中で該当コミットがブランチに含まれるかを確認することが必要です。
今回は後者の方法を深掘りします。
コンテキスト Context
コンテキストを参照すると、トリガーとなったイベントの周辺情報を確認できます。
公式ドキュメントにある次の例のように、特定のジョブについてはpushされたのがmain
ブランチの時のみ実行する、という分岐を書けるようになります。
name: CI
on: push
jobs:
prod-check:
if: ${{ github.ref == 'refs/heads/main' }}
runs-on: ubuntu-latest
steps:
- run: echo "Deploying to production server on branch $GITHUB_REF"
とはいえ、タグでトリガーされた時にブランチ名を直接参照するコンテキストは存在しません。そのため、上の例と同じようにif構文を使う方法ではうまくいきません。コンテキストをgitコマンドと組み合わせて使い、コマンドラインで取得する必要があります。
タグのつけられたコミットが含まれるブランチは次のgitコマンドで取得できます。
git branch --contains ${TAG}
$ git branch --contains v1.0.0
* main
test_branch
このコマンドを使えばpushされたタグについて、特定のブランチにも含まれるのかを確認できそうです。
pushされたタグはコンテキストgithub.ref_name
を使ってタグ名を取得できます。
こねくりまわす
ここまでをまとめると、
- 特定のタグがpushされた時に起動する
- そのタグがついたコミットが含まれるブランチ一覧を取得する
- ブランチ一覧に特定のブランチが含まれる時正常終了、含まれない時異常終了する
とすれば実現できそうです。
それぞれ、次の通り記述できます。
- 特定のタグがpushされた時に起動する
on:
push:
tags:
- 'v*'
- そのタグがついたコミットが含まれるブランチ一覧を取得する
steps:
- name: Checkout main branch
uses: actions/checkout@v3
with:
ref: main
fetch-depth: 0
- name: Check tagged branch
run: |
BRANCHS=$(git branch --contains ${{ github.ref_name }})
- ブランチ一覧に特定のブランチが含まれる時正常終了、含まれない時異常終了する
set -- $BRANCHS
for BRANCH in $BRANCHS ; do
if [[ "$BRANCH" == "main" ]]; then
exit 0
fi
done
exit 1
組み合わせたものが結論になっています。
おわりに
Github Actionsでpushされた時に特定ブランチとタグでトリガーする方法について記述しました。
今回のやり方ではmain
ブランチに含まれるコミットに対する命名規則を満たしたタグ付け全てにトリガーされます。
変更を遡ることに柔軟である一方、厳格さに欠ける面もあるかもしれません。
よりミスを減らすにはタグ付け自体をワークフローで実行するなど工夫できると良さそうです。
オペレーション自体を見直せるのであればワークフローを複雑化せずに済みなお良いでしょう。
シンプルで最良なフローの実装を頑張りたいですね。
Discussion