Перейти к основному содержимому

GitHub Actions — CI/CD рецепты


Для кого эта статья

Готовые примеры GitHub Actions с пошаговым разбором каждой строки YAML — как в галерее Turtle для Python и curl / fetch для API. Можно скопировать workflow, вставить в репозиторий и понять, зачем нужна каждая строка.

Подойдёт, если вы:

  • делаете курсовую, лабораторную, диплом или pet-проект на GitHub;
  • гуглите «github actions пример», «github actions yaml», «ci cd github actions», «github actions node js», «github actions python», «деплой на github pages actions», «как настроить github actions»;
  • знаете git push, но вкладка Actions пока пустая;
  • хотите зелёную галочку в pull request и badge «CI passing» в README.

Как применять:

ШагДействие
1Создайте папку .github/workflows/ в корне репозитория
2Сохраните YAML в файл, например ci.yml
3git add, git commit, git push
4Откройте вкладку Actions — там появится run
5При ошибке кликните красный step и читайте лог

Бесплатного лимита GitHub Actions хватает для учебных репозиториев. Подробности — в документации GitHub.

Сначала теория

Системное введение — GitHub Actions. Полный справочник по ключам YAML — Справочник по GitHub Actions. Связка Git и триггеров — Git и GitFlow в DevOps. Пошаговый деплой сайта — кейс GitHub Pages.


Как пользоваться статьёй

  1. Прочитайте блок «Что такое GitHub Actions» — там смысл CI/CD без жаргона.
  2. Сделайте первый workflow за 5 минут — минимальный рабочий файл.
  3. Найдите свой стек (Node, Python, деплой, PR).
  4. Скопируйте YAML целиком.
  5. Прочитайте Разбор и Разбор построчно под кодом.
  6. Выполните Попробуйте — одна маленькая правка закрепляет тему.
  7. Для отчёта по лабораторной можно скриншотить вкладку Actions и зелёный step.

Что такое GitHub Actions простыми словами

Вы делаете git push — код попадает на GitHub. GitHub Actions — это робот на сервере GitHub, который автоматически выполняет команды из вашего репозитория: установить Node.js, запустить тесты, собрать сайт, залить на GitHub Pages.

Инструкции роботу лежат в файле YAML (текст с отступами) в папке .github/workflows/.

Без CIС GitHub Actions
«У меня локально всё работает»На каждый push проверка на чистой Linux-ВМ
Преподаватель клонирует и мучается с версией NodeВ YAML зафиксирована версия 20
Забыли запустить тесты перед сдачейТесты стартуют сами, результат виден в PR
Деплой — копировать папку рукамиnpm run build + публикация на Pages одной кнопкой

CI (Continuous Integration) — «каждое изменение кода автоматически проверяется». CD (Continuous Delivery/Deployment) — «после проверок артефакт выкладывается на сервер или Pages».


Словарь за 30 секунд

ТерминПростыми словами
WorkflowОдин YAML-файл = один сценарий автоматизации
JobБлок работы на одной виртуальной машине
StepОдин шаг внутри job — команда или готовый action
RunnerВременная ВМ, где выполняются step (ubuntu-latest = Linux)
ActionЧужой готовый step из каталога (actions/checkout@v4)
on:Когда запускать — push, PR, расписание, кнопка
uses:Подключить action
run:Выполнить shell-команду (npm test, pytest)
with:Параметры для action (версия Node, путь к папке)
${{ … }}Подстановка переменной GitHub (секрет, matrix, ref)
SecretПароль/токен в Settings, в код не пишется
ArtifactZip с build/ или dist/ — скачать из UI run
MatrixОдин job × много версий (Node 18 и 20 параллельно)

Первый workflow за 5 минут

Задача: с нуля получить зелёный run во вкладке Actions.

Шаг 1 — создать файл локально

В корне репозитория (там же, где README.md):

my-project/
.github/
workflows/
hello.yml ← ваш первый workflow
README.md

Папки .github и workflows с точкой — это стандарт GitHub, не опечатка.

Шаг 2 — минимальный YAML

Файл .github/workflows/hello.yml:

name: Hello CI

on:
push:
branches: [main]
workflow_dispatch:

jobs:
greet:
runs-on: ubuntu-latest
steps:
- run: echo "GitHub Actions работает"

Шаг 3 — отправить на GitHub

git add .github/workflows/hello.yml
git commit -m "ci: первый workflow GitHub Actions"
git push origin main

Если основная ветка называется master, в YAML замените main на master.

Шаг 4 — посмотреть результат

  1. Откройте репозиторий на github.com.
  2. Вкладка Actions → слева Hello CI → сверху последний run.
  3. Клик по job greet → step с echo → в логе строка GitHub Actions работает.
  4. Зелёная галочка ✓ — workflow успешен.

Что увидите в UI:

ЭлементЗначение
Жёлтый кружокRun ещё выполняется
Зелёная галочкаВсе step прошли
Красный крестКакой-то step упал — откройте его лог
Re-run jobsПовторить без нового коммита

Попробуйте: на вкладке Actions нажмите Run workflow (работает, потому что в YAML есть workflow_dispatch).


Анатомия YAML-файла workflow

Любой workflow — это четыре уровня вложенности. Отступы только пробелами (обычно 2), табы ломают парсер.

name ← имя в UI
on ← триггеры
jobs ← список job
job_id ← имя job (вы придумываете)
runs-on ← ОС runner
steps ← список шагов
- run ← команда
- uses ← action

Разбор минимального hello.yml построчно

name: Hello CI

Разбор:

  • name: — подпись workflow во вкладке Actions. Можно по-русски: name: Моя первая CI.
  • Без name GitHub покажет имя файла hello.yml.

on:
push:
branches: [main]
workflow_dispatch:

Разбор построчно:

СтрокаСмысл
on:Блок «когда запускать»
push:При отправке коммитов (git push)
branches: [main]Только push в ветку main, push в feature/login этот workflow не тронет
workflow_dispatch:Ручной запуск кнопкой Run workflow в UI

Короткая запись того же триггера: on: [push, workflow_dispatch] — без фильтра по ветке (сработает на любой push).


jobs:
greet:
runs-on: ubuntu-latest
steps:
- run: echo "GitHub Actions работает"

Разбор построчно:

СтрокаСмысл
jobs:Начало списка job. Можно несколько: test, deploy, …
greet:ID job — латиница, без пробелов. В логах и в needs: greet
runs-on: ubuntu-latestGitHub выдаёт свежую Ubuntu с bash, curl, git
steps:Шаги выполняются сверху вниз на одной и той же ВМ
- run: echo "…"Минус + пробел = элемент списка. run — команда в shell
echoПечать текста в лог (как в терминале Linux)

Почему - перед step: в YAML это массив. Каждый step — новый элемент списка.


Основы — checkout и actions

Checkout — скачать код на runner

Задача: понять, зачем почти везде первый step — actions/checkout.

Без checkout на runner пустая папка. Команда npm ci упадёт — нет package.json.

steps:
- uses: actions/checkout@v4
- run: ls -la
- run: cat package.json

Разбор построчно:

СтрокаСмысл
- uses: actions/checkout@v4uses = взять готовый action. actions/checkout — официальный, клонирует репо
@v4Версия action. Пишите @v4, @v5, не @main — иначе завтра action может сломаться
ls -laСписок файлов в рабочей папке — в логе увидите исходники
cat package.jsonПечать файла — проверка, что checkout сработал

Где лежит код на runner: переменная $GITHUB_WORKSPACE — обычно /home/runner/work/ИМЯ_РЕПО/ИМЯ_РЕПО.

Попробуйте: добавьте под checkout:

- uses: actions/checkout@v4
with:
fetch-depth: 0

Разбор fetch-depth: 0:

  • По умолчанию checkout качает 1 последний коммит (fetch-depth: 1) — быстрее.
  • 0 = вся история Git. Нужно для release notes, git describe, Docusaurus «last updated».

uses: и run: — в чём разница

uses:run:
Что этоГотовый action (чужой YAML+скрипт)Ваша команда в shell
Примерactions/setup-node@v4npm test
КогдаСтандартные задачи (git, node, cache)Ваши скрипты проекта

Один step — либо uses, либо run (иногда оба через run внутри action).


Синтаксис ${{ }} — подстановка значений

GitHub подставляет значения до выполнения step:

node-version: ${{ matrix.node-version }}
github_token: ${{ secrets.GITHUB_TOKEN }}
if: github.ref == 'refs/heads/main'
ВыражениеОткуда значение
${{ matrix.node-version }}Из блока strategy.matrix
${{ secrets.API_TOKEN }}Settings → Secrets
${{ github.ref }}Текущая ветка или тег
${{ github.event_name }}push, pull_request, …
${{ runner.os }}Linux, Windows, macOS

В логах секреты заменяются на ***. Писать echo ${{ secrets.TOKEN }} бессмысленно — увидите звёздочки.


Стартовые рецепты

Простые сценарии для отчёта, курсовой и первого badge в README.

Node.js — установка и тесты (самый частый запрос)

Задача: на каждый push и pull request установить зависимости и запустить npm test.

Файл .github/workflows/node-ci.yml:

name: Node CI

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

jobs:
test:
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 test

Разбор блоков:

БлокЗачем
pull_request + pushPR проверяется до merge; push в main — после слияния
setup-node@v4Ставит Node.js 20 на runner (локально у вас может быть 22 — в CI всегда 20)
cache: 'npm'Кэш скачанных пакетов — второй run быстрее на 30–60 секунд
npm ciclean install строго по package-lock.json. Для CI предпочтительнее npm install
npm testВызывает скрипт "test" из package.json

Разбор построчно — блок on::

on:
push:
branches: [main]
pull_request:
branches: [main]
  • push на ветку feature/x без открытого PR — только если добавите push без фильтра или отдельный workflow.
  • pull_request с branches: [main] — когда PR влит в main или открыт в main (target branch = main).

Связь с package.json — в проекте должен быть скрипт "test":

{
"scripts": {
"test": "jest"
}
}

Другие варианты той же строки: "node --test", "vitest run", "mocha". Главное — чтобы npm test находил команду.

Без "test" команда npm test упадёт с missing script: test.

Что увидите в логе step npm test:

> my-app@1.0.0 test
> jest

PASS src/app.test.js
Tests: 3 passed, 3 total

Красный step — прокрутите вверх до первой строки FAIL или Error:.

Попробуйте:

  1. Добавьте step - run: npm run lint после npm ci.
  2. Добавьте в README badge (замените USER и REPO):
![CI](https://github.com/USER/REPO/actions/workflows/node-ci.yml/badge.svg)

Python — pytest

Задача: прогнать unit-тесты на Python 3.12 в CI.

name: Python CI

on: [push, pull_request]

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

Разбор построчно:

СтрокаСмысл
on: [push, pull_request]Короткая форма — любой push и любой PR
setup-python@v5Python 3.12 на runner
cache: 'pip'Кэш wheel-файлов pip
pip install -r requirements.txtЗависимости проекта из файла
pip install pytestТестовый раннер (если нет в requirements)
pytest -qquiet — меньше строк в логе, только итог и ошибки

Структура тестов для pytest:

project/
src/
calc.py
tests/
test_calc.py

Пример tests/test_calc.py:

def test_add():
assert 1 + 1 == 2

Попробуйте: замените pytest -q на pytest -v — в логе будет имя каждого теста (удобно для отчёта).

Если зависимости в pyproject.toml:

- run: pip install -e ".[dev]"
- run: pytest -q

Только pull request — проверки без деплоя

Задача: на каждый PR в main — lint и test; деплой этот файл не трогает.

name: PR checks

on:
pull_request:
branches: [main]

jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm run lint
- run: npm test

Разбор:

  • Триггер только pull_request — обычный push в feature-ветку без PR workflow не запустит.
  • В карточке PR появится секция Checks — зелёный или красный статус.
  • Если в Settings → Branches → Branch protection включено «Require status checks», merge без зелёного CI невозможен.

Что увидите в PR:

All checks have passed
✓ verify / test (pull_request)

Попробуйте: намеренно сломайте тест, откройте PR — преподаватель увидит красный крест до исправления.


Java — Maven (сборка и тесты)

Задача: типичный CI для учебного Java-проекта с pom.xml.

name: Java CI

on: [push, pull_request]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'
cache: maven
- run: mvn -B verify

Разбор построчно:

СтрокаСмысл
setup-java@v4JDK на runner
distribution: temurinСборка Eclipse Temurin (бывший AdoptOpenJDK)
java-version: '21'Версия языка — как в вашем pom.xml
cache: mavenКэш ~/.m2 — не качать одни и те же jar каждый раз
mvn -B verifyBatch mode (без интерактива) + compile + test + package checks

Попробуйте: Gradle вместо Maven — cache: gradle и run: ./gradlew test.


CI/CD рецепты

1. Matrix — Node 18 и 20 параллельно

Задача: убедиться, что проект работает на двух LTS-версиях Node.

name: Node matrix

on: [push, pull_request]

jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node-version: [18, 20]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm test

Разбор построчно:

СтрокаСмысл
strategy:Настройки параллельного запуска
matrix:Таблица параметров → GitHub создаёт отдельный run на каждую комбинацию
node-version: [18, 20]Два job: один с Node 18, второй с 20
fail-fast: falseУпал тест на 18 — проверка на 20 всё равно дойдёт до конца
${{ matrix.node-version }}В первом job подставится 18, во втором 20

Что увидите в UI: два под-job test (18) и test (20) внутри одного workflow run.

Попробуйте — кросс-платформа:

strategy:
matrix:
os: [ubuntu-latest, windows-latest]
node-version: [20]
runs-on: ${{ matrix.os }}

Получится 2 job: Linux + Windows.


2. Кэш npm вручную (actions/cache)

Задача: ускорить CI в монорепо, когда встроенного cache: 'npm' мало.

Фрагмент steps:

- uses: actions/checkout@v4
- uses: actions/cache@v4
id: npm-cache
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-
- run: npm ci

Разбор построчно:

СтрокаСмысл
actions/cache@v4Сохранить/восстановить папку между run
id: npm-cacheИмя step — можно сослаться в if: steps.npm-cache.outputs.cache-hit
path: ~/.npmЧто кэшируем — каталог npm на Linux
hashFiles('**/package-lock.json')Хэш lock-файла в ключе: изменился lock → новый кэш
restore-keys:Если точного ключа нет — взять ближайший префикс ${{ runner.os }}-npm-
| после restore-keys:Многострочный YAML — вторая строка с отступом

Что увидите в логе cache step:

Cache restored from key: Linux-npm-a1b2c3d4...

или при первом run:

Cache not found for input keys: Linux-npm-...

Попробуйте: второй push без изменения package-lock.json — время step npm ci обычно падает.


3. Секреты — API-токен без утечки в Git

Задача: вызвать внешний API из CI, токен хранится только в Settings.

Шаг 1 — в GitHub UI:

Settings → Secrets and variables → Actions → New repository secret

ПолеЗначение
NameAPI_TOKEN
Secretваш токен (строка)

Шаг 2 — в YAML:

- name: Deploy with token
env:
API_TOKEN: ${{ secrets.API_TOKEN }}
run: |
curl -sf -H "Authorization: Bearer $API_TOKEN" \
https://api.example.com/deploy

Разбор построчно:

СтрокаСмысл
name: Deploy with tokenПодпись step в UI (необязательно, но удобно)
env:Переменные окружения только для этого step
API_TOKEN: ${{ secrets.API_TOKEN }}GitHub подставит секрет перед запуском shell
run: |Многострочный shell-скрипт
curl -sf-s тихо, -f exit code ≠ 0 при HTTP 4xx/5xx — step станет красным
$API_TOKENShell-переменная из env (без ${{ }} внутри run)

GITHUB_TOKEN — секрет создаётся автоматически на каждый run. Нужен для push в тот же репозиторий (ветка gh-pages, releases). Пишут ${{ secrets.GITHUB_TOKEN }}.

Секрет в истории Git

Токен в коммите остаётся в истории навсегда. Отзовите ключ, очистите историю (git filter-repo / BFG), создайте секрет заново. В YAML — только ${{ secrets.NAME }}.

Попробуйте: step run: echo "token length is ${#API_TOKEN}" с секретом в env — в логе число символов, сам токен скрыт ***.


4. Артефакты — сохранить папку build/

Задача: после сборки положить dist/ в zip — скачать из UI без повторной сборки локально.

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci && npm run build
- uses: actions/upload-artifact@v4
with:
name: web-dist
path: dist/
retention-days: 7

Разбор построчно:

СтрокаСмысл
npm run buildСоздаёт папку dist/ (Vite, Vue CLI) или build/ (CRA, Docusaurus)
upload-artifact@v4Упаковывает папку и загружает в хранилище GitHub
name: web-distИмя zip в UI run → Artifacts
path: dist/Что положить в zip
retention-days: 7Удалить через 7 дней (экономия квоты)

Что увидите: внизу страницы run ссылка Artifacts → web-dist — скачать zip.

Передача между job:

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run build
- uses: actions/upload-artifact@v4
with:
name: site
path: dist/

deploy:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
name: site
path: dist/
- run: ls -la dist/

Разбор связки:

  • needs: build — job deploy стартует после успешного build.
  • download-artifact — распаковывает zip в dist/ на новой ВМ (у каждого job свой runner).

5. Условный деплой только с main

Задача: тесты на всех ветках и PR; выкладка на Pages — только push в main.

name: Test and deploy

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

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci && npm test

deploy:
needs: test
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci && npm run build
- uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist
publish_branch: gh-pages

Разбор построчно — job deploy:

СтрокаСмысл
needs: testЖдём зелёный job test
if: github.event_name == 'push' && github.ref == 'refs/heads/main'PR и push в develop → job пропускается (skipped)
permissions: contents: writeБез этого GITHUB_TOKEN только читает репо — push в gh-pages упадёт
peaceiris/actions-gh-pages@v4Community action: коммитит содержимое publish_dir в ветку gh-pages
publish_dir: ./distОткуда брать HTML/CSS/JS
publish_branch: gh-pagesКуда пушить (GitHub Pages читает эту ветку)

Что увидите при PR: job test зелёный, deploy серый Skipped.

Попробуйте: Vite/React часто пишет в dist, Docusaurus — в build. Проверьте локально npm run build и подставьте правильную папку.


6. Официальный деплой GitHub Pages

Задача: опубликовать статику через официальные action deploy-pages (без peaceiris).

name: Deploy Pages

on:
push:
branches: [main]
workflow_dispatch:

permissions:
contents: read
pages: write
id-token: write

concurrency:
group: pages
cancel-in-progress: true

jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- uses: actions/checkout@v4
- uses: actions/configure-pages@v5
- uses: actions/upload-pages-artifact@v3
with:
path: .
- id: deployment
uses: actions/deploy-pages@v4

Разбор построчно — верх файла:

СтрокаСмысл
permissions: pages: writeПраво публиковать на Pages
id-token: writeOIDC-токен для безопасной авторизации
concurrency: group: pagesОдин deploy Pages одновременно
cancel-in-progress: trueНовый push отменяет старый незавершённый deploy
environment: github-pagesСвязь с Settings → Environments (опционально protection rules)
url: ${{ steps.deployment.outputs.page_url }}Ссылка на сайт в UI run
configure-pages@v5Подготовка Pages
upload-pages-artifactZip для Pages
id: deploymentИмя step — ссылка steps.deployment.outputs.page_url
deploy-pages@v4Финальная публикация
path: .Корень репо = готовый HTML. После сборки укажите path: build

В Settings → Pages источник должен быть GitHub Actions, не «Deploy from a branch».

Попробуйте: перед upload добавьте npm ci, npm run build, смените path на build.


7. Расписание cron — ночной smoke test

Задача: раз в сутки проверить, что API отвечает 200.

name: Nightly smoke

on:
schedule:
- cron: '0 6 * * *'
workflow_dispatch:

jobs:
ping:
runs-on: ubuntu-latest
steps:
- run: |
code=$(curl -s -o /dev/null -w "%{http_code}" https://httpbin.org/status/200)
echo "HTTP code: $code"
test "$code" = "200"

Разбор построчно:

СтрокаСмысл
schedule:Запуск по cron (UTC!)
cron: '0 6 * * *'Каждый день в 06:00 UTC (= 09:00 МСК зимой)
curl -s -o /dev/nullТело ответа выбросить
-w "%{http_code}"Напечатать только код статуса
test "$code" = "200"Shell: если не 200 — exit 1 → красный step

Формат cron (5 полей): минута час день_месяца месяц день_недели

ПримерЗначение
'0 6 * * *'Каждый день 06:00 UTC
'0 */4 * * *'Каждые 4 часа
'30 8 * * 1-5'Пн–Пт в 08:30 UTC

Расписание работает только на default branch (main).

Попробуйте: workflow_dispatch + Run workflow — отладка без ожидания ночи.


8. Concurrency — отмена старых run

Задача: десять push подряд в PR — не ждать десять одинаковых CI, отменять устаревшие.

Добавьте на уровне workflow (рядом с on:, не внутри job):

name: Fast CI

on: [push, pull_request]

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

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm test

Разбор построчно:

СтрокаСмысл
group: ci-${{ github.workflow }}-${{ github.ref }}Одна «очередь» на пару workflow + ветка/PR
cancel-in-progress: trueНовый run убивает предыдущий незавершённый

Что увидите: первый run со статусом Cancelled, последний — актуальный результат.


9. Reusable workflow — один шаблон для всех студентов

Задача: преподаватель держит эталон CI, студенты подключают одной строкой.

Репозиторий org/ci-templates/.github/workflows/node-test.yml:

name: Reusable Node test

on:
workflow_call:
inputs:
node-version:
required: false
type: string
default: '20'

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
- run: npm ci
- run: npm test

Разбор:

КлючСмысл
workflow_callЭтот workflow не стартует от push — только когда его вызвали
inputs.node-versionПараметр от вызывающего workflow
${{ inputs.node-version }}Значение параметра внутри reusable

В проекте студента .github/workflows/ci.yml:

name: CI

on: [push, pull_request]

jobs:
call-shared:
uses: org/ci-templates/.github/workflows/node-test.yml@main
with:
node-version: '20'

Разбор вызова:

  • uses: org/repo/path@main@main = ветка шаблона (можно @v1 tag).
  • Один репозиторий — локально: uses: ./.github/workflows/node-test.yml.

10. Docker — проверить сборку Dockerfile

Задача: убедиться, что образ собирается на CI (для отчёта по DevOps).

name: Docker build

on: [push, pull_request]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v6
with:
context: .
push: false
tags: myapp:ci

Разбор построчно:

СтрокаСмысл
setup-buildx-actionСовременный движок сборки Docker
build-push-actiondocker build внутри action
context: .Dockerfile и контекст — корень репо
push: falseНе пушить в registry — только проверка сборки
tags: myapp:ciЛокальное имя образа на runner

Попробуйте: push: true + docker/login-action + GHCR — для продвинутых проектов; теория — контейнеризация. Сначала убедитесь, что локальный Dockerfile собирается — примеры Node, Python, Go с построчным разбором.


Реальный пример — деплой этого сайта

Workflow it-knowledge-base — Docusaurus на GitHub Pages.

name: Deploy to GitHub Pages

on:
push:
branches: [main]

permissions:
contents: write

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: rm -rf .docusaurus .cache build
- run: npm run build
- uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./build
publish_branch: gh-pages
force_orphan: true
user_name: 'github-actions[bot]'
user_email: 'github-actions[bot]@users.noreply.github.com'

Разбор построчно — каждый step:

StepЧто делаетЗачем
checkout + fetch-depth: 0Клон с полной историейDocusaurus показывает дату последнего изменения страницы
setup-node 20Node LTS на runnerСовпадает с engines проекта
npm ciУстановка по lock-файлуВоспроизводимая сборка
rm -rf .docusaurus .cache buildУдалить старый кэш сборкиЛечит «залипший» битый build на runner
npm run buildDocusaurus → папка build/Готовый статический сайт
peaceiris/actions-gh-pagesPush build/ в gh-pagesGitHub Pages отдаёт сайт читателям
force_orphan: trueВетка gh-pages без историиТолько HTML, без исходников
user_name / user_emailАвтор коммита — botВ history видно github-actions[bot]

Цепочка для отчёта:

push main → Actions deploy.yml → npm run build → ветка gh-pages → spirzen.ru

Подробнее с DNS и Settings — кейс GitHub Pages.


Badge «CI passing» в README

Задача: в README красивая картинка статуса последнего run.

![CI](https://github.com/USER/REPO/actions/workflows/node-ci.yml/badge.svg)

Разбор URL:

ЧастьЗамените на
USERваш логин GitHub
REPOимя репозитория
node-ci.ymlимя файла workflow без пути

Пример для этого репозитория:

![Deploy](https://github.com/Spirzen/it-knowledge-base/actions/workflows/deploy.yml/badge.svg)

Статус обновляется после каждого run. Красный badge = последний run упал.


Частые ошибки — симптом и лечение

Симптом в логеЧастая причинаЧто сделать
Workflow не появился в ActionsФайл не в .github/workflows/Проверьте путь и расширение .yml
yaml syntax errorТабы вместо пробеловПереведите отступы на 2 пробела
npm ERR! Missing script: "test"Нет "test" в package.jsonДобавьте скрипт или замените команду
npm ci can only install with package-lockНет lock-файлаnpm install локально, закоммитьте lock
Permission denied при gh-pagesНет permissions: contents: writeДобавьте блок permissions
No such file or directory: distНеверная папка сборкиЛокально npm run build, посмотрите имя папки
Secret пустойОпечатка secrets.API_TOKENИмя = как в Settings, регистр важен
Сайт без CSS на PagesНеверный base / homepageДля project site нужен /repo-name/ в конфиге
Два deploy подрядНет concurrencycancel-in-progress: true
PR без ChecksТолько push в workflowДобавьте pull_request в on:
Как читать красный лог

Откройте упавший step → прокрутите вверх от ##[error] → найдите первую строку с Error:, FAIL или exit code 1. Часто ошибка в step выше, чем кажется (например, npm ci упал из-за lock-файла).


Шпаргалка — что вставить в отчёт по лабораторной

Краткий текст для пояснительной записки (адаптируйте под свой проект):

В репозитории настроен CI на GitHub Actions. Файл .github/workflows/node-ci.yml описывает pipeline: при push и pull request запускается job на виртуальной машине ubuntu-latest, выполняется checkout кода, установка Node.js 20, команда npm ci для установки зависимостей и npm test для автоматического тестирования. Результат отображается во вкладке Actions и в статусах pull request. Это обеспечивает непрерывную интеграцию (CI) — проверку кода на каждое изменение без ручного запуска тестов на машине разработчика.


Куда дальше

ЗадачаМатериал
Теория CI/CD, runner, eventsGitHub Actions
Все ключи YAML, contextsСправочник
E2E в браузереPlaywright и Actions
Git, PR, branch protectionОсновы Git
Деплой сайта с нуляКейс GitHub Pages
HTTP в job (curl)curl / fetch — примеры
Bash-скрипты в stepBash — однострочники, production

См. также

Другие статьи этого же раздела в боковом меню (как на странице "О разделе").

Освоение главы0%