Learn (Almost) Anything
КаталогСкачать курс

Автоматизация в GitHub

Из чего обычно состоит CI: checkout, setup runtime, install dependencies, lint/typecheck/test/build, upload reports, status checks и branch protection integration.

ruЭнциклопедия33 урока6 модулей9
GitHub actionsАвтоматизация в GitHubМодель workflowсостояние и артефактыматрицы и runtimeрелизы и environmentsПереиспользование и собственные actionsgovernance и эксплуатацияgithubactions

CI pipeline

Из чего обычно состоит CI: checkout, setup runtime, install dependencies, lint/typecheck/test/build, upload reports, status checks и branch protection integration.

CI pipeline

CI pipeline в GitHub Actions — это workflow, который автоматически проверяет изменение до merge: забирает код, поднимает runtime, ставит зависимости, запускает lint/typecheck/test/build и оставляет понятные результаты в checks, логах, summaries и artifacts. Его задача не «задеплоить всё», а дать команде быстрый и воспроизводимый ответ: этот commit можно безопасно вливать или нет.

Обычно CI запускают на pull_request, чтобы проверять изменения до merge, и на push в основную ветку, чтобы видеть состояние уже принятого кода. Детали триггеров относятся к Events и filters, но для CI важна простая идея: проверка должна срабатывать ровно там, где от неё зависит решение о merge.

flowchart LR A[Pull request или push] --> B[Workflow trigger] B --> C[Job: ci / node] C --> D[Checkout] D --> E[Setup runtime] E --> F[Install dependencies] F --> G[Lint и typecheck] G --> H[Tests] H --> I[Build] I --> J[Artifacts и summary] J --> K[GitHub check] K --> L{Branch protection} L -->|success| M[Merge allowed] L -->|failure| N[Merge blocked]
flowchart LR
  A[Pull request или push] --> B[Workflow trigger]
  B --> C[Job: ci / node]
  C --> D[Checkout]
  D --> E[Setup runtime]
  E --> F[Install dependencies]
  F --> G[Lint и typecheck]
  G --> H[Tests]
  H --> I[Build]
  I --> J[Artifacts и summary]
  J --> K[GitHub check]
  K --> L{Branch protection}
  L -->|success| M[Merge allowed]
  L -->|failure| N[Merge blocked]
Типовой путь CI-сигнала: от события в репозитории до required check в защищённой ветке.

Минимальный контракт CI

Хороший CI pipeline похож на контракт между репозиторием и branch protection. Workflow говорит: «я умею проверить проект». Branch protection говорит: «без успешного check нельзя вливать в main». GitHub Actions при запуске workflow создаёт checks; именно их обычно выбирают как required status checks.

Типовой Node.js pipeline может выглядеть так:

name: CI

on:
  pull_request:
  push:
    branches: [main]

permissions:
  contents: read

concurrency:
  group: ci-${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  node-ci:
    name: ci / node
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm

      - name: Install dependencies
        run: npm ci

      - name: Lint
        run: npm run lint

      - name: Typecheck
        run: npm run typecheck

      - name: Test
        run: npm test -- --ci

      - name: Build
        run: npm run build

      - name: Upload test reports
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: test-reports
          path: |
            coverage/
            test-results/
          if-no-files-found: ignore

      - name: Write summary
        if: always()
        run: |
          echo "## CI" >> "$GITHUB_STEP_SUMMARY"
          echo "Commit: $GITHUB_SHA" >> "$GITHUB_STEP_SUMMARY"
          echo "Job: $GITHUB_JOB" >> "$GITHUB_STEP_SUMMARY"

Этот пример намеренно скучный. В CI это достоинство. Тут нет deploy, облачных secrets и лишних прав у GITHUB_TOKEN: permissions: contents: read достаточно для checkout и чтения репозитория. Более широкие права относятся к Permissions и GITHUB_TOKEN, а рискованные PR-сценарии — к pull_request_target и untrusted PR.

Стадии pipeline

checkout почти всегда первый реальный step. Runner не получает полный рабочий каталог магически: репозиторий надо явно забрать через action. Если нужен полный history для versioning или changelog, настраивают fetch-depth, но для обычного CI достаточно стандартного поведения.

setup runtime фиксирует среду: Node, Python, Go, Java, Ruby, Rust, .NET. Это лучше, чем полагаться на случайно предустановленную версию в image. Вопрос drift образов и выбора ubuntu-latest, Windows или macOS подробнее раскрывается в GitHub-hosted runners.

install dependencies должен быть воспроизводимым. Для Node это обычно npm ci, для Python — установка из lock/constraints, для Go — go mod download, для Rust — cargo fetch или обычный cargo test, который сам подтянет зависимости. Cache ускоряет этот этап, но не должен заменять lock-файл. Граница между cache и результатами сборки разбирается в Dependency cache.

lint, typecheck, test, build — разные вопросы к коду. Lint отвечает за стиль и часть bug patterns. Typecheck ловит несоответствия типов до runtime. Tests проверяют поведение. Build доказывает, что production bundle, binary или package вообще собирается. Иногда build идёт до tests, если tests запускаются против собранного артефакта; это нормальная архитектурная деталь, а не универсальное правило.

upload reports нужен, когда результатом является файл: coverage, JUnit XML, Playwright HTML report, screenshots, бинарники. Для коротких строк используйте Step outputs и job outputs, для файлов — Artifacts и reports. Если report нужен даже при падении тестов, ставьте if: always(), иначе самый полезный diagnostic artifact исчезнет ровно в failed run.

summary — не обязательная стадия, но очень полезная. Как было в Workflow commands и summaries, GITHUB_STEP_SUMMARY подходит для короткого человеческого итога: что запускалось, где отчёт, какой build создан, почему job упал. Не надо копировать туда весь лог.

Один job или несколько

Для маленького проекта один job проще и дешевле в сопровождении. Все steps идут на одном runner, общий workspace сохраняется между steps, а failure видно в одном check.

Несколько jobs нужны, когда есть независимые дорогие проверки, разные runners или явный handoff: например, build собирает frontend artifact, а e2e скачивает его и гоняет браузерные тесты. Связи между jobs описываются через needs, условия — через if, а fan-out по версиям и ОС — через Matrix strategy. Не дробите pipeline только ради красивого графа: каждый job имеет overhead на очередь, startup, checkout и установку окружения.

Если проекту нужны PostgreSQL, Redis или очередь, не устанавливайте их вручную в shell без причины. Для этого есть service containers; они описаны отдельно в Containers и service containers.

Branch protection и required checks

CI становится gate только после настройки branch protection или ruleset. В настройках защищённой ветки включают requirement «status checks must pass» и выбирают конкретные checks. Практическая деталь: имена jobs должны быть уникальными и стабильными. Если в двух workflows есть одинаковый name, required check может стать неоднозначным и заблокировать merge.

Важно помнить и про skipped checks. GitHub считает skipped job успешным для зависимых checks. Поэтому условие if: на required job надо писать аккуратно: если required check пропускается на важном PR, branch protection может получить «зелёный» сигнал без реальной проверки. Для optional проверок это нормально; для merge gate — почти всегда ошибка дизайна.

Отдельная ловушка — чрезмерные paths/paths-ignore фильтры. Они экономят минуты, но требуют проверки вместе с branch protection: required check должен появляться предсказуемо на PR, иначе команда получит зависшие или пропущенные gate-сценарии. Оптимизация времени CI должна идти после ясного контракта проверки; подробнее это тема Оптимизация времени CI.

Рабочая эвристика

Начинайте с одного понятного CI workflow: checkout → setup → install → lint/typecheck/test/build → reports → summary. Дайте job стабильное имя, ограничьте permissions, загрузите diagnostic artifacts при if: always(), подключите check к branch protection. Потом расширяйте: matrix, service containers, split jobs, reusable workflows и отдельные deployment workflows.

Нормальный CI не обязан быть сложным. Он обязан быть скучно надёжным: одинаково запускаться на каждом PR, быстро падать при настоящей проблеме и оставлять достаточно следов, чтобы исправление не начиналось с раскопок в логах.

See also

Быстрое повторение #rc-1

Зачем CI workflow обычно запускают и на pull_request, и на push в main?

Показать ответ

pull_request проверяет изменения до merge, а push в main показывает состояние уже принятого кода. CI должен запускаться там, где его результат влияет на решение о merge или на доверие к основной ветке.

Источники

  1. Understanding GitHub Actions - GitHub Docs
  2. Workflow syntax for GitHub Actions - GitHub Docs
  3. Building and testing your code - GitHub Docs
  4. Store and share data with workflow artifacts - GitHub Docs
  5. Dependency caching reference - GitHub Docs
  6. About status checks - GitHub Docs
  7. About protected branches - GitHub Docs
  8. GitHub for Beginners: Getting started with GitHub Actions - GitHub Blog
  9. How to use GitHub Actions | GitHub for Beginners - YouTube