Pull RequestトリガーのGitHub ActionsでSkip CIを実現する (Deprecated)
この記事で説明している手法は不要になりました
GitHub Actionsは、組み込みでSkip CIをサポートするようになりました (GitHub Actions: Skip pull request and push workflows with [skip ci] - GitHub Changelog)。コミットメッセージに以下のキーワードが含まれていると、Workflowの実行が自動的にスキップされます。
[skip ci][ci skip][no ci][skip actions][actions skip]
そのため、この記事で紹介しているSkip CIの実現方法は不要になりました。記事を残しておきますが、以下で説明するJobをWorkflowに追加する必要はありません。
ここから不要になった方法の紹介です
Pull Requestトリガーで実行されるGitHub Actions Workflowで、コミットメッセージに [skip ci] などの特定のキーワードが含まれていたら、ビルドの実行をキャンセルする方法を紹介します。
PushトリガーのWorkflowの場合
PushトリガーのWorkflowでは、以下の記事で紹介されている方法で、Skip CIの仕組みを実現できます。
WorkflowがPushイベントで起動した場合、githubコンテキストの github.event.head_commit.message プロパティにコミットメッセージが設定されています。contains 組み込み関数でコミットメッセージがキーワードを含んでいるかどうかを調べ、その結果を反転してJobの if に設定すれば、Jobの実行有無を制御することができます。
on: push
jobs:
accept_commit:
runs-on: ubuntu-20.04
if: "! contains(github.event.head_commit.message, '[skip ci]')"
steps:
- run: echo "build is NOT skipped"
build:
runs-on: ubuntu-20.04
needs: accept_commit
steps:
Pull RequestトリガーのWorkflowの場合
Pull RequestトリガーのWorkflowでは、githubコンテキストのプロパティにコミットメッセージが入ってこないので、上記の方法は使うことができません。その代わり、コミットのハッシュが github.event.pull_request.head.sha プロパティでわかるため、git log コマンドでコミットメッセージを取得し、grep コマンドでキーワードの有無を調べることができます。以下に例を示します。
on: pull_request
jobs:
check_commit:
runs-on: ubuntu-20.04
env:
SKIP_CI_KEYWORD: "[skip ci]"
outputs:
skip_ci: ${{ steps.check_message.outputs.skip_ci }}
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 2
- name: Check commit message
id: check_message
run: |
message=$(git log --format=%B -n 1 ${{ github.event.pull_request.head.sha }})
if echo "$message" | grep -q -F "${{ env.SKIP_CI_KEYWORD }}"; then
echo "::set-output name=skip_ci::true"
else
echo "::set-output name=skip_ci::false"
fi
build:
runs-on: ubuntu-20.04
needs: check_commit
if: ${{ needs.check_commit.outputs.skip_ci != 'true' }}
steps:
check_commit ジョブで、以下のことを実行しています。
- リポジトリをチェックアウトする
- コミットハッシュ
github.event.pull_request.head.shaのコミットメッセージを取得して、[skip ci]キーワードが含まれているかどうかを調べる - 調べた結果を、
check_commitジョブのOutputskip_ciにtrueorfalseで設定する
後続のジョブは、needs で check_commit ジョブに依存することを宣言し、needs.check_commit.outputs.skip_ci で check_commit ジョブの skip_ci Outputを参照することができます。あとは、ジョブの if 条件文で、needs.check_commit.outputs.skip_ci が true でない場合にジョブを実行する (= needs.check_commit.outputs.skip_ci が true だったらジョブの実行をキャンセルする)、と記述することで、Skip CIの仕組みを実現できます。
ここで、check_commit ジョブにおいて、GITHUB_SHA をコミットのハッシュとして利用することはできないので、注意が必要です。Pull RequestトリガーのWorkflowでは、GITHUB_REF はGitHubが自動的に生成するのPRマージブランチ refs/pull/:prNumber/merge を指しており、GITHUB_SHA はこのPRマージブランチの最新コミットを指しています (Events that trigger workflows - GitHub Docs)。PRマージブランチは、GitHubが自動的に生成するブランチで、Pull Requestの作業ブランチとベースブランチをマージした状態を追跡しています。Pull Requestの作業ブランチとベースブランチのマージコミットが常に自動的に作成されており、Pull RequestトリガーのWorkflowでは GITHUB_SHA はそのマージコミットを指しています。今回、コミットメッセージを調べたいコミットは、Pull Request作業ブランチの最新コミット = マージコミット (GITHUB_SHA) の1つ前のコミットです。actions/checkout@v2 アクションは、デフォルトでは GITHUB_SHA のコミットだけしかチェックアウトしないので、fetch-depth: 2 パラメーターを指定してその1つ前のコミットまでチェックアウトし、GITHUB_SHA ではなく github.event.pull_request.head.sha のコミットを調べる必要があります。
GitHub Actionsのサンプル
上で紹介した方法のサンプルは、kafumi/github-actions-skip-ci-samples に配置してあります。
- PushトリガーのWorkflowのサンプル:
.github/workflows/push.yml - Pull RequestトリガーのWorkflowのサンプル:
.github/workflows/pull_request.yml
Discussion