Как устроен CI/CD pipeline в Node.js проекте?

Ответ

Типичный CI/CD pipeline для Node.js проекта состоит из последовательных этапов, автоматизирующих сборку, тестирование и развертывание. Вот пример конфигурации для GitHub Actions:

.github/workflows/ci-cd.yml:

name: Node.js CI/CD Pipeline
on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  test-and-build:
    runs-on: ubuntu-latest
    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 --audit=false

      - name: Run linter (ESLint)
        run: npm run lint

      - name: Run tests with coverage
        run: npm test -- --coverage

      - name: Build project (для TypeScript)
        run: npm run build

      - name: Upload coverage report
        uses: codecov/codecov-action@v3

  deploy-staging:
    runs-on: ubuntu-latest
    needs: test-and-build
    if: github.ref == 'refs/heads/develop'
    steps:
      - name: Deploy to Staging (AWS Elastic Beanstalk example)
        run: |
          # Команды для деплоя, например, с помощью AWS CLI
          eb deploy myapp-staging --label ${{ github.sha }}

  deploy-production:
    runs-on: ubuntu-latest
    needs: test-and-build
    if: github.ref == 'refs/heads/main'
    steps:
      - name: Approve and Deploy to Production
        # Часто требует ручного подтверждения (manual approval)
        run: echo "Производственный деплой инициирован..."

Ключевые этапы локально и в CI:

  1. Установка: npm ci для воспроизводимых зависимостей.
  2. Линтинг: Проверка стиля кода с помощью ESLint и Prettier.
  3. Тестирование: Запуск юнит- и интеграционных тестов (Jest, Mocha).
  4. Сборка: Транспиляция TypeScript, минификация, бандлинг (если применимо).
  5. Деплой: Автоматическое развертывание на staging/production среды (часто в Docker-контейнерах на платформах вроде AWS, GCP, Heroku).

Ответ 18+ 🔞

Слушай, ну вот представь: ты написал код, и он у тебя работает на локалхосте. А теперь надо, чтобы эта штука ещё и в продакшене не накрылась медным тазом. Вот для этого и нужен CI/CD, этакая хитрая жопа из скриптов, которая всё за тебя сделает — проверит, соберёт и засунет на сервер. Смотри, как это обычно выглядит для Node.js, чтобы ты не бздел перед каждым деплоем.

Вот тебе типичный конфиг для GitHub Actions, чтоб ты понимал масштаб:

.github/workflows/ci-cd.yml:

name: Node.js CI/CD Pipeline
on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  test-and-build:
    runs-on: ubuntu-latest
    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 --audit=false

      - name: Run linter (ESLint)
        run: npm run lint

      - name: Run tests with coverage
        run: npm test -- --coverage

      - name: Build project (для TypeScript)
        run: npm run build

      - name: Upload coverage report
        uses: codecov/codecov-action@v3

  deploy-staging:
    runs-on: ubuntu-latest
    needs: test-and-build
    if: github.ref == 'refs/heads/develop'
    steps:
      - name: Deploy to Staging (AWS Elastic Beanstalk example)
        run: |
          # Команды для деплоя, например, с помощью AWS CLI
          eb deploy myapp-staging --label ${{ github.sha }}

  deploy-production:
    runs-on: ubuntu-latest
    needs: test-and-build
    if: github.ref == 'refs/heads/main'
    steps:
      - name: Approve and Deploy to Production
        # Часто требует ручного подтверждения (manual approval)
        run: echo "Производственный деплой инициирован..."

А теперь, ёпта, разберём по косточкам, что тут происходит, а то смотришь на этот YAML и волнение ебать начинается.

Этап первый: Установка зависимостей.
Ты не просто npm install кидаешь, а npm ci. Это чтобы зависимости ставились строго по package-lock.json, а не как бог на душу положит. Иначе один чувак соберёт с одной версией пакета, а у другого — с другой, и потом овердохуища багов. Доверия к npm install в CI — ноль ебать.

Этап второй: Линтинг.
Запускаешь ESLint. Это чтобы код был в одном стиле, а не как у мартышлюшки, которая случайно по клавиатуре прошлась. Если линтер орёт — значит, ты распиздяй, и тебе надо поправить отступы и точку с запятой.

Этап третий: Тесты.
Самое важное. Запускаешь npm test. Если тесты не проходят — всё, пиши пропало. Деплоить нечего. Это как проверка: а не говно ли ты написал? Покрытие (coverage) тоже смотришь, чтобы не было мест, куда ты даже тестов не сунул — это подозрительно, ёбать чувствую.

Этап четвёртый: Сборка.
Если у тебя TypeScript — тут он в JavaScript превращается. Если React — бандлится. Главное, чтобы скрипт build не сломался на ровном месте. Иначе получится хуй в пальто, а не артефакт для деплоя.

Этап пятый: Деплой.
Вот тут уже начинается магия. На develop ветке автоматом летит на staging — там можно ещё потыкать. А на main — уже на продакшн. Но часто на продакшн нужен ручной аппрув, типа «Чувак, ты уверен?». И это правильно, а то один неверный пуш — и ты уже не герой, а пидарас шерстяной, который уронил продакшен.

Короче, смысл в чём: ты пушишь код, а дальше эта ебать-колотить автоматизация сама всё прогоняет. Если где-то сломалось — pipeline красный, и ничего никуда не улетает. Красота же! Сидишь себе, кофе пьёшь, а тебе уже пишут: «Всё упало на тестах». Ну, значит, пора чинить, а не впиздюривать кривой код в мастер.