Урок 04

CI/CD с GitHub Actions

Автоматизация проверок и деплоя при пуше.

Базовый workflow

.github/workflows/ci.yml:

name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: 'npm'
      - run: npm ci
      - run: npm run lint
      - run: npx tsc --noEmit

  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: 'npm'
      - run: npm ci
      - run: npm run build
        env:
          DATABASE_URL: ${{ secrets.DATABASE_URL }}
          AUTH_SECRET: ${{ secrets.AUTH_SECRET }}

Секреты

Settings → Secrets and variables → Actions.

DATABASE_URL
AUTH_SECRET
VERCEL_TOKEN

Доступны как ${{ secrets.NAME }}.

Деплой на Vercel

name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - 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'

Деплой на VPS через SSH

name: Deploy to VPS

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Deploy via SSH
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.SSH_HOST }}
          username: ${{ secrets.SSH_USER }}
          key: ${{ secrets.SSH_KEY }}
          script: |
            cd /var/www/my-app
            git pull
            docker compose build
            docker compose up -d
            docker compose exec -T app npx prisma migrate deploy

Docker build и push

- name: Build and push
  uses: docker/build-push-action@v5
  with:
    context: .
    push: true
    tags: ghcr.io/${{ github.repository }}:latest
  env:
    REGISTRY: ghcr.io

Затем на сервере:

docker pull ghcr.io/user/repo:latest
docker compose up -d

Матрица версий

strategy:
  matrix:
    node: [20, 22]

steps:
  - uses: actions/setup-node@v4
    with:
      node-version: ${{ matrix.node }}

Кеш

- uses: actions/cache@v4
  with:
    path: ~/.npm
    key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}

Или через cache: 'npm' в setup-node.

Тесты

- run: npm test
- run: npm run test:e2e
  env:
    DATABASE_URL: ${{ secrets.TEST_DATABASE_URL }}

Условные шаги

- name: Deploy
  if: github.ref == 'refs/heads/main'
  run: vercel --prod

Только для main.

Preview для PR

- name: Deploy Preview
  if: github.event_name == 'pull_request'
  run: vercel

Уведомления

- name: Notify
  if: failure()
  uses: slackapi/slack-github-action@v1
  with:
    payload: |
      {"text": "Deploy failed for ${{ github.repository }}"}
  env:
    SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}

Best practices

  • Кешируй node_modules и .next/cache
  • Запускай линтер и типы до сборки
  • Используй npm ci, а не npm install
  • Секреты — только через GitHub Secrets
  • Preview-деплой для PR
  • Уведомления при падении

Итоги

  • GitHub Actions для CI/CD
  • Секреты через Settings
  • Деплой на Vercel, VPS, Docker
  • Кеш для скорости
  • Условные шаги
  • Уведомления о падениях