GitHub Actions
Workflow GitHub Actions — on, jobs, runs-on, steps uses/run, needs, matrix, выражения, workflow_call, actionlint
GitHub Actions запускает workflow — YAML-файлы из каталога .github/workflows/ — по событиям репозитория: push, pull request, расписание, ручной запуск. Workflow состоит из задач (jobs), которые по умолчанию идут параллельно, каждая на своей виртуальной машине (раннере). Задача — это последовательность шагов (steps): готовое действие (uses) или команда оболочки (run).
Проверка в песочнице: actionlint разбирает workflow и находит ошибки в ключах, выражениях ${{ }}, ссылках между задачами, входах популярных действий и (через shellcheck) в скриптах run.
Синтаксис
name: CI
on: push # когда запускать
jobs:
имя_задачи:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: echo hello
Ключи верхнего уровня
| Ключ | Что задаёт |
|---|---|
name / run-name | имя workflow / имя конкретного запуска (можно с выражениями) |
on | события-триггеры |
permissions | права токена GITHUB_TOKEN: contents: read, packages: write… |
env | переменные окружения для всех задач |
defaults: run: | shell и working-directory для всех шагов run |
concurrency | group и cancel-in-progress: не запускать параллельно одинаковые запуски |
jobs | задачи |
События on
| Событие | Когда срабатывает |
|---|---|
push | push; фильтры branches, tags, paths, branches-ignore, paths-ignore |
pull_request | события PR; types: [opened, synchronize], те же фильтры веток и путей |
workflow_dispatch | ручной запуск кнопкой; inputs — параметры формы |
schedule | по расписанию: - cron: '0 3 * * 1' (время UTC) |
workflow_call | вызов из другого workflow (переиспользуемый); inputs, secrets, outputs |
release, issues, workflow_run… | другие события репозитория |
Ключи задачи
| Ключ | Что задаёт |
|---|---|
runs-on | раннер: ubuntu-latest, windows-latest, macos-latest или метки своего раннера |
needs | от каких задач зависит: запустится после их успеха |
if | условие выполнения задачи |
steps | шаги задачи |
env | переменные для всех шагов задачи |
outputs | значения, которые увидят зависимые задачи через needs.<id>.outputs |
strategy.matrix | запустить задачу для каждой комбинации значений; include, exclude |
strategy.fail-fast / max-parallel | отменять ли остальные комбинации при падении / сколько одновременно |
environment | окружение (секреты окружения, правила одобрения) |
container / services | выполнять шаги в контейнере / поднять рядом контейнеры (БД) |
timeout-minutes / continue-on-error | ограничение времени / не валить workflow при ошибке |
uses + with + secrets | вместо steps: вызвать переиспользуемый workflow |
Ключи шага
| Ключ | Что задаёт |
|---|---|
uses: владелец/репо@версия | готовое действие; ./путь — локальное |
with | входные параметры действия |
run | команды оболочки (несколько строк — через |) |
shell | bash, sh, pwsh, python |
name / id | подпись в логе / идентификатор для steps.<id>.outputs |
if | условие выполнения шага |
env | переменные шага |
working-directory | каталог для run |
continue-on-error / timeout-minutes | не валить задачу / ограничение времени |
В одном шаге — либо uses, либо run.
Выражения и контексты
Выражения пишутся в ${{ … }}; в if скобки можно опустить.
| Контекст | Что содержит |
|---|---|
github | событие и репозиторий: github.ref, github.sha, github.event_name, github.actor, github.event.* |
env / vars | переменные окружения / переменные репозитория из настроек |
secrets | секреты: secrets.DEPLOY_TOKEN, secrets.GITHUB_TOKEN |
matrix | значения текущей комбинации матрицы |
needs | результаты и outputs задач из needs |
steps | outputs и исход предыдущих шагов (steps.<id>.outputs.x) |
inputs | параметры workflow_dispatch / workflow_call |
runner | сведения о раннере: runner.os, runner.temp |
| Функция | Что делает |
|---|---|
success(), failure(), always(), cancelled() | статус для if: по умолчанию шаг идёт только при success() |
contains(a, b), startsWith(a, b), endsWith(a, b) | проверки строк и списков |
format('{0}-{1}', a, b), join(список, ',') | сборка строк |
toJSON(x) / fromJSON(s) | в JSON / из JSON |
hashFiles('**/package-lock.json') | хэш файлов — для ключей кэша |
Операторы: ==, !=, &&, ||, !, <, >.
Файлы раннера
| Переменная | Что в неё писать |
|---|---|
$GITHUB_OUTPUT | имя=значение — output шага (steps.<id>.outputs.имя) |
$GITHUB_ENV | ИМЯ=значение — переменная окружения для следующих шагов |
$GITHUB_PATH | каталог, который добавится в PATH следующих шагов |
$GITHUB_STEP_SUMMARY | Markdown для страницы итогов запуска |
Примеры
name: CI
on:
push:
branches: [main]
pull_request:
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node: [20, 22]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- run: npm ci
- run: npm test
build:
needs: test
runs-on: ubuntu-latest
outputs:
version: ${{ steps.ver.outputs.version }}
steps:
- uses: actions/checkout@v4
- id: ver
run: echo "version=1.0.${{ github.run_number }}" >> "$GITHUB_OUTPUT"
- name: Сборка
run: |
mkdir -p dist
echo "built" > dist/app.txt
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
- if: failure()
run: echo "сборка упала"
Переиспользуемый workflow и его вызов:
# .github/workflows/deploy.yml
on:
workflow_call:
inputs:
environment:
type: string
required: true
secrets:
token:
required: true
jobs:
deploy:
runs-on: ubuntu-latest
environment: ${{ inputs.environment }}
steps:
- run: echo "deploy to ${{ inputs.environment }}"
env:
TOKEN: ${{ secrets.token }}
---
# .github/workflows/release.yml
on: workflow_dispatch
jobs:
call:
uses: ./.github/workflows/deploy.yml
with:
environment: production
secrets:
token: ${{ secrets.DEPLOY_TOKEN }}
# проверить все workflow репозитория (запускать внутри git-репозитория)
actionlint
# проверить конкретные файлы
actionlint .github/workflows/ci.yml
# пример сообщения:
# ci.yml:6:5: unexpected key "branch" for "push" section. expected one of "branches", ... [syntax-check]
# посмотреть триггеры через yq (он понимает YAML 1.2 и видит ключ on как строку)
yq '.on | keys' .github/workflows/ci.yml
Подводные камни
onв YAML 1.1 — этоtrue. GitHub иactionlintчитают ключonправильно, но парсеры YAML 1.1 (например, PyYAML в Python-скриптах) превращают его в булевоTrue, иdata['on']даётKeyError. В своих скриптах ищи ключTrueили пиши в файле"on":в кавычках. Так же в YAML 1.1 ведут себяyes/no/off.actionlintбез аргументов ищет git-репозиторий вверх по каталогам. Вне репозитория он завершится с ошибкойno project was found— передай пути к файлам явно.- Workflow должен лежать в
.github/workflows/и иметь расширение.ymlили.yaml, иначе GitHub его не увидит. - Шаг с
usesиrunодновременно — ошибка. Разнеси их по двум шагам. - Ключи с опечатками (
branchвместоbranches,stepвместоsteps,fetch_depthвместоfetch-depth) не дают работающего workflow —actionlintих ловит. needs.<id>.outputsдоступны, только если задача указана вneedsи объявилаoutputs. Иначе выражение пустое, аactionlintпредупредит.- После падения шага следующие пропускаются. Чтобы шаг выполнился всегда (уборка, отчёт), нужен
if: always()илиif: failure(). - Недоверенные данные в
run— инъекция.${{ github.event.pull_request.title }}подставляется в скрипт как текст. Передавай такие значения черезenv:и используй как"$TITLE". scheduleработает по UTC и только для основной ветки репозитория.- Версии действий закрепляй тегом или хэшем (
@v4), а не веткой: ветка может измениться без предупреждения.
См. также
gitlab-ci · git · yq · shellcheck