できない.dev

GitHub Actions の if 条件どおりにステップを実行できない

if が効かないときは、前ステップ失敗時に暗黙で付く success() 条件、文字列 'false' を真と評価する型の取り違え、! で始まる式のクオート漏れを順に疑う。
failure() / always() の明示と式の ${{ }} 囲みで大半は解決する。

#github-actions#if#conditional#expressions#workflow

公開:

要約

GitHub Actions の if 条件が効かない原因は大きく 3 つです。
(1) status 関数を含まない if には success() が暗黙で AND されるため、前のステップが失敗すると条件を満たしても実行されない。
(2) ! で始まる式はクオートか ${{ }} で囲まないと YAML として壊れる。
(3) 式の評価では空文字以外の文字列はすべて真なので、'false' という文字列も真になる。
詳細は式の公式ドキュメントを参照してください。

よくある原因

  1. 暗黙の success(): if: github.event_name == 'push' のような条件だけを書いた場合、直前までのステップがすべて成功していることが前提条件として追加される。
  2. ! のクオート漏れ: YAML では行頭の ! がタグ記法と解釈されるため、if: !startsWith(...) はパースに失敗するか意図しない動作になる。
  3. 文字列と真偽値の取り違え: workflow_dispatch の inputs や outputs 経由の値は文字列で渡ることが多く、if: inputs.dry_run は値が 'false' でも真になる。
  4. job レベル if での env 参照: env コンテキストはジョブレベルの if では利用できず、常に偽相当の評価になってジョブごとスキップされる。
  5. ref の形式違い: ブランチ判定は refs/heads/ プレフィックス込みで比較する必要がある。

解決策

1. 失敗時にも動かす条件を明示する

steps:
  - name: Notify on failure
    if: failure()
    run: ./notify.sh
  - name: Cleanup
    if: always()
    run: ./cleanup.sh

2. 式全体を ${{ }} で囲む

  - name: Build (except tags)
    if: ${{ !startsWith(github.ref, 'refs/tags/') }}
    run: npm run build

クオートで if: "!startsWith(...)" と書いても同じ効果があります。

3. 文字列は明示的に比較する

  - name: Deploy
    if: ${{ inputs.dry_run == 'false' }}
    run: ./deploy.sh

fromJSON(inputs.dry_run) で真偽値へ変換する方法もあります。
型の扱いはワークフロー構文のリファレンスに整理されています。

この記事は役立ちましたか?