<CodeLearn/>
デプロイ レッスン3

CI/CD入門

GitHub Actionsでテストとデプロイを自動化しよう

CI/CDとは?

CI(Continuous Integration / 継続的インテグレーション)は、 コードの変更を頻繁にメインブランチに統合し、自動でテストを実行する手法です。CD(Continuous Delivery / 継続的デリバリー)は、 テストに通ったコードを自動的に本番環境にデプロイする仕組みです。

CI/CDの流れ

コード変更 → push → 自動テスト → 自動ビルド → 自動デプロイ
   ↑                    ↓
   └──── 失敗通知 ←─── テスト失敗で停止

CI(継続的インテグレーション):
  1. 開発者がコードをpush
  2. 自動でリント・テスト・ビルドを実行
  3. 問題があれば開発者に通知

CD(継続的デリバリー/デプロイ):
  4. テスト通過後、ステージング環境に自動デプロイ
  5. 承認後(または自動で)本番環境にデプロイ

CI/CDを導入することで、バグの早期発見、デプロイの高速化、手動作業によるミスの防止が実現できます。

GitHub Actionsの基本

GitHub Actionsは、GitHubに組み込まれたCI/CDサービスです。 リポジトリの.github/workflows/ディレクトリにYAMLファイルを置くだけで自動化が設定できます。

パブリックリポジトリでは無料、プライベートリポジトリでも月2,000分の無料枠があります。

Workflow(ワークフロー)

自動化の全体定義。YAMLファイル1つが1ワークフロー。

Event(イベント/トリガー)

ワークフローを起動する条件(push、PR作成、スケジュールなど)。

Job(ジョブ)

ワークフロー内の処理グループ。並列または順次実行が可能。

Step(ステップ)

ジョブ内の個々のタスク。コマンド実行やアクションの利用。

ワークフローYAMLの書き方

実際のワークフローファイルを見てみましょう。Next.jsアプリのCI設定例です。

# .github/workflows/ci.yml
name: CI

# トリガー:mainブランチへのpushとPR
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  # リント・型チェック・テスト
  test:
    runs-on: ubuntu-latest

    steps:
      # リポジトリのコードを取得
      - name: Checkout code
        uses: actions/checkout@v4

      # Node.jsのセットアップ
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "20"
          cache: "npm"

      # 依存関係のインストール
      - name: Install dependencies
        run: npm ci

      # リント
      - name: Run linter
        run: npm run lint

      # 型チェック
      - name: Type check
        run: npx tsc --noEmit

      # テスト
      - name: Run tests
        run: npm test

      # ビルド確認
      - name: Build
        run: npm run build

usesで公開されたアクション(再利用可能な処理)を利用し、runでシェルコマンドを実行します。cache: "npm"で依存関係のキャッシュが効き、2回目以降のインストールが高速になります。

トリガー(イベント)の種類

ワークフローを起動するトリガーはさまざまな種類があります。 用途に応じて適切なトリガーを選びましょう。

# pushトリガー(特定ブランチ)
on:
  push:
    branches: [main, develop]
    paths:
      - "src/**"        # srcディレクトリの変更時のみ
      - "!*.md"         # Markdownの変更は除外

# PRトリガー
on:
  pull_request:
    branches: [main]
    types: [opened, synchronize, reopened]

# スケジュールトリガー(cron式)
on:
  schedule:
    - cron: "0 9 * * 1"  # 毎週月曜の9:00 UTC

# 手動トリガー
on:
  workflow_dispatch:
    inputs:
      environment:
        description: "デプロイ先"
        required: true
        default: "staging"
        type: choice
        options:
          - staging
          - production

# タグトリガー(リリース時)
on:
  push:
    tags:
      - "v*"  # v1.0.0 のようなタグ

pathsフィルターを使えば、 変更されたファイルに応じてワークフローを実行するかどうかを制御できます。 ドキュメントの変更でCIが走るのを防ぐ場合などに便利です。

自動テストの実行

CI環境でテストを自動実行し、問題があればPRにフィードバックを返す設定例です。 複数のNode.jsバージョンでテストを実行するマトリックス戦略も活用できます。

# .github/workflows/test.yml
name: Test

on:
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest

    # マトリックス戦略:複数バージョンでテスト
    strategy:
      matrix:
        node-version: [18, 20, 22]

    steps:
      - uses: actions/checkout@v4

      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: "npm"

      - run: npm ci
      - run: npm test -- --coverage

      # テストカバレッジをPRにコメント
      - name: Upload coverage
        if: matrix.node-version == 20
        uses: actions/upload-artifact@v4
        with:
          name: coverage-report
          path: coverage/

  # E2Eテスト(テスト完了後に実行)
  e2e:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: "20"
          cache: "npm"
      - run: npm ci
      - run: npx playwright install --with-deps
      - run: npm run build
      - run: npx playwright test

needsキーワードでジョブ間の依存関係を定義し、 ユニットテストが通ってからE2Eテストを実行するという順序制御ができます。

自動デプロイの設定

テストが通ったら自動的に本番環境にデプロイするワークフローを構築しましょう。 以下はVercelへの自動デプロイの例です。

# .github/workflows/deploy.yml
name: Deploy

on:
  push:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: "20"
          cache: "npm"
      - run: npm ci
      - run: npm run lint
      - run: npm test
      - run: npm run build

  deploy:
    needs: test  # テスト成功後にデプロイ
    runs-on: ubuntu-latest

    # 環境(GitHub上でシークレットを管理)
    environment:
      name: production
      url: https://myapp.vercel.app

    steps:
      - uses: actions/checkout@v4

      - name: Deploy to Vercel
        uses: amondnet/vercel-action@v25
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
          vercel-args: "--prod"

シークレットはGitHubリポジトリの Settings > Secrets and variables > Actions から設定します。コードに直接書かないようにしましょう。

# シークレットの使い方
# リポジトリ設定で以下を登録:
#   VERCEL_TOKEN      : Vercelのアクセストークン
#   VERCEL_ORG_ID     : Vercelの組織ID
#   VERCEL_PROJECT_ID : VercelのプロジェクトID

# ワークフロー内でシークレットを参照
${{ secrets.VERCEL_TOKEN }}

# 環境変数として使う場合
env:
  DATABASE_URL: ${{ secrets.DATABASE_URL }}

まとめ

  • CIはコード変更ごとに自動テスト、CDは自動デプロイを実現する手法
  • GitHub Actionsはリポジトリ内のYAMLファイルでCI/CDを定義できる
  • Workflow、Job、Stepの階層構造でパイプラインを構成する
  • push、PR、スケジュール、手動など多様なトリガーが利用できる
  • マトリックス戦略で複数バージョンのテストを並列実行できる
  • シークレットでAPIキーやトークンを安全に管理する