Генератор CI/CD: промпты и YAML для GitHub Actions
Что такое AI-генерация CI/CD пайплайнов?
AI-генерация CI/CD использует LLM для черновика GitHub Actions YAML по промпту со стеком, триггерами, стадиями, целевой инфраструктурой и ограничениями. Черновик экономит время на настройке, но перед коммитом его всё равно нужно проверить на безопасность и корректность.
TL;DR
- -Полезный промпт для CI/CD охватывает 5 элементов: стек и версии, триггеры, стадии, инфраструктуру и ограничения вроде таймаутов и concurrency.
- -Каждый сгенерированный workflow нужно проверить по 4 пунктам: полные SHA для actions, минимальные permissions, узкий scope секретов и маскирование чувствительного вывода.
- -Ревью в четыре прохода (база → безопасность → оптимизация → расширение) упрощает поиск ошибок по сравнению с одним перегруженным промптом.
- -Reusable workflows через workflow_call устраняют дублирование конфигов между репозиториями - одно обновление распространяется на все проекты организации.
- -Без timeout-minutes на каждый job зависший runner GitHub Actions может блокировать очередь до 6 часов (дефолтный лимит платформы).
Опасность AI-сгенерированного workflow обычно не в невалидном YAML. Чаще модель
забывает permissions, оставляет шестичасовой таймаут или подключает сторонний action
по изменяемому тегу. Черновик появится за минуту, но границы доверия модель не угадает,
если их не указать в промпте.
Ниже — шаблоны для Node.js, Python, Docker и поэтапного деплоя. Для читаемости в примерах используются актуальные мажорные теги. Перед публикацией workflow закрепите каждый внешний action проверенным полным commit SHA и перепроверьте permissions.
Анатомия промпта для CI/CD генерации
AI-модель генерирует YAML тем точнее, чем конкретнее описан контекст - тот же принцип, что в context engineering для LLM: структурированный вход даёт структурированный выход. Промпт для GitHub Actions должен содержать пять элементов:
- Стек и версии - язык, runtime, package manager
- Триггеры - на какие события запускать pipeline
- Стадии - что именно проверять и в каком порядке
- Инфраструктура - где деплоить, какие секреты нужны
- Ограничения - таймауты, concurrency, условия пропуска
Если пропустить один из элементов, модель начнёт угадывать. Все пять дают достаточно конкретный черновик, который можно проверить по устройству репозитория.
Базовый шаблон промпта:
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 22, 24, 26 (matrix strategy)
- Package manager: pnpm 11 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
Модель сгенерирует следующий черновик. Node 24 — LTS-база, Node 22 проверяет старую поддерживаемую ветку, а Node 26 заранее ловит несовместимости с Current. Перед копированием матрицы в долгоживущий репозиторий сверьтесь с расписанием релизов Node.js.
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@v7
- uses: pnpm/action-setup@v4
with:
version: 11
- uses: actions/setup-node@v7
with:
node-version: 24
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: [22, 24, 26]
steps:
- uses: actions/checkout@v7
- uses: pnpm/action-setup@v4
with:
version: 11
- uses: actions/setup-node@v7
with:
node-version: ${{ matrix.node-version }}
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm test -- --coverage
- uses: actions/upload-artifact@v7
if: matrix.node-version == 24
with:
name: coverage-report
path: coverage/
build:
needs: [lint, test]
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v7
- uses: pnpm/action-setup@v4
with:
version: 11
- uses: actions/setup-node@v7
with:
node-version: 24
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, специфика кеширования. Матрица начинается с Python 3.12 и включает актуальную на момент обновления ветку 3.14. При следующем обновлении workflow сверьтесь с официальным списком релизов Python.
Промпт:
Generate GitHub Actions workflow for a Python library:
- Python versions: 3.12, 3.13, 3.14 (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
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@v7
- uses: actions/setup-python@v7
with:
python-version: "3.14"
- name: Install poetry
run: pipx install poetry
- name: Cache poetry
uses: actions/cache@v6
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.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}
- name: Install poetry
run: pipx install poetry
- name: Cache poetry
uses: actions/cache@v6
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@v7
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@v7
- uses: actions/setup-python@v7
with:
python-version: "3.14"
- 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
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@v7
- uses: docker/setup-qemu-action@v4
- uses: docker/setup-buildx-action@v4
- name: Log in to GHCR
if: github.event_name != 'pull_request'
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v6
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@v7
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/[email protected]
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@v4
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
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@v7
- uses: actions/setup-node@v7
with:
node-version: 24
cache: npm
- run: npm ci
- run: npm test
build:
needs: test
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 24
cache: npm
- run: npm ci
- run: npm run build
- uses: actions/upload-artifact@v7
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@v8
with:
name: build-output
path: dist/
- name: Deploy to Cloudflare Pages
uses: cloudflare/wrangler-action@v4
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@v3
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@v8
with:
name: build-output
path: dist/
- name: Deploy to Cloudflare Pages
uses: cloudflare/wrangler-action@v4
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@v3
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@v7 ссылается на
изменяемый тег. В рекомендациях GitHub по безопасности
полный commit SHA назван единственным неизменяемым способом подключить action. Перед
пиннингом проверьте commit в официальном репозитории:
# Вместо этого
- uses: actions/checkout@v7
# Используйте это
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Добавьте в промпт: Pin all third-party actions to full SHA commit hash with version comment.
Минимальные permissions. Дефолт зависит от настроек репозитория и организации. В новом личном репозитории токен получает чтение contents и packages, но у организации может быть другая политика. Задавайте права в workflow явно и не полагайтесь на текущую настройку администратора:
permissions:
contents: read
packages: write
Секреты. AI иногда предлагает хардкодить значения или использовать ${{ secrets.GITHUB_TOKEN }} там, где нужен отдельный токен. Всегда проверяйте, какие секреты использует workflow. Подробнее о дырах безопасности в AI-коде - в чеклисте AI security audit.
Производительность
Кеширование. Встроенный кеш actions/setup-node подходит, когда граф зависимостей
определяет один lockfile. В монорепо укажите правильный lockfile через
cache-dependency-path или используйте actions/cache, если нужен собственный scope
и порядок восстановления.
Параллельные jobs. AI часто выстраивает все jobs в линейную цепочку через needs. Lint и test можно запускать параллельно:
build:
needs: [lint, test] # lint и test запускаются параллельно
Conditional steps. Пропускайте тяжёлые шаги, если изменились только документы:
- 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:
- 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-чеков отменяйте предыдущие запуски:
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 "24"), 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
name: Node.js CI (Reusable)
on:
workflow_call:
inputs:
node-version:
type: string
default: "24"
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@v7
- if: inputs.package-manager == 'pnpm'
uses: pnpm/action-setup@v4
with:
version: 11
- uses: actions/setup-node@v7
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
Вызов из другого репозитория:
jobs:
ci:
uses: my-org/.github/.github/workflows/reusable-node-ci.yml@main
with:
node-version: "24"
package-manager: pnpm
run-lint: true
secrets: inherit
Один конфиг обновляется в центральном репозитории и применяется ко всем проектам организации.
Итеративная доработка: prompt chaining
Сложные пайплайны редко получаются с первого промпта. Цепочка промптов:
- Базовый промпт - генерирует скелет workflow
- Промпт-ревью - “Review this workflow for security issues, missing caches, and unnecessary steps”
- Промпт-оптимизация - “Optimize this workflow to run under 5 minutes by parallelizing jobs”
- Промпт-расширение - “Add Slack notifications, artifact uploads, and deployment to staging”
Каждый шаг уточняет результат предыдущего. Модель видит контекст и вносит точечные правки вместо перегенерации. Если таких промптов накапливается много по разным проектам, наводить порядок помогает система prompt engineering.
Пример промпта-ревью:
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-агентов, только применённый к инфраструктурному коду.
Защита от каскадных сбоев в pipeline
CI/CD пайплайн зависит от внешних сервисов: npm registry, Docker Hub, облачные провайдеры. Один упавший registry блокирует все деплои. Принципы circuit breaker применимы и здесь:
- 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)
Заполните квадратные скобки и проверяйте результат как инфраструктурный код. Если workflow собирает контейнер, сверяйте build context, порядок слоёв, runtime-содержимое и сканирование с гайдом по Docker multi-stage builds.
Результат
Поручайте модели первый черновик, но не финальное решение. Промпт со стеком, триггерами, стадиями, инфраструктурой и ограничениями даёт ревьюеру конкретный YAML. Перед merge проверьте permissions, границы секретов, SHA внешних actions и таймауты. Когда этот процесс стабилизируется, вынесите повторяющиеся части в reusable workflow, а не генерируйте один и тот же конфиг заново.
Ценный результат — не пятиминутная демка, а проверяемый workflow, в diff которого видны границы доверия и поведение при сбоях.
Нужна помощь с настройкой CI/CD? Я помогаю стартапам внедрять AI-решения и строить продукты - belov.works.
Часто задаваемые вопросы
Пиннить GitHub Actions по полному SHA или достаточно тега версии типа @v7?
Как организовать CI/CD для монорепозитория, где изменились только некоторые сервисы?
dorny/paths-filter для определения изменившихся сервисов, затем закрывать тяжёлые jobs (тесты, билды, деплои) за conditional steps. Каждый сервис получает собственные правила фильтрации; jobs запускаются только при изменении релевантных путей. Это предотвращает ситуацию, когда правка документации в одном сервисе запускает полный билд и деплой несвязанных сервисов. Нативная фильтрация GitHub по on.push.paths снижает частоту триггеров, но не даёт гранулярности для условного запуска конкретных jobs внутри workflow - paths-filter решает эту задачу.
Какая стратегия кеширования зависимостей правильная для GitHub Actions?
actions/setup-node или actions/setup-python. В монорепо укажите нужный lockfile через cache-dependency-path; actions/cache нужен при собственном scope или порядке восстановления. Для Docker-слоёв cache-from: type=gha использует кеш GitHub Actions. Включайте хеш lockfile в ключ кеша зависимостей, чтобы изменения инвалидировали старые записи.