Complete Next.js CI/CD Pipeline
name: CI/CD Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
install:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 8
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Cache node_modules
uses: actions/cache@v4
with:
path: node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/pnpm-lock.yaml') }}
lint:
needs: install
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- name: Restore dependencies
uses: actions/cache@v4
with:
path: node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/pnpm-lock.yaml') }}
- name: Run ESLint
run: pnpm lint
typecheck:
needs: install
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- name: Restore dependencies
uses: actions/cache@v4
with:
path: node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/pnpm-lock.yaml') }}
- name: Run TypeScript
run: pnpm type-check
test:
needs: install
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- name: Restore dependencies
uses: actions/cache@v4
with:
path: node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/pnpm-lock.yaml') }}
- name: Run unit tests
run: pnpm test:unit --coverage
- name: Upload coverage
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
e2e:
needs: install
runs-on: ubuntu-latest
strategy:
matrix:
browser: [chromium, firefox]
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- name: Restore dependencies
uses: actions/cache@v4
with:
path: node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/pnpm-lock.yaml') }}
- name: Install Playwright Browsers
run: pnpm exec playwright install --with-deps ${{ matrix.browser }}
- name: Run E2E tests
run: pnpm test:e2e --project=${{ matrix.browser }}
- name: Upload test results
if: failure()
uses: actions/upload-artifact@v4
with:
name: playwright-report-${{ matrix.browser }}
path: playwright-report/
deploy:
needs: [lint, typecheck, test, e2e]
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment:
name: production
url: https://yourapp.com
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'
- name: Notify Slack
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "Deployment to production successful!",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "✅ *Deployment Successful*\nCommit: ${{ github.sha }}\nAuthor: ${{ github.actor }}"
}
}
]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}