【Github Actions】定期的に変更コミットをチェックしてアクション実行判断する
はじめに
この記事では、GitHub Actions を利用してリポジトリの変更有無を確認して何らかの処理をトリガーさせる方法について説明します。
前回 Rust プロジェクトにて自動でクレートのバージョンアップをするワークフローを紹介しましたが、何らかの条件によりこういった処理をトリガーしたいケースがあります。
今回は定期的にリポジトリに変更があったかどうかをチェックして処理をトリガーさせるような仕組みを構築してみます。
完成状態
構築するワークフローの実装はこちらです。
アップデートのためのチェックを実施し、そのチェック結果を以て、実処理のためのワークフロー呼び出しに使用しています。
今回実処理には、前回構築した自動でクレートバージョンアップを行うためのワークフロー (workflow_dispatch
) を使用します。
name: Check for Version up
on:
schedule:
- cron: '0 18 * * *'
env:
INTERVEL_SEC: 86400 # same to cron interval
TARGET_PATH: src # check for updates in these files/folders
jobs:
check:
runs-on: ubuntu-latest
steps:
- name: Checkout the source code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Check for updates
id: check
run: |
LATEST_COMMIT_UNIX_TIME=$((git log -1 --format=%ct -- ${{ env.TARGET_PATH }}))
CUREENT_TIME=$(date +%s)
DIFF=$((CUREENT_TIME - LATEST_COMMIT_UNIX_TIME))
IS_EXIST_NEW_COMMIT=$(($CUREENT_TIME - ${{ env.INTERVEL_SEC }} - $LATEST_COMMIT_UNIX_TIME < 0))
echo "is_exist_new_commit=$IS_EXIST_NEW_COMMIT" >> $GITHUB_OUTPUT
- name: if check flag is true, request to update
if: ${{ steps.check.outputs.is_exist_new_commit != '0' }}
uses: convictional/trigger-workflow-and-wait@v1.6.5
with:
owner: (owner_name)
repo: (repo_name)
workflow_file_name: (workflow_filename)
github_token: ${{ secrets.GITHUB_TOKEN }}
Step By Step
前のセクションで完成したワークフローを展開しましたが、ここでは必要とするパーツごとに解説を加えながら完成系を作る流れを紹介していきます。
リポジトリチェックアウト
対象にするリポジトリのコミット情報を使用する必要があるので actions/checkout@vN
を使用する際に fetch-depth: 0
を指定します。(コストはかかるので、多少深さをコントロールしても良いでしょう。)
Set fetch-depth: 0 to fetch all history for all branches and tags.
Source: https://github.com/actions/checkout
name: Check for Version up
on: # todo
jobs:
check:
runs-on: ubuntu-latest
steps:
- name: Checkout the source code
uses: actions/checkout@v3
with:
fetch-depth: 0
期間内にコミットがあったかチェック
実行時に現在までの指定した時間範囲においてコミットがあったかどうかをチェックします。現在時刻は date
で取得し、最新のコミットは git log
を利用して取得しましょう。時間データ自体を比較する際にはフォーマットやタイムゾーンを気にしたり基準を揃えることを意識する必要がありますが、今回は UNIX時間
を使用します。
UNIX時刻はシステム依存だが、大多数のシステムでは、協定世界時 (UTC) の時刻に基づき、1970年1月1日午前0時0分0秒 (UNIXエポック) からの経過秒数を、閏秒の存在を無視し形式的な差を計算した値に等しい。
Source: https://ja.wikipedia.org/wiki/UNIX時間
date
では +%s
を付与することで Unix epoch からの秒数を取得することができます。
% date +%s
1709022219
直前のコミットに関しては、git log -1
で取得しますが、ここにフォーマットの指定 --format=%ct
を入れることで "直前のコミットのUNIX時間" を取得することができます。
% git log -1
commit 0055b997df1ead6a67cc2ed9711e6bef652dd27b (HEAD -> main)
Author: linnefromice <linnefromice@gmail.com>
Date: Mon Feb 26 21:40:07 2024 +0900
chore: xxxxx
% git log -1 --format=%cd
Mon Feb 26 21:40:07 2024 +0900
% git log -1 --format=%ct
1708951207
Reference: Git - pretty-formats Documentation
これらのコマンドを利用して、更新有無をチェックします。以下のように変数を利用するので、後述のワークフロー実装を理解する際の参考にしてください。
- 最終コミット時刻 -> 変数
LATEST_COMMIT_UNIX_TIME
に代入 - 現在時刻 -> 変数
CUREENT_TIME
に代入 - 更新があったと判断する現在時刻からの時間範囲 -> GitHub ワークフローの
env
のINTERVEL_SEC
に設定- 今回はこの値を "1日" に設定しています。(24 * 60 * 60)
これらを踏まえて、以下のような実装になります。
...
+env:
+ INTERVEL_SEC: 86400 # same to cron interval
jobs:
check:
runs-on: ubuntu-latest
steps:
...
- name: Check for updates
run: |
+ LATEST_COMMIT_UNIX_TIME=$((git log -1 --format=%ct))
+ CUREENT_TIME=$(date +%s)
+ DIFF=$((CUREENT_TIME - LATEST_COMMIT_UNIX_TIME))
+ IS_EXIST_NEW_COMMIT=$(($CUREENT_TIME - ${{ env.INTERVEL_SEC }} - $LATEST_COMMIT_UNIX_TIME < 0))
+ echo $IS_EXIST_NEW_COMMIT
上記のワークフローにより、更新要否が変数 IS_EXIST_NEW_COMMIT
に格納されています。次のステップでこの変数を使用可能とするように、GitHub Actions の仕組みを使用しましょう。
...
jobs:
check:
runs-on: ubuntu-latest
steps:
...
- name: Check for updates
+ id: check
run: |
LATEST_COMMIT_UNIX_TIME=$((git log -1 --format=%ct))
CUREENT_TIME=$(date +%s)
DIFF=$((CUREENT_TIME - LATEST_COMMIT_UNIX_TIME))
IS_EXIST_NEW_COMMIT=$(($CUREENT_TIME - ${{ env.INTERVEL_SEC }} - $LATEST_COMMIT_UNIX_TIME < 0))
- echo $IS_EXIST_NEW_COMMIT
+ echo "is_exist_new_commit=$IS_EXIST_NEW_COMMIT" >> $GITHUB_OUTPUT
ステップに id
を設定し $GITHUB_OUTPUT
に出力したい変数を echo で出力することで後続ジョブで使用することができます。詳細は以下を参考にしてください。
今回の場合であれば、後続ジョブで steps.check.outputs.is_exist_new_commit
を利用することでチェック結果を使用することができます。
チェックフラグを確認し、実処理を呼び出す
今回のポイントは、前ステップで判断した結果に応じて処理を分岐する部分です。その後の実処理の呼び出しはおまけなので、用途に応じてカスタマイズをしてください。最初に前ステップで判断した結果を使用します、前ステップで判定結果を変数に出力したので、それを if
条件で使用します。
...
jobs:
check:
runs-on: ubuntu-latest
steps:
...
- name: Check for updates
id: check
run: |
...
echo "is_exist_new_commit=$IS_EXIST_NEW_COMMIT" >> $GITHUB_OUTPUT
+ - name: if check flag is true, request to update
+ if: ${{ steps.check.outputs.is_exist_new_commit != '0' }}
+ uses: # todo (uses, run etc)
上記のように if
条件で、ステップ自体を実行するかどうか判断することができます。
今回の実処理は、バージョンアップをするために別のワークフローを呼び出します。そのために convictional/trigger-workflow-and-wait@vX.Y.Z
を利用します。
...
jobs:
check:
runs-on: ubuntu-latest
steps:
...
- name: if check flag is true, request to update
if: ${{ steps.check.outputs.is_exist_new_commit != '0' }}
- uses: # todo (uses, run etc)
+ uses: convictional/trigger-workflow-and-wait@v1.6.5
+ with:
+ owner: (owner_name)
+ repo: (repo_name)
+ workflow_file_name: (workflow_filename)
+ github_token: ${{ secrets.GITHUB_TOKEN }}
以上で、ワークフロー全体の実装が完了しました。少しだけ改善を加えて完成させましょう。
改善: チェック対象ディレクトリ/ファイルの絞り込み
以前のセクションで更新有無をチェックするステップを追加しましたが、このステップは全てのフォルダをチェック対象にしています。今回指定した実処理のように自動で更新を加えるような処理がトリガーで実行される場合、それによって積まれたコミットもチェックしてしまいます。こういった事態を避けるために、チェックする対象のフォルダを絞り込みます。
git
コマンドの引数に指定することで対象フォルダを選択することができるのでこちらを利用しましょう。-- (フォルダパス)
とコマンドに加えることで絞り込みができます、今回は src
フォルダのみをターゲットとしました。
...
env:
INTERVEL_SEC: 86400
+ TARGET_PATH: src
jobs:
check:
runs-on: ubuntu-latest
steps:
...
- name: Check for updates
id: check
run: |
- LATEST_COMMIT_UNIX_TIME=$((git log -1 --format=%ct))
+ LATEST_COMMIT_UNIX_TIME=$((git log -1 --format=%ct -- ${{ env.TARGET_PATH }}))
CUREENT_TIME=$(date +%s)
DIFF=$((CUREENT_TIME - LATEST_COMMIT_UNIX_TIME))
IS_EXIST_NEW_COMMIT=$(($CUREENT_TIME - ${{ env.INTERVEL_SEC }} - $LATEST_COMMIT_UNIX_TIME < 0))
echo "is_exist_new_commit=$IS_EXIST_NEW_COMMIT" >> $GITHUB_OUTPUT
...
改善: タイマー実行
今回実装したワークフローは "1日" 以内に更新があったかどうかをチェックするようにしています。このワークフロー自体も1日単位で自動実行するようにしてみましょう。
トリガーさせるイベントに schedule
を設定することで時間間隔による定期実行を組み込むことができます。この時間設定は cron
形式で行います。詳細は下記を参考にしてください。
1日単位で実行するために下記のように設定してみましょう。
name: Check for Version up
+on:
+ schedule:
+ - cron: '0 0 * * *'
env:
...
終わりに
この記事では、定期的にリポジトリの変更をチェックして何らかの処理をトリガーする GitHub Actions ワークフローを構築する方法について説明しました。
定期的なリポジトリの変更の監視は、自動化されたタスクの実行や適切なタイミングでの処理の実行に役立つケースがあると思います。
ぜひ利用してみてください。
Discussion