GitHub Actionsの実行制限を回避!「Conditional Execution」と「Continue-on-error」を組み合わせた堅牢なワークフロー設計
こんにちは。テックリードの私だ。
日々、プルリクエストの山と格闘し、CI/CDの緑色のビルドアイコンに一喜一憂していることだろう。
さて、君たちのプロジェクトではこんな課題に直面していないか?
- 「Flaky Test(不安定なテスト)」のせいで、本質的ではないエラーでデプロイが止まる。
- Linterのわずかな警告でビルド全体が落ち、開発者のフローが完全に分断される。
- GitHub Actionsの無料枠・同時実行数の制限に引っかかり、キューにジョブが溜まっていく。
GitHub Actionsは非常に強力だが、デフォルトの挙動のままでは「融通の利かない厳格すぎる検問所」になってしまう。開発スピードを極限まで高めつつ、プロダクトの品質を担保するためには、「失敗を許容する勇気」と「実行を制御する知性」が必要だ。
今回は、`continue-on-error` と条件分岐(`if`)を完璧に組み合わせ、CI/CDパイプラインを「止まらない、しかし緩まない」要塞へと進化させる実践テクニックを伝授しよう。
—
1. なぜ「`continue-on-error` 単体」では地獄を見るのか?
まず、GitHub Actionsの基本機能である `continue-on-error: true` についておさらいしておこう。
これは文字通り、そのジョブやステップが失敗(Exit Code != 0)しても、ワークフロー全体のステータスを「成功(または中立)」扱いにして後続の処理を続行させる機能だ。
悪い例:ただ continue-on-error を貼っただけ
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run strict linter
run: npm run lint:strict
continue-on-error: true # 失敗しても次に進むが…
このアプローチには致命的な欠陥がある。「失敗したという事実が握りつぶされ、後続のジョブが『すべて正常に完了した』という誤った前提で動き出す」点だ。
例えば、Linterがエラーを吐いたにもかかわらず、`continue-on-error: true` のおかげで後続のデプロイジョブが走り出し、結果として汚染されたコードが本番にデプロイされる……なんて大事故になりかねない。
私たちが目指すべきは、「失敗を検知する(Observability)」ことと、「処理を強制停止させない(Resilience)」ことの完全な分離だ。
—
2. 究極の解:「Conditional Execution(条件分岐)」との融合
この問題を解決するのが、`continue-on-error` と `steps.
- `outcome`: `continue-on-error` の結果を反映したステータス(`success`, `failure`, `cancelled`, `skipped`)
- `conclusion`: `continue-on-error` を考慮した最終的なステータス
これらを利用することで、「あえて失敗を許容するが、その後の振る舞いをコードで完全にコントロールする」という高度なパイプライン制御が可能になる。
実践:Flakyなテストと必須タスクのスマートな分離
以下のワークフロー設定を見てほしい。これは、外部APIに依存していてどうしても一定確率で失敗する「E2Eテスト」を安全にハンドリングしつつ、チームにアラートを飛ばすベストプラクティスだ。
name: Resilient CI Pipeline
on:
pull_request:
branches: [ main ]
jobs:
e2e-flaky-tests:
runs-on: ubuntu-latest
# ジョブ自体の失敗を許容しつつ、後続へステータスを渡すための出力定義を行う
outputs:
test_status: ${{ steps.e2e.outcome }}
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: ’20’
cache: ‘npm’
- name: Install Dependencies
run: npm ci
# 【核心】不安定なE2Eテスト。失敗してもパイプラインを即死させない
- name: Run Flaky E2E Tests
id: e2e
run: npm run test:e2e
continue-on-error: true
# 【核心】テストが「失敗」した場合のみ、Slackやログへ警告を残す(処理は止めない)
- name: Notify Test Flakiness (Non-Blocking)
if: steps.e2e.outcome == ‘failure’
run: |
echo “::warning::E2Eテストが失敗しましたが、continue-on-errorによりビルドを継続します。”
# ここにSlack Webhook通知スクリプトなどを置くことも可能
# 後続の必須ジョブ
build-and-pack:
needs: e2e-flaky-tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build Application
run: |
echo “ビルド処理を実行…”
npm run build
- name: Report Summary
if: always()
run: |
echo “E2E Test Outcome: ${{ needs.e2e-flaky-tests.outputs.test_status }}”
echo “ビルドプロセスが正常に完了しました。”
この構成の美しさは、「テストが落ちてもビルド・デプロイの検証までは進められるが、テストが失敗したという事実(`test_status`)は後続のジョブやダッシュボードに確実に伝播する」という点にある。
—
3. プロが実践するチーム開発のハック&設定共有ルール
ここからは、日々の開発スピードを爆発的に高めるための、現場で培った実践知(ハック)を共有しよう。
① 開発効率を上げる隠れたキーボードショートカット
ブラウザ版のGitHub Actions画面(特に `Actions` タブ)でイライラしたことはないか?
- `f` キー または `/` キー: リポジトリ内やActionsの検索バーに一瞬でフォーマットを合わせる。
- ワークフローのログ画面で `Shift + J` / `Shift + K` (※拡張機能やVimバインド環境によるが、ブラウザのコンソール操作等と合わせて)ログの展開・折りたたみをマスターすると、デバッグスピードが3倍になる。
② 絶対入れるべきVS Code神プラグイン
ローカルでGitHub Actionsを書く際、シンタックスエラーでプッシュ&プレビューを繰り返すのは時間の無駄だ。
- 「GitHub Actions」 (Extension ID: `GitHub.vscode-github-actions`):
YAMLの補完はもちろん、ワークフローの構文チェックや、ローカルからのトリガー実行支援までやってくれる。これなしでActionsを書くのは、目隠しで高速道路を走るようなものだ。
- 「YAML」 (Extension ID: `redhat.vscode-yaml`):
JSON Schemaを紐付けることで、GitHub Actionsのスキーマバリデーションをリアルタイムで行えるように設定しておこう。
③ チーム開発におけるワークフローのDRY原則(再利用の極意)
プロジェクトが増えてくると、似たようなCI設定が乱立する。これを防ぐために Reusable Workflows(再利用可能ワークフロー) を `.github/workflows` の共通リポジトリ(または同一リポジトリ内)に切り出し、今回紹介した `continue-on-error` のロジックをカプセル化せよ。
.github/workflows/_reusable-lint.yml (共通化されたLinterワークフロー)
name: Reusable Lint
on:
workflow_call:
inputs:
strict-mode:
required: false
type: boolean
default: false
outputs:
lint_outcome:
description: “Linterの実行結果”
value: ${{ jobs.lint.outputs.outcome }}
jobs:
lint:
runs-on: ubuntu-latest
outputs:
outcome: ${{ steps.run-lint.outcome }}
steps:
- uses: actions/checkout@v4
- name: Run Linter
id: run-lint
run: npm run lint
continue-on-error: ${{ !inputs.strict-mode }}
呼び出し側からは、引数一つで「厳格モード(エラーで即停止)」と「許容モード(警告のみで継続)」を切り替えられる。これにより、組織全体でCIのメンテナンスコストを劇的に削減できる。
—
4. まとめ:CI/CDは「開発者を縛る鎖」ではなく「加速させる翼」であるべきだ
ツールの仕様に振り回されるな。ツールをハックし、自分たちの開発フローに奉仕させろ。
今回紹介した `continue-on-error` と `if` 条件分岐を組み合わせたConditional Executionは、「機械的な厳格さ」と「人間的な柔軟性」を両立させるための最強の武器だ。
- 不安定な外部要因による無駄なビルド失敗を排除し、GitHub Actionsの実行枠(Minutes)を節約する。
- 失敗を隠蔽せず、コンテキストを持った状態で後続の処理や通知に繋げる。
この設計を取り入れた瞬間から、あなたのチームのCI/CDパイプラインは単なる「自動テスト装置」から、「チームの生産性を極限まで引き出す高速道路」へと生まれ変わるはずだ。
さあ、今すぐ `yaml` ファイルを開き、無駄に止まっているジョブたちを解放してこい。