Типовой CI-пайплайн: checkout, setup, install, test

Собираем эталонный CI-пайплайн, который подойдёт почти любому проекту.

Любой CI сводится к четырём шагам: получить код → подготовить окружение → установить зависимости → проверить (линтер и тесты).

Анатомия типового пайплайна

Названия команд меняются от языка к языку, но скелет один и тот же. Вот он на примере Node.js-проекта:

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

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

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

      - name: Install
        run: npm ci

      - name: Lint
        run: npm run lint

      - name: Test
        run: npm test

Почему npm ci, а не npm install

В CI используют npm ci (clean install): он ставит ровно то, что записано в package-lock.json, не меняет lock-файл и работает быстрее. Это даёт повторяемость — ключевое свойство CI. Аналоги в других экосистемах: pip install -r requirements.txt, poetry install, composer install.

Тот же скелет для Python

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - run: pip install -r requirements.txt
      - run: ruff check .
      - run: pytest

Порядок шагов и быстрое падение

Шаги идут от дешёвых к дорогим: сначала линтер (секунды), потом тесты (минуты). Если код не проходит линтер, нет смысла гонять тесты — job упадёт раньше и сэкономит время. Это принцип «fail fast»: пусть проблема всплывёт как можно раньше и дешевле.

Что считается успехом

Job зелёный, только если все команды вернули код 0. Тестовые фреймворки специально возвращают ненулевой код при упавших тестах — поэтому достаточно просто вызвать pytest или npm test, и CI сам поймёт результат.

Итог

  • Скелет CI: checkout → setup → install → lint → test.
  • В CI ставят зависимости детерминированно (npm ci, lock-файлы) ради повторяемости.
  • Дешёвые проверки — раньше дорогих (fail fast).
Проверьте себя
1. Почему в CI предпочитают npm ci, а не npm install?
Anpm ci умеет деплоить
Bnpm ci ставит ровно версии из lock-файла, не меняет его и работает предсказуемо
Cnpm install не существует
Dnpm ci игнорирует тесты
2. Почему линтер ставят в пайплайне раньше тестов?
AЛинтер обязателен по правилам GitHub
BПринцип fail fast: дешёвая проверка падает раньше и экономит время на дорогих тестах
CТесты не умеют возвращать код ошибки
DЛинтер запускает тесты сам
3. Как CI понимает, что тесты упали?
AАнализирует текст логов вручную
BТестовый фреймворк возвращает ненулевой код выхода, и шаг становится красным
CПо количеству строк вывода
DНикак, нужно проверять глазами
Поддержать проект