1.この記事を書こうと思った背景

on:
  schedule:
    - cron: '0 17 1-7 * 1'

2.長いので結論を書く

Github Actions の cron で採用されている POSIX 規格の crontab の構文 では日時と曜日が指定されている場合、日時と曜日のOR判定となることが正しい

  • if either the month or day of month is specified as an element or list, and the day of week is also specified as an element or list, then any day matching either the month and day of month, or the day of week, shall be matched.

  • (Google翻訳) 月または日のいずれかが要素またはリストとして指定され、曜日も要素またはリストとして指定されている場合、月と日、または曜日のいずれかに一致する任意の日、一致するものとします。

  • 出所:POSIX 規格の crontab の構文
  • つまり、冒頭で一例として書いた cron の場合、以下のいずれかの条件に合致する場合、Schedule event は実行されることとなる
    • 毎月1日〜7日の17:00(UTC)
    • 毎週月曜日の17:00(UTC)
on:
  schedule:
    - cron: '0 17 1-7 * 1'

それでも Workflow を日時と曜日いずれも指定して実行する方法はある!

  • Github Actions の schedule では日時だけ指定し、曜日指定は Job で date コマンドの結果を使うようにする
  • 採用を見送ったこと
    • success() を使って後続の Job の実行制御をする
      • Job が成功した場合のみ、後続の Job を実行する
  • job と step どちらにも使える実行を制御する書き方、片方にしか使えない書き方の整理(こちらは別記事にて)

3.日時指定と曜日指定のやりかたの解説

  • 日時指定はscheduleでやる
on:
  schedule:
    - cron: 0 17 1-7 * *  # At 02:00 am on every day-of-month from 1 through 7. (JST)
  • 曜日指定は Job で date コマンドの結果を使う
    • date コマンドの結果が実行したい曜日である場合のみ、後続の Job を実行するようにした
jobs:
  date:
    name: Run date command
    runs-on: ubuntu-latest
    steps:
      - run: echo "::set-output name=today::$(LANG=C date '+%A')"
        id: day-of-week
    outputs:
      day-of-week: ${{ steps.day-of-week.outputs.today }}

  # Run only Monday 
  run-only-monday:
    name: Playground Job
    runs-on: ubuntu-latest
    needs: date
#  直前の "date" Job で outputs を使って date コマンドの結果を保持し、実行したい Monday (月曜日)である場合のみ "run-only-monday" Job を実行
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idoutputs
    if: needs.date.outputs.day-of-week == 'Monday'
    steps:
      - name: echo day-of-week
        run: echo ${{ needs.date.outputs.day-of-week }}
      # Job レベルで実行制御しているので複数の step をまとめて実行するかしないか決めている
      - name: echo hoge 
        run: echo "hoge"

3.やってみたけど採用を見送ったこと

  • success() を使って後続のJobの実行制御をする
jobs:
  check-if-today-is-monday:
    name: Check if today is Monday
    runs-on: ubuntu-latest
    steps:
      - run: if [ $(date +%u) -ne 1 ]; then exit 1; fi  ## このstepが失敗すれば (exit 1 となれば)、後続の step と job は実行されない
      - name: Run only Monday
        if: success()
        run: echo "hoge"

  # Run only Monday
  run-only-monday:
    name: Playground Job
    runs-on: ubuntu-latest
    needs: check-if-today-is-monday
    if: success()
    steps:
      - name: echo hoge
        run: echo "hoge"

3-1.採用を見送ったワケ

なぜ success() を使って後続の Job の実行制御をする方法の採用を見送ったか?それは Action の成否を確認するために Job のログを追わなければならないからだ。これはめんどくさい。

そこでActionの実行結果の見通しを損なわいようにするために、Jobの実行結果に応じて後続のJobを実行制御をすることにした。

# 後続のJobを実行制御をする箇所のみ抜粋

  # Run only Monday 
  run-only-monday:
    name: Playground Job
    runs-on: ubuntu-latest
    needs: date
#  直前の "date" Job で outputs を使って date コマンドの結果を保持し、実行したい Monday (月曜日)である場合のみ "run-only-monday" Job を実行
    if: needs.date.outputs.day-of-week == 'Monday'

4.Workflow 全体

まとめとして、Workflow 全体を書いておく。

name: Complex cron expression

on:
  schedule:
    - cron: 0 17 1-7 * *  # At 02:00 am on every day-of-month from 1 through 7. (JST)

jobs:
  date:
    name: Run date command
    runs-on: ubuntu-latest
    steps:
# if 文を使って date コマンドの結果を判定せず、 date '+%A' を使えばいい
#      - run: if [ $(date +%u) -eq 4 ]; then echo "::set-output name=today::Monday"; fi
      - run: echo "::set-output name=today::$(LANG=C date '+%A')"
        id: day-of-week
    outputs:
      day-of-week: ${{ steps.day-of-week.outputs.today }}

  # Run only Monday 
  run-only-monday:
    name: Playground Job
    runs-on: ubuntu-latest
    needs: date
#  直前の "date" Job で outputs を使って date コマンドの結果を保持し、実行したい Monday (月曜日)である場合のみ "run-only-monday" Job を実行
    if: needs.date.outputs.day-of-week == 'Monday'
    steps:
      - name: echo day-of-week
        run: echo ${{ needs.date.outputs.day-of-week }}
      - name: echo hoge 
        run: echo "hoge"

5.備考

on:
  schedule:
# on weekday
    - cron: '15 10 * * 1-5' # At 07:15 pm on every day-of-week from Monday through Friday.

6.参考