読み込み中...
GitHub Actionsを使用することで、テストからデプロイまでの一連のプロセスを自動化できます。本記事では、Next.jsアプリケーションを例に、実践的なCI/CDパイプラインの構築方法を段階的に解説します。
GitHub Actionsは以下の要素で構成されます。
.github/
└── workflows/
├── ci.yml # CI(継続的インテグレーション)
├── cd.yml # CD(継続的デプロイ)
└── release.yml # リリース自動化
# .github/workflows/ci.yml
name: CI
on:
pull_request:
branches: [main, develop]
push:
branches: [main, develop]
jobs:
lint:
name: ESLint と TypeScript チェック
runs-on: ubuntu-latest
steps:
- name: コードのチェックアウト
uses: actions/checkout@v4
- name: Node.js のセットアップ
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: 依存関係のインストール
run: npm ci
- name: ESLint 実行
run: npm run lint
- name: TypeScript 型チェック
run: npm run type-check
test:
name: ユニットテストと統合テスト
runs-on: ubuntu-latest
steps:
- name: コードのチェックアウト
uses: actions/checkout@v4
- name: Node.js のセットアップ
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: 依存関係のインストール
run: npm ci
- name: ユニットテスト実行
run: npm run test:unit
- name: 統合テスト実行
run: npm run test:integration
- name: カバレッジレポートのアップロード
uses: codecov/codecov-action@v3
with:
files: ./coverage/lcov.info
flags: unittests
name: codecov-umbrella
build:
name: ビルド確認
runs-on: ubuntu-latest
steps:
- name: コードのチェックアウト
uses: actions/checkout@v4
- name: Node.js のセットアップ
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: 依存関係のインストール
run: npm ci
- name: Next.js ビルド
run: npm run build
env:
NEXT_PUBLIC_API_URL: ${{ secrets.NEXT_PUBLIC_API_URL }}
- name: ビルド成果物のキャッシュ
uses: actions/cache@v3
with:
path: .next/cache
key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-nextjs-# .github/workflows/e2e.yml
name: E2E Tests
on:
pull_request:
branches: [main]
schedule:
- cron: '0 2 * * *' # 毎日午前2時に実行
jobs:
e2e:
name: Playwright E2E テスト
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: コードのチェックアウト
uses: actions/checkout@v4
- name: Node.js のセットアップ
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: 依存関係のインストール
run: npm ci
- name: Playwright のインストール
run: npx playwright install --with-deps
- name: Next.js ビルド
run: npm run build
env:
NEXT_PUBLIC_API_URL: ${{ secrets.NEXT_PUBLIC_API_URL }}
- name: E2E テスト実行
run: npm run test:e2e
env:
BASE_URL: http://localhost:3000
- name: テスト失敗時のスクリーンショット保存
uses: actions/upload-artifact@v3
if: failure()
with:
name: playwright-screenshots
path: test-results/
retention-days: 7
- name: Playwright レポートのアップロード
uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 14# .github/workflows/cd.yml
name: CD - Deploy to Vercel
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
deploy-preview:
name: プレビュー環境へのデプロイ
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- name: コードのチェックアウト
uses: actions/checkout@v4
- name: 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 }}
scope: ${{ secrets.VERCEL_ORG_ID }}
- name: デプロイURLをコメント
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '✅ Preview deployed to Vercel\n\nURL: ${{ steps.deploy.outputs.preview-url }}'
})
deploy-production:
name: 本番環境へのデプロイ
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
needs: [lint, test, build] # CIジョブが成功した場合のみ実行
steps:
- name: コードのチェックアウト
uses: actions/checkout@v4
- name: 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'
scope: ${{ secrets.VERCEL_ORG_ID }}
- name: Slack 通知
uses: slackapi/slack-github-action@v1
with:
webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
payload: |
{
"text": "✅ Production deployment successful",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Production Deployment*\n\n✅ Successfully deployed to production\n\nCommit: ${{ github.sha }}\nAuthor: ${{ github.actor }}"
}
}
]
}# .github/workflows/security.yml
name: Security Scan
on:
push:
branches: [main, develop]
schedule:
- cron: '0 3 * * 1' # 毎週月曜日午前3時に実行
jobs:
dependency-scan:
name: 依存関係の脆弱性スキャン
runs-on: ubuntu-latest
steps:
- name: コードのチェックアウト
uses: actions/checkout@v4
- name: npm audit 実行
run: npm audit --audit-level=moderate
continue-on-error: true
- name: Snyk による脆弱性スキャン
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high
code-scan:
name: コードの静的解析
runs-on: ubuntu-latest
steps:
- name: コードのチェックアウト
uses: actions/checkout@v4
- name: CodeQL 初期化
uses: github/codeql-action/init@v2
with:
languages: javascript, typescript
- name: CodeQL 解析
uses: github/codeql-action/analyze@v2
- name: SonarCloud スキャン
uses: SonarSource/sonarcloud-github-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}# .github/workflows/lighthouse.yml
name: Lighthouse CI
on:
pull_request:
branches: [main]
jobs:
lighthouse:
name: Lighthouse パフォーマンステスト
runs-on: ubuntu-latest
steps:
- name: コードのチェックアウト
uses: actions/checkout@v4
- name: Node.js のセットアップ
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: 依存関係のインストール
run: npm ci
- name: Next.js ビルド
run: npm run build
- name: Lighthouse CI 実行
uses: treosh/lighthouse-ci-action@v10
with:
urls: |
http://localhost:3000
http://localhost:3000/about
http://localhost:3000/blog
uploadArtifacts: true
temporaryPublicStorage: true
configPath: './lighthouserc.json'
- name: Lighthouse スコアの確認
run: |
if [ $(cat lhci_reports/manifest.json | jq '.[0].summary.performance') -lt 0.9 ]; then
echo "Performance score is below 90!"
exit 1
fi{
"ci": {
"collect": {
"startServerCommand": "npm start",
"url": [
"http://localhost:3000/",
"http://localhost:3000/about"
],
"numberOfRuns": 3
},
"assert": {
"preset": "lighthouse:recommended",
"assertions": {
"categories:performance": ["error", { "minScore": 0.9 }],
"categories:accessibility": ["error", { "minScore": 0.95 }],
"categories:best-practices": ["error", { "minScore": 0.9 }],
"categories:seo": ["error", { "minScore": 0.95 }]
}
},
"upload": {
"target": "temporary-public-storage"
}
}
}# .github/workflows/release.yml
name: Release
on:
push:
branches: [main]
jobs:
release:
name: セマンティックリリース
runs-on: ubuntu-latest
steps:
- name: コードのチェックアウト
uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: false
- name: Node.js のセットアップ
uses: actions/setup-node@v4
with:
node-version: '20'
- name: 依存関係のインストール
run: npm ci
- name: semantic-release 実行
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npx semantic-release
- name: リリースノート生成
uses: release-drafter/release-drafter@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}{
"branches": ["main"],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
"@semantic-release/changelog",
[
"@semantic-release/npm",
{
"npmPublish": false
}
],
[
"@semantic-release/git",
{
"assets": ["package.json", "CHANGELOG.md"],
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
}
],
"@semantic-release/github"
]
}name: Matrix Build
on:
push:
branches: [main, develop]
jobs:
test-matrix:
name: Node ${{ matrix.node-version }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
node-version: [18, 20, 21]
os: [ubuntu-latest, windows-latest, macos-latest]
exclude:
- os: windows-latest
node-version: 18
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 run build
- run: npm teststeps:
- name: キャッシュの復元
uses: actions/cache@v3
with:
path: |
~/.npm
.next/cache
node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx') }}
restore-keys: |
${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
${{ runner.os }}-node-
- name: 依存関係のインストール
run: npm cienv:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
API_KEY: ${{ secrets.API_KEY }}
# 決してシークレットをハードコードしないjobs:
build:
runs-on: ubuntu-latest
steps:
- run: npm run build
test:
needs: build # buildが成功した後に実行
runs-on: ubuntu-latest
steps:
- run: npm test
deploy:
needs: [build, test] # buildとtestが両方成功した後に実行
runs-on: ubuntu-latest
steps:
- run: npm run deployjobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 15 # 15分でタイムアウト
steps:
- run: npm testGitHub Actionsを活用することで、以下のメリットが得られます。
本記事で紹介したワークフローをベースに、プロジェクトのニーズに合わせてカスタマイズしてください。
コメント