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

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

`workflow_call`, inputs, secrets, outputs, nested workflows, matrix with reusable workflows, limitations с environment secrets и мониторинг использования.

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

Reusable workflows

`workflow_call`, inputs, secrets, outputs, nested workflows, matrix with reusable workflows, limitations с environment secrets и мониторинг использования.

Reusable workflows

Reusable workflow — это workflow-файл, который другой workflow вызывает как целый job. Он лежит в .github/workflows, как обычный workflow, но объявляет специальный trigger workflow_call. Это не Composite actions: composite action собирает несколько steps в один action, а reusable workflow может содержать jobs, runs-on, permissions, environment, outputs и собственную структуру pipeline.

Хороший use case: у организации есть десять репозиториев с одинаковым Node.js CI, Docker build или deploy flow. Вместо copy-paste YAML в каждом repo можно держать один workflow в platform-actions и вызывать его из product repo. Так проще обновлять setup, вводить единые Permissions и GITHUB_TOKEN, менять runner images и проверять deploy-политику.

flowchart TD A[Caller workflow: ci.yml] -->|jobs.node-ci.uses| B[Reusable workflow: node-ci.yml] A -->|with: node-version, run-build| B A -->|secrets: explicit или inherit| B B --> C[Job: test] C --> D[Steps: checkout, setup, test, build] D --> E[Step output через GITHUB_OUTPUT] E --> F[Job output] F --> G[workflow_call output] G -->|needs.node-ci.outputs.report-name| H[Downstream job в caller]
flowchart TD
  A[Caller workflow: ci.yml] -->|jobs.node-ci.uses| B[Reusable workflow: node-ci.yml]
  A -->|with: node-version, run-build| B
  A -->|secrets: explicit или inherit| B
  B --> C[Job: test]
  C --> D[Steps: checkout, setup, test, build]
  D --> E[Step output через GITHUB_OUTPUT]
  E --> F[Job output]
  F --> G[workflow_call output]
  G -->|needs.node-ci.outputs.report-name| H[Downstream job в caller]
Поток данных в reusable workflow: caller передаёт inputs/secrets, called workflow выполняет jobs и возвращает workflow-level outputs.

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

Reusable workflow начинается с контракта: какие inputs принимает, какие secrets ожидает и какие outputs возвращает. Пример файла .github/workflows/node-ci.yml в общем repo:

name: reusable-node-ci

on:
  workflow_call:
    inputs:
      node-version:
        required: true
        type: string
      run-build:
        required: false
        type: boolean
        default: true
    secrets:
      npm-token:
        required: false
    outputs:
      report-name:
        description: "Name of the uploaded test report"
        value: ${{ jobs.test.outputs.report-name }}

jobs:
  test:
    runs-on: ubuntu-24.04
    permissions:
      contents: read
    outputs:
      report-name: ${{ steps.meta.outputs.report-name }}
    steps:
      - uses: actions/checkout@v6

      - uses: actions/setup-node@v6
        with:
          node-version: ${{ inputs.node-version }}
          cache: npm

      - run: npm ci
      - run: npm test
      - if: ${{ inputs.run-build }}
        run: npm run build

      - id: meta
        run: echo "report-name=node-${{ inputs.node-version }}-report" >> "$GITHUB_OUTPUT"

Здесь важно три уровня output: step пишет в $GITHUB_OUTPUT, job мапит step output в jobs.test.outputs, а on.workflow_call.outputs поднимает его наружу для caller workflow. Это та же модель данных, что в Step outputs и job outputs, только добавлен workflow-level слой.

Как caller вызывает workflow

Reusable workflow вызывается через jobs.<job_id>.uses, не внутри steps. Поэтому caller job не пишет runs-on и steps: runner и steps находятся в called workflow.

name: ci

on:
  pull_request:
  push:
    branches: [main]

jobs:
  node-ci:
    permissions:
      contents: read
    uses: octo-org/platform-actions/.github/workflows/node-ci.yml@8b7f2c0a4f0b3a9e6d1c2b5a1234567890abcdef
    with:
      node-version: "22"
      run-build: true
    secrets:
      npm-token: ${{ secrets.NPM_TOKEN }}

  print-report:
    needs: node-ci
    runs-on: ubuntu-24.04
    steps:
      - run: echo "Report: ${{ needs.node-ci.outputs.report-name }}"

Синтаксис бывает внешний и локальный. Для другого repo используется owner/repo/.github/workflows/file.yml@ref; для того же repo — ./.github/workflows/file.yml. Внешний ref может быть branch, tag или commit SHA. По тем же причинам, что в Marketplace actions и pinning, для production-sensitive workflow лучше pin по SHA или по строго контролируемому release tag. Локальный вызов без @ref берёт workflow из того же commit, что и caller.

Есть деталь, которая часто удивляет: если called workflow делает actions/checkout, по умолчанию он checkout-ит репозиторий caller workflow, а не repo, где лежит reusable workflow. Это обычно именно то, что нужно для общего CI: reusable YAML живёт отдельно, но тестирует код вызывающего проекта.

Inputs, secrets и inherit

Inputs в workflow_call типизированы: string, number или boolean. Они доступны через inputs.*, а не как обычные env-переменные. Если нужен env, задайте его явно внутри called workflow:

env:
  NODE_VERSION: ${{ inputs.node-version }}

Secrets передаются отдельно. Можно явно перечислять secrets, как в примере выше, или использовать secrets: inherit, если caller и called workflow находятся в допустимой области доступа — например, в одной organization или enterprise. inherit удобно для внутренних стандартных workflows, но это сильное разрешение: called workflow получает все secrets, к которым имеет доступ caller job. Для deploy и package publish лучше начинать с явного списка.

Во вложенных reusable workflows secrets не «текут» автоматически через всю цепочку. Если A вызывает B, а B вызывает C, то C увидит secret из A только если A передал его B, а B затем передал его C. Это полезное ограничение для Secure use и threat model: каждый переход в цепочке должен быть осознанным.

ИнтерактивСвяжите конструкцию и смысл#int-1
Сопоставьте элемент GitHub Actions с его ролью в reusable workflow.
Быстрая самопроверка по контракту reusable workflow: какие YAML-конструкции за что отвечают.

Matrix with reusable workflows

Caller job может использовать Matrix strategy и вызывать reusable workflow несколько раз с разными inputs:

jobs:
  deploy:
    strategy:
      fail-fast: false
      max-parallel: 1
      matrix:
        target: [dev, stage, prod]
    uses: octo-org/platform-actions/.github/workflows/deploy.yml@v2
    with:
      environment: ${{ matrix.target }}
    secrets: inherit

Такой pattern хорошо подходит для однотипных deployments, browser matrix, language-version matrix и package builds. Но matrix не бесплатна: она создаёт несколько job runs, ест minutes и усложняет outputs. Если reusable workflow с matrix возвращает один output, caller получит значение от последнего успешного reusable workflow, который реально установил этот output. Для отчётов и build artifacts часто лучше использовать Artifacts и reports, а не пытаться склеивать всё в один string output.

Environments и protection rules

Главное ограничение: environment secrets нельзя передать из caller через on.workflow_call, потому что workflow_call не поддерживает keyword environment на уровне контракта. Если called workflow сам указывает environment на job level, он использует secrets именно этого environment внутри called workflow, а не «environment secret, переданный caller».

Практический вариант для deploy reusable workflow — передавать имя environment как input и назначать environment внутри called job:

on:
  workflow_call:
    inputs:
      environment:
        required: true
        type: string

jobs:
  deploy:
    runs-on: ubuntu-24.04
    environment: ${{ inputs.environment }}
    permissions:
      contents: read
      id-token: write
    steps:
      - run: ./scripts/deploy.sh "${{ inputs.environment }}"

Тогда approval, wait timer, branch/tag restrictions и environment secrets работают в месте, где реально выполняется deploy. Это напрямую связано с Environments и protection rules и Deployment workflows: reusable workflow не должен обходить release governance, он должен централизовать его.

Nested workflows, OIDC и мониторинг

Reusable workflow может вызывать другой reusable workflow. GitHub документирует цепочку до десяти уровней: top-level caller плюс до девяти called workflows. Циклы запрещены, все workflows в цепочке должны быть доступны caller, а permissions по цепочке можно только сохранить или сузить, но не повысить. Если reusable deploy получает contents: read, вложенный workflow не должен внезапно стать contents: write.

Для Cloud deploy через OIDC reusable workflows особенно полезны: можно держать один hardened deploy workflow и на стороне cloud role проверять, что OIDC token пришёл именно из этого called workflow. В OIDC token для такого job есть claim job_workflow_ref, который указывает на reusable workflow. Это позволяет строить trust policy не только вокруг caller repo, но и вокруг утверждённого deployment workflow.

{
  "repository": "octo-org/product-api",
  "workflow_ref": "octo-org/product-api/.github/workflows/release.yml@refs/heads/main",
  "job_workflow_ref": "octo-org/platform-actions/.github/workflows/deploy.yml@refs/tags/v2.4.1",
  "environment": "prod"
}

Эксплуатационно reusable workflows нужно мониторить как shared dependency. В GitHub Enterprise Cloud использование можно отслеживать через audit log API; в репозитории caller reused workflows также видны как dependencies в dependency graph. На практике добавляют CODEOWNERS на .github/workflows, changelog для shared workflow repo, pinned refs в caller repos и регулярный review через Monitoring и troubleshooting и Enterprise policies и migration.

Когда это не тот инструмент

Reusable workflow не заменяет всё. Если нужно просто спрятать пять shell steps и вызывать их как один step — берите Composite actions. Если нужна переносимая логика на Node API GitHub — это зона JavaScript actions. Если нужен свой Linux image с зависимостями — смотрите Docker container actions. Reusable workflow выбирают, когда единицей переиспользования является job или pipeline: CI template, deploy policy, release flow, package publish, security scan.

See also

Внешние справки: GitHub Docs по reuse workflows, workflow syntax, reusing workflow configurations и OIDC with reusable workflows.

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

Когда в GitHub Actions стоит выбрать reusable workflow, а не composite action?

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

Когда переиспользуемая единица — целый job или pipeline: CI template, deploy policy, release flow, package publish, security scan. Composite action лучше для упаковки нескольких steps в один step.

Источники

  1. GitHub Docs: Reuse workflows
  2. GitHub Docs: Workflow syntax for GitHub Actions
  3. GitHub Docs: Reusing workflow configurations
  4. GitHub Docs: Using OpenID Connect with reusable workflows