# CI/CD Pipeline Generator: AI собирает GitHub Actions за 5 минут

> Промпты для генерации GitHub Actions с помощью AI. Multi-stage pipelines, матричные билды, кеширование, секреты, деплой. Рабочие YAML-примеры и best practices.
> Author: Roman Belov · Published: 2026-04-05 · Source: https://futurecraft.pro/ru/blog/cicd-pipeline-generator/

Большинство разработчиков копируют CI/CD конфиги из прошлых проектов и адаптируют вручную. Каждый раз одни и те же шаги: checkout, установка зависимостей, линтер, тесты, билд, деплой. AI-модели генерируют рабочие GitHub Actions workflows за один промпт, но результат зависит от качества этого промпта.

В этой статье: структурированные промпты, которые выдают production-ready пайплайны. Не абстрактные советы, а конкретные шаблоны для Node.js, Python, Docker и multi-stage деплоя.

## Анатомия промпта для CI/CD генерации

AI-модель генерирует YAML тем точнее, чем конкретнее описан контекст — тот же принцип, что в [context engineering для LLM](/ru/blog/context-engineering-guide/): структурированный вход даёт структурированный выход. Промпт для GitHub Actions должен содержать пять элементов:

1. **Стек и версии** — язык, runtime, package manager
2. **Триггеры** — на какие события запускать pipeline
3. **Стадии** — что именно проверять и в каком порядке
4. **Инфраструктура** — где деплоить, какие секреты нужны
5. **Ограничения** — таймауты, concurrency, условия пропуска

Промпт без этих элементов выдаст generic-конфиг, который придётся переписывать. Промпт со всеми пятью генерирует workflow, готовый к commit.

Базовый шаблон промпта:

```
Generate a GitHub Actions workflow for:
- Stack: [language] [version], [package manager]
- Triggers: push to main, pull_request to main
- Steps: install deps, lint, test, build
- Cache: [package manager] cache
- Node version matrix: [versions]
- Fail fast: true
- Timeout: 15 minutes per job
```

## Первый промпт: Node.js с матричным тестированием

Начнём с типовой задачи. Нужен pipeline для TypeScript-проекта: линтинг, тесты на нескольких версиях Node.js, билд.

**Промпт:**

```
Generate a GitHub Actions workflow for a TypeScript project:
- Runtime: Node.js 18, 20, 22 (matrix strategy)
- Package manager: pnpm 9 with caching
- Triggers: push to main, pull_request to main
- Jobs: lint (single node version), test (matrix), build (single, needs test)
- Lint: eslint + prettier check
- Test: vitest with coverage, upload coverage artifact
- Build: tsc --noEmit, then vite build
- Fail fast: false (run all matrix combinations)
- Timeout: 10 minutes per job
- Concurrency: cancel in-progress runs for same PR
```

AI сгенерирует следующий workflow:

```yaml
name: CI

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

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

jobs:
  lint:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@v4

      - uses: pnpm/action-setup@v4
        with:
          version: 9

      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: pnpm

      - run: pnpm install --frozen-lockfile
      - run: pnpm lint
      - run: pnpm prettier --check .

  test:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    strategy:
      fail-fast: false
      matrix:
        node-version: [18, 20, 22]
    steps:
      - uses: actions/checkout@v4

      - uses: pnpm/action-setup@v4
        with:
          version: 9

      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: pnpm

      - run: pnpm install --frozen-lockfile
      - run: pnpm test -- --coverage

      - uses: actions/upload-artifact@v4
        if: matrix.node-version == 22
        with:
          name: coverage-report
          path: coverage/

  build:
    needs: [lint, test]
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@v4

      - uses: pnpm/action-setup@v4
        with:
          version: 9

      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: pnpm

      - run: pnpm install --frozen-lockfile
      - run: pnpm tsc --noEmit
      - run: pnpm build
```

Ключевые детали, которые AI корректно обработал: `--frozen-lockfile` для воспроизводимости, кеш pnpm через встроенную опцию `actions/setup-node`, загрузка coverage только с одной версии Node.js, `concurrency` для отмены устаревших запусков.

## Промпт для Python: тесты + линтинг + публикация пакета

Python-проекты требуют другой структуры. Виртуальное окружение, зависимости через pip или poetry, специфика кеширования.

**Промпт:**

```
Generate GitHub Actions workflow for a Python library:
- Python versions: 3.11, 3.12, 3.13 (matrix)
- Dependency manager: poetry with caching
- Triggers: push to main, pull_request, release published
- Jobs:
  1. quality: ruff check + ruff format --check + mypy (single python version)
  2. test: pytest with matrix, upload junit xml
  3. publish: build wheel, publish to PyPI (only on release event)
- Publish uses trusted publishing (OIDC), no API tokens
- Timeout: 15 minutes
```

```yaml
name: CI/CD

on:
  push:
    branches: [main]
  pull_request:
  release:
    types: [published]

jobs:
  quality:
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-python@v5
        with:
          python-version: "3.13"

      - name: Install poetry
        run: pipx install poetry

      - name: Cache poetry
        uses: actions/cache@v4
        with:
          path: ~/.cache/pypoetry
          key: poetry-${{ hashFiles('poetry.lock') }}

      - run: poetry install --no-interaction
      - run: poetry run ruff check .
      - run: poetry run ruff format --check .
      - run: poetry run mypy src/

  test:
    runs-on: ubuntu-latest
    timeout-minutes: 15
    strategy:
      fail-fast: false
      matrix:
        python-version: ["3.11", "3.12", "3.13"]
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}

      - name: Install poetry
        run: pipx install poetry

      - name: Cache poetry
        uses: actions/cache@v4
        with:
          path: ~/.cache/pypoetry
          key: poetry-${{ matrix.python-version }}-${{ hashFiles('poetry.lock') }}

      - run: poetry install --no-interaction
      - run: poetry run pytest --junitxml=results.xml

      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: test-results-${{ matrix.python-version }}
          path: results.xml

  publish:
    if: github.event_name == 'release'
    needs: [quality, test]
    runs-on: ubuntu-latest
    timeout-minutes: 15
    permissions:
      id-token: write
    environment: pypi
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-python@v5
        with:
          python-version: "3.13"

      - name: Install poetry
        run: pipx install poetry

      - run: poetry build
      - uses: pypa/gh-action-pypi-publish@release/v1
```

Обратите внимание на trusted publishing через OIDC. Нет API-токенов в секретах, PyPI верифицирует публикацию через GitHub identity. Это текущий стандарт для open-source пакетов.

## Docker: multi-stage build + registry push

Контейнерные проекты требуют работы с Docker registry, кеширования слоёв и multi-platform builds.

**Промпт:**

```
Generate GitHub Actions for Docker image:
- Triggers: push to main (build+push), pull_request (build only)
- Registry: GitHub Container Registry (ghcr.io)
- Multi-platform: linux/amd64, linux/arm64
- Cache: GitHub Actions cache backend
- Tags: sha, branch name, latest (only on main), semver from git tag
- Scan image with trivy before push
- Timeout: 20 minutes
```

```yaml
name: Docker

on:
  push:
    branches: [main]
    tags: ["v*"]
  pull_request:
    branches: [main]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build:
    runs-on: ubuntu-latest
    timeout-minutes: 20
    permissions:
      contents: read
      packages: write
      security-events: write
    steps:
      - uses: actions/checkout@v4

      - uses: docker/setup-qemu-action@v3

      - uses: docker/setup-buildx-action@v3

      - name: Log in to GHCR
        if: github.event_name != 'pull_request'
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=sha
            type=ref,event=branch
            type=semver,pattern={{version}}
            type=raw,value=latest,enable={{is_default_branch}}

      - name: Build and push
        uses: docker/build-push-action@v6
        with:
          context: .
          platforms: linux/amd64,linux/arm64
          push: ${{ github.event_name != 'pull_request' }}
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

      - name: Scan with Trivy
        uses: aquasecurity/trivy-action@v0.36.0
        with:
          image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:sha-${{ github.sha }}
          format: sarif
          output: trivy-results.sarif

      - name: Upload scan results
        if: always()
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: trivy-results.sarif
```

`docker/metadata-action` автоматически формирует теги по git context. `cache-from: type=gha` использует встроенный кеш GitHub Actions без внешнего registry для кеш-слоёв.

## Multi-stage pipeline: от PR до production

Полноценный деплой-пайплайн включает стадии staging и production с ручным подтверждением. Здесь промпт становится длиннее, потому что описывает бизнес-логику деплоя.

**Промпт:**

```
Generate a multi-stage deployment pipeline:
- Trigger: push to main deploys to staging automatically
- Production deploy: manual workflow_dispatch with environment approval
- Stages: test → build → deploy-staging → deploy-production
- Deploy target: Cloudflare Pages (staging and production)
- Environment secrets: CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID
- Build artifact shared between deploy jobs
- Slack notification on deploy success/failure
- Production requires GitHub environment protection rules
```

```yaml
name: Deploy

on:
  push:
    branches: [main]
  workflow_dispatch:
    inputs:
      environment:
        description: "Deploy target"
        required: true
        type: choice
        options:
          - staging
          - production

jobs:
  test:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm
      - run: npm ci
      - run: npm test

  build:
    needs: test
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm
      - run: npm ci
      - run: npm run build

      - uses: actions/upload-artifact@v4
        with:
          name: build-output
          path: dist/
          retention-days: 3

  deploy-staging:
    if: github.event_name == 'push' || inputs.environment == 'staging'
    needs: build
    runs-on: ubuntu-latest
    timeout-minutes: 10
    environment:
      name: staging
      url: https://staging.example.com
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: build-output
          path: dist/

      - name: Deploy to Cloudflare Pages
        uses: cloudflare/wrangler-action@v3
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
          command: pages deploy dist/ --project-name=my-project --branch=staging

      - name: Notify Slack
        if: always()
        uses: slackapi/slack-github-action@v2
        with:
          webhook: ${{ secrets.SLACK_WEBHOOK }}
          webhook-type: incoming-webhook
          payload: |
            {
              "text": "Staging deploy ${{ job.status }}: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
            }

  deploy-production:
    if: inputs.environment == 'production'
    needs: build
    runs-on: ubuntu-latest
    timeout-minutes: 10
    environment:
      name: production
      url: https://example.com
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: build-output
          path: dist/

      - name: Deploy to Cloudflare Pages
        uses: cloudflare/wrangler-action@v3
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
          command: pages deploy dist/ --project-name=my-project --branch=main

      - name: Notify Slack
        if: always()
        uses: slackapi/slack-github-action@v2
        with:
          webhook: ${{ secrets.SLACK_WEBHOOK }}
          webhook-type: incoming-webhook
          payload: |
            {
              "text": "Production deploy ${{ job.status }}: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
            }
```

Билд-артефакт создаётся один раз и переиспользуется в обоих деплоях. Staging деплоится автоматически на push в main. Production требует ручного запуска через `workflow_dispatch` и подтверждения через GitHub environment protection rules.

## Best practices: что AI пропускает

AI-модели генерируют структурно корректные workflows, но систематически пропускают несколько вещей. Чеклист для ревью сгенерированного пайплайна.

### Безопасность

**Pinning actions по SHA.** Стандартный `uses: actions/checkout@v4` использует мажорный тег. Вредоносный maintainer может перезаписать тег. Production-пайплайны пиннят по SHA:

```yaml
# Вместо этого
- uses: actions/checkout@v4

# Используйте это
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.7
```

Добавьте в промпт: `Pin all third-party actions to full SHA commit hash with version comment`.

**Минимальные permissions.** GitHub Actions по умолчанию дают `write` доступ ко всему репозиторию. Задавайте явно:

```yaml
permissions:
  contents: read
  packages: write
```

**Секреты.** AI иногда предлагает хардкодить значения или использовать `${{ secrets.GITHUB_TOKEN }}` там, где нужен отдельный токен. Всегда проверяйте, какие секреты использует workflow. Подробнее о дырах безопасности в AI-коде — в [чеклисте AI security audit](/ru/blog/ai-security-audit/).

### Производительность

**Кеширование.** `actions/setup-node` с параметром `cache` быстрее, чем ручной `actions/cache`. Но для монорепо с несколькими `package.json` встроенный кеш не работает — нужен `actions/cache` с кастомным ключом.

**Параллельные jobs.** AI часто выстраивает все jobs в линейную цепочку через `needs`. Lint и test можно запускать параллельно:

```yaml
build:
  needs: [lint, test]  # lint и test запускаются параллельно
```

**Conditional steps.** Пропускайте тяжёлые шаги, если изменились только документы:

```yaml
- name: Check for code changes
  id: changes
  uses: dorny/paths-filter@v3
  with:
    filters: |
      code:
        - 'src/**'
        - 'package.json'

- name: Run tests
  if: steps.changes.outputs.code == 'true'
  run: npm test
```

### Надёжность

**Retry для flaky шагов.** Сетевые операции (npm install, docker push) падают из-за таймаутов. Добавьте retry:

```yaml
- name: Install dependencies
  uses: nick-fields/retry@v3
  with:
    timeout_minutes: 5
    max_attempts: 3
    command: npm ci
```

**Таймауты.** Без `timeout-minutes` job может висеть до 6 часов (дефолт GitHub). Всегда задавайте явный таймаут.

**Concurrency.** Без `concurrency` группы два push подряд запустят два одинаковых пайплайна. Для PR-чеков отменяйте предыдущие запуски:

```yaml
concurrency:
  group: ci-${{ github.ref }}
  cancel-in-progress: ${{ github.event_name == 'pull_request' }}
```

## Продвинутые промпты: reusable workflows и composite actions

Когда проектов много и каждый хранит копию одного CI/CD конфига, обновление превращается в рутину. GitHub поддерживает reusable workflows и composite actions для переиспользования.

**Промпт для reusable workflow:**

```
Generate a reusable GitHub Actions workflow (.github/workflows/reusable-node-ci.yml):
- Callable via workflow_call
- Inputs: node-version (string, default "22"), package-manager (string, default "pnpm"), run-lint (boolean, default true)
- Secrets: inherited
- Jobs: install, lint (conditional on input), test, build
- Cache based on package manager input
```

```yaml
name: Node.js CI (Reusable)

on:
  workflow_call:
    inputs:
      node-version:
        type: string
        default: "22"
      package-manager:
        type: string
        default: "pnpm"
      run-lint:
        type: boolean
        default: true

jobs:
  ci:
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - uses: actions/checkout@v4

      - if: inputs.package-manager == 'pnpm'
        uses: pnpm/action-setup@v4
        with:
          version: 9

      - uses: actions/setup-node@v4
        with:
          node-version: ${{ inputs.node-version }}
          cache: ${{ inputs.package-manager }}

      - name: Install (npm)
        if: inputs.package-manager == 'npm'
        run: npm ci

      - name: Install (pnpm)
        if: inputs.package-manager == 'pnpm'
        run: pnpm install --frozen-lockfile

      - name: Lint
        if: inputs.run-lint
        run: ${{ inputs.package-manager }} run lint

      - run: ${{ inputs.package-manager }} test
      - run: ${{ inputs.package-manager }} run build
```

Вызов из другого репозитория:

```yaml
jobs:
  ci:
    uses: my-org/.github/.github/workflows/reusable-node-ci.yml@main
    with:
      node-version: "20"
      package-manager: pnpm
      run-lint: true
    secrets: inherit
```

Один конфиг обновляется в центральном репозитории и применяется ко всем проектам организации.

## Итеративная доработка: prompt chaining

Сложные пайплайны редко получаются с первого промпта. Цепочка промптов:

1. **Базовый промпт** — генерирует скелет workflow
2. **Промпт-ревью** — "Review this workflow for security issues, missing caches, and unnecessary steps"
3. **Промпт-оптимизация** — "Optimize this workflow to run under 5 minutes by parallelizing jobs"
4. **Промпт-расширение** — "Add Slack notifications, artifact uploads, and deployment to staging"

Каждый шаг уточняет результат предыдущего. Модель видит контекст и вносит точечные правки вместо перегенерации. Если таких промптов накапливается много по разным проектам, наводить порядок помогает [система prompt engineering](/ru/blog/prompt-engineering-system/).

Пример промпта-ревью:

```
Review this GitHub Actions workflow for:
1. Security: pinned actions, minimal permissions, secret handling
2. Performance: caching, parallelism, conditional execution
3. Reliability: timeouts, retry, concurrency groups
4. Maintainability: DRY (reusable workflows), clear naming

List issues as: [SEVERITY] description → fix
```

AI выдаст структурированный список проблем с конкретными исправлениями. Этот паттерн работает и как [code review через AI-агентов](/ru/blog/claude-concilium-multi-agent-code-review/), только применённый к инфраструктурному коду.

## Защита от каскадных сбоев в pipeline

CI/CD пайплайн зависит от внешних сервисов: npm registry, Docker Hub, облачные провайдеры. Один упавший registry блокирует все деплои. Принципы [circuit breaker](/ru/blog/circuit-breaker-deno-edge-functions/) применимы и здесь:

- **Fallback registry.** Настройте `.npmrc` с резервным registry
- **Retry с backoff.** Сетевые шаги должны повторяться с увеличивающейся задержкой
- **Timeout на каждый шаг.** Не только на job, но и на отдельные step'ы через `timeout-minutes`
- **Cache как circuit breaker.** Если registry недоступен, закешированные зависимости позволяют пайплайну пройти (для тестов, не для деплоя)

## Шаблон промпта: универсальный генератор

Финальный промпт, покрывающий большинство сценариев:

```
Generate a production-ready GitHub Actions workflow:

PROJECT:
- Language: [X], version: [Y]
- Package manager: [Z]
- Monorepo: yes/no

TRIGGERS:
- push: [branches]
- pull_request: [branches]
- release: published
- schedule: [cron]
- workflow_dispatch: [inputs]

JOBS (in dependency order):
1. [job-name]: [description] (runs on: [os], timeout: [min])
2. ...

REQUIREMENTS:
- Pin all third-party actions to SHA
- Minimal permissions per job
- Cache: [strategy]
- Concurrency: cancel in-progress for PRs
- Artifacts: [what to upload]
- Notifications: [Slack/email/none]
- Environments: [staging/production with protection rules]

CONSTRAINTS:
- Total pipeline time: under [X] minutes
- Runner: [ubuntu-latest / self-hosted]
- No secrets in logs (mask sensitive outputs)
```

Заполните квадратные скобки под свой проект. AI сгенерирует workflow, который пройдёт ревью без правок в большинстве случаев. Оставшееся покроет промпт-ревью из предыдущего раздела.

## Результат

AI генерирует GitHub Actions workflows быстрее ручного написания. Качество определяется промптом. Пять элементов (стек, триггеры, стадии, инфраструктура, ограничения) превращают размытый запрос в production-ready конфиг. Reusable workflows масштабируют подход на организацию. Prompt chaining доводит результат до финального качества за 2-3 итерации.

Весь процесс: первый промпт (2 минуты), ревью-промпт (1 минута), точечные правки (2 минуты). Пять минут от идеи до рабочего пайплайна.

---

*Нужна помощь с настройкой CI/CD? Я помогаю стартапам внедрять AI-решения и строить продукты — [belov.works](https://belov.works).*
