TL;DR
タグをトリガーとするGitHub Actionsでそのタグがmainブランチに存在しない場合、エラー終了させるには以下のようなstepを組み込めば良い。
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Fail if tagged commit is not in main branch
run: |
BRANCHES=$(git branch -r --contains)
echo $BRANCHES
for BRANCH in $BRANCHES ; do
if [[ "$BRANCH" == "origin/main" ]]; then
exit 0
fi
done
exit 1
- name: Deploy
run: echo "Deploy sesame"
背景
あるリポジトリで、特定のタグを付けたらデプロイするというGitHub Actionsを構築していた。
このとき、タグが最終的な統合ブランチであるmainブランチに所属していることをチェックしたいと考えた。
同じようなことをやろうとしている、以下のような先行記事があった。
Github Actionsでpushされた時に特定ブランチとタグでトリガーする(Zenn)
しかし、こちらの求めるものと少し相違があった。
先行記事の内容
対比しやすいように、先行記事のコードの内容を損ねないように整理したものがこちらになる。
# (1) mainをチェックアウト
- uses: actions/checkout@v4
with:
ref: main
fetch-depth: 0
# (2) github.ref_name が指すタグがmainブランチ上のコミットに付いていない場合はエラー終了
- name: Fail if tagged commit is not in main branch
run: |
BRANCHES=$(git branch --contains ${{ github.ref_name }})
echo $BRANCHES
for BRANCH in $BRANCHES ; do
if [[ "$BRANCH" == "main" ]]; then
exit 0
fi
done
exit 1
# (3) デプロイを実行
- name: Deploy
run: echo "Deploy sesame"
意図通りで無かった点はただ1つ。
(3)の時点で、本来はタグがチェックアウトされた状態になっていてほしいのだが、mainブランチがチェックアウトされていることである。
解決方法
まず、チェックアウト対象としてmainを指定するのをやめる。
- uses: actions/checkout@v4
with:
fetch-depth: 0
ただし、こうすると git branch --contains
としたときにmainがヒットしなくなる。
fetch-depth: 0
を指定したにも関わらずである。
これは actions/checkout
でrefを指定しない場合、トリガーとなったrefがチェックアウトされ、ローカルブランチとしてのmainは存在していないからである。
ローカルブランチとしてのmainは存在していないのだが、リモート追跡ブランチ(こちらの用語を参照した)である`origin/main
はfetchされている( fetch-depth: 0
の効果)。
リモート追跡ブランチで対象のタグが含まれているものをリストアップするためには -r
オプションを追加して git branch -r --contains
とする。
- name: Fail if tagged commit is not in main branch
run: |
BRANCHES=$(git branch -r --contains)
# ※対象を省略した場合は現在のHEADが対象となるため、タグをチェックアウトしていれば `${{ github.ref_name }}` は不要
以上を踏まえた完成形は以下のようになる。
name: Deploy
on:
push:
tags:
- 'v*'
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Fail if tagged commit is not in main branch
run: |
BRANCHES=$(git branch -r --contains)
echo $BRANCHES
for BRANCH in $BRANCHES ; do
if [[ "$BRANCH" == "origin/main" ]]; then
exit 0
fi
done
exit 1
- name: Deploy
run: echo "Deploy sesame"
Q&A形式の補足
Q1: refをmainにした状態でcheckoutして、後で git checkout ${{ github.ref_name }}
しても良いのでは?
それでも良いと思う。
ただ、タグをトリガーとしたworkflowであればタグがチェックアウトされた状態を期待すると思うので、他のコミット(ブランチ)がチェックアウトされた状態はなるべく避けたかった。
Q2: git branch --contains ${{ github.ref_name }}
したものをechoするとなんかファイル名が列挙されるんだが?
mainブランチをチェックアウトしている状態では、 git branch(以下略
は次のようなテキストを出力する。
❯ git branch --contains v1.2.3
* main
アスタリスクは現在チェックアウトされているブランチを指す。
したがって、結果をechoするということは echo * main
というコマンドを実行することになる。
このとき *
はglob展開され、実行ディレクトリ直下のファイルが列挙される。