GitHub Actions: практический пример
Updated Jul 2026
Готовый к продакшену тестовый пайплайн
Следующий workflow демонстрирует реалистичный CI-пайплайн для веб-приложения с несколькими уровнями тестирования. Внимательно изучите каждый раздел — каждая строка имеет своё назначение.
# .github/workflows/test-pipeline.yml
name: Test Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
schedule:
- cron: '0 6 * * 1-5' # Weekdays at 6 AM UTC
env:
NODE_ENV: test
BASE_URL: https://staging.example.com
jobs:
unit-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- run: npm run test:unit -- --coverage
- uses: actions/upload-artifact@v4
if: always()
with:
name: unit-coverage
path: coverage/
integration-tests:
needs: unit-tests
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env:
POSTGRES_DB: test_db
POSTGRES_PASSWORD: ${{ secrets.DB_PASSWORD }}
ports:
- 5432:5432
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- run: npm run test:integration
env:
DATABASE_URL: postgres://postgres:${{ secrets.DB_PASSWORD }}@localhost:5432/test_db
browser-tests:
needs: integration-tests
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
browser: [chromium, firefox, webkit]
shard: [1, 2, 3]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- run: npx playwright install --with-deps ${{ matrix.browser }}
- run: npx playwright test --project=${{ matrix.browser }} --shard=${{ matrix.shard }}/3
- uses: actions/upload-artifact@v4
if: failure()
with:
name: traces-${{ matrix.browser }}-${{ matrix.shard }}
path: test-results/
Построчный разбор
Триггеры
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
schedule:
- cron: '0 6 * * 1-5'
Три типа триггеров охватывают три различных цикла обратной связи:
- Push запускается при прямых push в
mainиdevelop— ловит проблемы сразу после слияния - Pull request запускается, когда PR направлен в
main— ловит проблемы до слияния - Schedule запускается в будние дни утром — ловит дрейф окружения, истёкшие токены или нестабильные тесты, которые проявляются лишь периодически
Глобальные переменные окружения
env:
NODE_ENV: test
BASE_URL: https://staging.example.com
Заданные на уровне workflow, эти переменные доступны всем задачам. Используйте глобальные переменные окружения для конфигурации, применимой повсеместно. Для более специфичных настроек используйте переменные на уровне задачи или шага.
Зависимости между задачами
needs: unit-tests
Ключевое слово needs создаёт пайплайн, в котором unit-тесты блокируют интеграционные тесты, а те блокируют браузерные тесты. Если unit-тесты падают, интеграционные никогда не запускаются — экономя вычислительные ресурсы и обеспечивая более быструю обратную связь.
Почему порядок имеет значение:
- Unit-тесты (секунды) — ловят логические ошибки мгновенно
- Интеграционные тесты (минуты) — ловят проблемы связей и базы данных
- Браузерные тесты (минуты) — ловят проблемы UI и сквозные проблемы
Если вы запустите браузерные тесты первыми и они упадут из-за сломанной утилитарной функции, вы потратите 15 минут, прежде чем получите ту же обратную связь, которую unit-тесты дали бы за 30 секунд.
Сервисы (sidecar-контейнеры)
services:
postgres:
image: postgres:16
env:
POSTGRES_DB: test_db
POSTGRES_PASSWORD: ${{ secrets.DB_PASSWORD }}
ports:
- 5432:5432
GitHub Actions запускает контейнер Postgres рядом с вашим тестовым раннером. База данных доступна по адресу localhost:5432 внутри задачи. Именно так вы запускаете интеграционные тесты на реальных базах данных без управления внешней инфраструктурой.
Другие распространённые сервисы:
- Redis:
redis:7на порту 6379 - MySQL:
mysql:8на порту 3306 - Elasticsearch:
elasticsearch:8.11.0на порту 9200 - RabbitMQ:
rabbitmq:3-managementна порту 5672
Секреты
${{ secrets.DB_PASSWORD }}
Секреты зашифрованы и никогда не выводятся в логах. GitHub автоматически маскирует их в выводе. Настраивайте секреты в параметрах репозитория: Settings > Secrets and variables > Actions.
Лучшие практики:
- Используйте описательные имена:
DB_PASSWORD, а неSECRET1 - Документируйте, какие секреты необходимы, в файле
CONTRIBUTING.md - По возможности используйте секреты для конкретного окружения (например,
STAGING_API_KEYвместоPROD_API_KEY)
Матричная стратегия
strategy:
fail-fast: false
matrix:
browser: [chromium, firefox, webkit]
shard: [1, 2, 3]
Это создаёт 3 браузера x 3 шарда = 9 параллельных задач. Каждая комбинация выполняется независимо. Настройка fail-fast: false означает, что все 9 задач завершатся, даже если некоторые упадут, давая вам полную картину сбоев по всем браузерам.
Когда использовать матрицы:
- Кросс-браузерное тестирование (Chromium, Firefox, WebKit)
- Кросс-платформенное тестирование (ubuntu, windows, macos)
- Шардирование тестов для параллелизации
- Тестирование на нескольких версиях (Node 18, 20, 22)
Артефакты
- uses: actions/upload-artifact@v4
if: always()
with:
name: unit-coverage
path: coverage/
Условие if: always() загружает артефакты даже при падении задачи. Для отчётов о покрытии данные нужны всегда. Для трейсов можно использовать if: failure(), чтобы собирать артефакты только при возникновении ошибок.
Расширение пайплайна
Добавление линтинга и проверки типов
Добавьте быструю первую задачу, которая выполняется перед всем остальным:
lint-and-typecheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npm run typecheck
Затем сделайте unit-tests зависимым от lint-and-typecheck:
unit-tests:
needs: lint-and-typecheck
Добавление уведомлений в Slack
notify-on-failure:
needs: [unit-tests, integration-tests, browser-tests]
if: failure()
runs-on: ubuntu-latest
steps:
- uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "Pipeline failed on ${{ github.ref_name }}: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
Добавление фильтрации по путям
Пропуск дорогих тестов при изменении только документации:
on:
push:
branches: [main, develop]
paths-ignore:
- '**.md'
- 'docs/**'
- '.github/ISSUE_TEMPLATE/**'
Отладка GitHub Actions
Отладка workflow — одна из самых болезненных задач. Вот практические стратегии:
- Включите отладочное логирование: установите секрет репозитория
ACTIONS_STEP_DEBUGвtrueдля подробного вывода - Используйте
actлокально: инструмент act запускает workflow GitHub Actions на вашей локальной машине, значительно ускоряя итерации - Добавьте диагностические шаги: вставьте шаги
envиls -laдля инспекции окружения, когда происходит что-то неожиданное - Проверяйте вкладку Actions: у упавших шагов есть раскрываемые логи. Посмотрите на последний успешный шаг и первый упавший, чтобы сузить область проблемы
- Используйте
continue-on-error: trueвременно: позвольте упавшему шагу продолжить выполнение, чтобы увидеть вывод последующих шагов для отладки
# Temporary debugging step
- name: Debug environment
if: failure()
run: |
echo "Working directory: $(pwd)"
ls -la
env | sort
cat package.json | head -20
Практическое упражнение
- Сделайте fork простого Node.js-проекта (или создайте его с помощью
npm init) - Добавьте тестовый пайплайн из этого файла в
.github/workflows/test-pipeline.yml - Упростите его: начните только с задачи
unit-tests - Сделайте push и наблюдайте за вкладкой Actions — убедитесь, что пайплайн запускается и создаёт артефакты
- Добавьте
integration-testsс сервисом Postgres - Добавьте матричную стратегию для браузерных тестов
- Намеренно сломайте тест и убедитесь, что артефакты загружаются при сбое
- Добавьте фильтрацию по путям и уведомления в Slack
Стройте пайплайн инкрементально. Не пытайтесь написать всю конфигурацию сразу — вы потратите больше времени на отладку, чем на создание.