EXERCISE 60分

演習:初めてのCI/CDワークフロー

ストーリー

「座学はここまでだ。実際にワークフローを作ってみよう」

木村先輩がGitHubリポジトリを用意してくれた。

「Node.jsのWebアプリケーションプロジェクトがある。 これに対して、CI/CDワークフローをゼロから構築してくれ。 PRを出した時にテストが走り、mainにマージされたらビルドされる。 段階的に進めていこう」


演習の概要

Node.jsプロジェクトに対して、GitHub Actionsワークフローを構築してください。

プロジェクト構成

my-webapp/
├── .github/
│   └── workflows/        ← ここにワークフローを作成
├── src/
│   ├── index.ts
│   ├── app.ts
│   └── utils/
│       └── validator.ts
├── tests/
│   ├── app.test.ts
│   └── validator.test.ts
├── package.json
├── tsconfig.json
└── README.md

package.jsonのscripts

json
{
  "scripts": {
    "lint": "eslint src/ --ext .ts",
    "typecheck": "tsc --noEmit",
    "test": "jest --coverage",
    "build": "tsc && node -e \"console.log('Build successful')\"",
    "start": "node dist/index.js"
  }
}

課題1: CIワークフローの作成

PRが作成・更新された時に、Lint、型チェック、テストを実行するワークフローを作成してください。

要件

  • ファイル名: .github/workflows/ci.yml
  • トリガー: pull_request (mainブランチへのPR)
  • Node.js バージョン: 20
  • 実行するステップ: checkout → setup-node → npm ci → lint → typecheck → test
  • タイムアウト: 15分
<details> <summary>解答例(自分で実装してから確認しよう)</summary>
yaml
# .github/workflows/ci.yml
name: CI

on:
  pull_request:
    branches: [ main ]

permissions:
  contents: read

jobs:
  ci:
    name: Lint, Type Check & Test
    runs-on: ubuntu-latest
    timeout-minutes: 15

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run ESLint
        run: npm run lint

      - name: Type check
        run: npm run typecheck

      - name: Run tests
        run: npm test
</details>

課題2: ビルド & アーティファクトの保存

課題1のCIが成功した後に、ビルドを行いアーティファクトとして保存するワークフローを追加してください。

要件

  • CIジョブ成功後にビルドジョブを実行(needs を使用)
  • ビルド成果物(dist/)をアーティファクトとしてアップロード
  • アーティファクトの保持期間: 7日
<details> <summary>解答例(自分で実装してから確認しよう)</summary>
yaml
# .github/workflows/ci.yml(課題1を拡張)
name: CI

on:
  pull_request:
    branches: [ main ]

permissions:
  contents: read

jobs:
  lint-and-test:
    name: Lint, Type Check & Test
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run ESLint
        run: npm run lint

      - name: Type check
        run: npm run typecheck

      - name: Run tests
        run: npm test

  build:
    name: Build
    needs: lint-and-test
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Build
        run: npm run build

      - name: Upload build artifact
        uses: actions/upload-artifact@v4
        with:
          name: build-output
          path: dist/
          retention-days: 7
</details>

課題3: mainブランチへのpush時のCD

mainブランチにマージされた時に、ビルド → デプロイ(模擬)を実行するワークフローを作成してください。

要件

  • ファイル名: .github/workflows/cd.yml
  • トリガー: push (mainブランチのみ)
  • ジョブ構成: test → build → deploy
  • deploy ジョブは build の成功後に実行
  • deploy ジョブでは echo でデプロイメッセージを出力
  • deploy ジョブには環境名(environment: production)を設定
<details> <summary>解答例(自分で実装してから確認しよう)</summary>
yaml
# .github/workflows/cd.yml
name: CD

on:
  push:
    branches: [ main ]

permissions:
  contents: read

env:
  NODE_VERSION: '20'

jobs:
  test:
    name: Run Tests
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run tests
        run: npm test

  build:
    name: Build Application
    needs: test
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Build
        run: npm run build

      - name: Upload build artifact
        uses: actions/upload-artifact@v4
        with:
          name: production-build
          path: dist/
          retention-days: 3

  deploy:
    name: Deploy to Production
    needs: build
    runs-on: ubuntu-latest
    environment: production
    timeout-minutes: 10
    steps:
      - name: Download build artifact
        uses: actions/download-artifact@v4
        with:
          name: production-build
          path: dist/

      - name: Deploy
        run: |
          echo "=========================================="
          echo "  Deploying to production environment"
          echo "  Commit: ${{ github.sha }}"
          echo "  Actor:  ${{ github.actor }}"
          echo "  Time:   $(date -u '+%Y-%m-%d %H:%M:%S UTC')"
          echo "=========================================="
          echo "Deploying files from dist/..."
          ls -la dist/
          echo "Deployment complete!"
</details>

課題4: 手動実行ワークフロー

緊急時に手動でデプロイできるワークフローを作成してください。

要件

  • ファイル名: .github/workflows/manual-deploy.yml
  • トリガー: workflow_dispatch
  • 入力パラメータ: environment(staging/production の選択)、version(文字列)
  • 選択した環境とバージョンに応じたデプロイメッセージを出力
<details> <summary>解答例(自分で実装してから確認しよう)</summary>
yaml
# .github/workflows/manual-deploy.yml
name: Manual Deploy

on:
  workflow_dispatch:
    inputs:
      environment:
        description: 'Deploy target environment'
        required: true
        type: choice
        options:
          - staging
          - production
      version:
        description: 'Version to deploy (e.g., v1.2.3)'
        required: true
        type: string

permissions:
  contents: read

jobs:
  confirm:
    name: Confirm Deployment
    runs-on: ubuntu-latest
    steps:
      - name: Display deployment info
        run: |
          echo "============================================"
          echo "  Manual Deployment Request"
          echo "============================================"
          echo "  Environment: ${{ inputs.environment }}"
          echo "  Version:     ${{ inputs.version }}"
          echo "  Triggered by: ${{ github.actor }}"
          echo "  Time: $(date -u '+%Y-%m-%d %H:%M:%S UTC')"
          echo "============================================"

  deploy:
    name: Deploy to ${{ inputs.environment }}
    needs: confirm
    runs-on: ubuntu-latest
    environment: ${{ inputs.environment }}
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          ref: ${{ inputs.version }}

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install & Build
        run: |
          npm ci
          npm run build

      - name: Deploy
        run: |
          echo "Deploying version ${{ inputs.version }} to ${{ inputs.environment }}..."
          echo "Deployment successful!"
</details>

達成度チェック

課題内容完了
課題1CIワークフロー(Lint + テスト)[ ]
課題2ビルド & アーティファクト保存[ ]
課題3CDワークフロー(テスト → ビルド → デプロイ)[ ]
課題4手動実行ワークフロー[ ]

まとめ

ポイント内容
CIPRトリガーで Lint + テスト + ビルドを自動実行
CDmainへのpushでテスト → ビルド → デプロイを自動化
アーティファクトジョブ間でビルド成果物を受け渡し
手動実行workflow_dispatch で緊急時の手動デプロイに対応

チェックリスト

  • CI用ワークフローを作成できた
  • needs でジョブの依存関係を設定できた
  • アーティファクトのアップロード/ダウンロードを実装できた
  • CDワークフローでデプロイジョブを構成できた
  • workflow_dispatch で手動実行ワークフローを作成できた

次のステップへ

演習が完了したら、Step 2 のチェックポイントクイズに挑戦しましょう。


推定所要時間: 60分