コンテンツにスキップ

Design

Context

現在のGitHub Actionsワークフロー構成には以下の問題がある:

  • test.yml: PR to main と push で発火し、テストを実行
  • deploy.yml: すべてのブランチの push で発火し、test/lint/deployを実行
  • 結果: PR to main では両ワークフローが発火し、テストが重複実行される(3-4ジョブが並行実行)
  • パスフィルターなし: ドキュメントのみの変更でもフルパイプラインが実行される
  • 存在しないファイル参照: deploy.ymlが scripts/seed/index.json を参照しているが、このファイルは存在しない

この問題を解決するため、3ファイル構成に再構築し、責務を明確に分離する。

Goals / Non-Goals

Goals:

  • CI効率の向上: 重複実行の完全排除、適切なパスフィルターによる最適化
  • 明確な責務分離: CI(品質保証)、本番デプロイ、開発デプロイの3つに分離
  • リソース最適化: feature branchのPRがない限り、CIを実行しない
  • コスト削減: GitHub Actionsの実行時間とジョブ数を削減
  • 拡張性: 将来のE2Eテスト統合に備えた構造(deploy-dev.ymlに拡張ポイント)

Non-Goals:

  • E2Eテストの実装: 今回は準備のみ、実装は将来の課題
  • デプロイ先の変更: Azure Blob Storageへのデプロイは継続
  • ビルドプロセスの変更: 既存のViteビルド設定を維持
  • ワークフロー以外のCI/CD改善: パッケージマネージャーやキャッシュ戦略の変更は対象外

Decisions

1. 3ファイル構成の採用

決定: ci.yml + deploy.yml + deploy-dev.yml の3ファイル構成

理由:

  • 責務の明確な分離: CI(品質保証)とデプロイ(環境反映)を完全に分離
  • concurrency制御の粒度向上: CIはPR単位、デプロイは環境単位で制御
  • 可読性と保守性: 各ワークフローの目的が明確で、複雑な条件分岐が不要

代替案:

  • 1ファイルで複雑な条件分岐: 可読性・保守性が低下、concurrency制御が困難
  • 2ファイル構成(CI + Deploy統合): dev/prod環境の制御が複雑化

2. ci.ymlでのジョブ並列実行

決定: test/lint/buildの3ジョブを並列実行(needs なし)

理由:

  • 実行時間短縮: 最長ジョブの時間のみで完了(テストが通常最長)
  • ジョブ間の依存関係なし: 各ジョブは独立して実行可能
  • 早期フィードバック: lintやbuildエラーを待たずに検出

代替案:

  • 直列実行: 実行時間が長くなり、フィードバック速度が低下

3. パスフィルターの厳格化

決定: src/**, tests/**, e2e/**, 設定ファイル(package.json, pnpm-lock.yaml等)のみをトリガー対象に

理由:

  • 不要な実行を防ぐ: ドキュメント変更(README.md等)でCIが走らない
  • フィードバック速度向上: 実際にコード品質に影響する変更のみを検証
  • コスト削減: ムダなGitHub Actionsの実行を削減

代替案:

  • パスフィルターなし: すべての変更でCIが実行され、リソース浪費
  • 緩いフィルター: ドキュメント変更も含めるとムダな実行が残る

4. deploy-dev.ymlを手動トリガーのみに

決定: workflow_dispatch のみで発火、自動トリガーなし

理由:

  • 開発環境の制御性向上: 意図しないデプロイを防止
  • 将来のE2Eテスト統合の準備: 手動実行→E2Eテスト→承認のフローを想定
  • リソース節約: feature branchの push で開発デプロイが走らない

代替案:

  • feature branchの push で自動デプロイ: ムダな実行が多く、制御が困難
  • PR to main で自動デプロイ: 本番デプロイと重複し、混乱を招く

5. concurrency設定の戦略

決定:

  • ci.yml: group: ci-${{ github.ref }}, cancel-in-progress: true → PR単位でグループ化、新しいpushで古い実行をキャンセル
  • deploy.yml: group: deploy-prod, cancel-in-progress: false → 本番デプロイは完全性を保証、キャンセルしない
  • deploy-dev.yml: group: deploy-dev, cancel-in-progress: true → 開発デプロイは最新のみ実行、古い実行はキャンセル可能

理由:

  • CI: 最新のコードのみ検証すればよく、古い実行は不要
  • 本番デプロイ: デプロイの完全性を保証し、中途半端な状態を避ける
  • 開発デプロイ: 最新のデプロイのみ有効で、古い実行はリソース浪費

6. 初期データ配置ステップの削除

決定: deploy.ymlの scripts/seed/index.json 参照ステップを完全削除

理由:

  • ファイルが存在しない: 現在のリポジトリに該当ファイルがなく、ステップが失敗する
  • 不要な処理: データは別の方法で管理されている

代替案:

  • ファイルを作成: 不要なファイルを追加することになり、保守負担が増える

Risks / Trade-offs

[リスク] パスフィルターが厳格すぎると、必要なビルドがスキップされる可能性

  • 軽減策: 設定ファイル(package.json, pnpm-lock.yaml, vite.config.js, .eslintrc.cjs)もフィルターに含める
  • 軽減策: ワークフロー自身(.github/workflows/ci.yml)の変更もトリガーに含める

[リスク] 手動トリガーのみの開発デプロイは利便性が低下

  • 軽減策: GitHub Actions UIから簡単に実行可能
  • 将来の改善: E2Eテスト統合時に自動化フローを再検討

[トレードオフ] 3ファイル構成は管理対象が増える

  • メリット: 明確な責務分離と保守性向上が、ファイル数増加のデメリットを上回る
  • 軽減策: 各ワークフローの目的を明確にドキュメント化

[リスク] ci.ymlとdeploy.ymlの両方がmainブランチで発火し、並列実行される

  • 影響: リソース使用量は変わらないものの、両方の成功が必要となる
  • メリット: CIとデプロイは独立しており、デプロイ失敗時もCI結果は保持される

[リスク] concurrency設定のミスによる意図しないキャンセルやデプロイ競合

  • 軽減策: deploy-prodはキャンセルしない設定で、デプロイの完全性を保証
  • 軽減策: 初回デプロイ後、動作を監視して問題があれば調整