Versioning и maintenance actions
Как выпускать и поддерживать actions: semantic tags, immutable releases, changelog, Marketplace metadata, deprecation policy и backward compatibility.
Versioning и maintenance actions
Версионирование action — это публичный контракт между автором и workflow, которые эту action вызывают. В обычной библиотеке breaking change ломает сборку после обновления dependency. В GitHub Actions хуже: чужой uses: owner/action@v1 может стоять в CI, release pipeline или production deploy. Поэтому maintenance action — это не только «поставить tag», а дисциплина: какие версии считаются совместимыми, какие tags можно двигать, где нужен immutable release, что написано в changelog и как заранее предупредить пользователей о deprecation.
Action может быть Composite actions, JavaScript actions или Docker container actions, но release-логика для всех похожа: metadata в action.yml, тесты до публикации, release notes, понятные tags и политика совместимости.
flowchart TD
A[PR в action repo] --> B[CI: tests, lint, smoke workflow]
B --> C{Breaking change?}
C -- нет --> D[Patch/minor release: v1.4.2]
C -- да --> E[Major release: v2.0.0]
D --> F[Draft GitHub Release]
E --> F
F --> G[Release notes + assets]
G --> H[Publish immutable release для точного tag]
H --> I[Обновить floating tags v1 / v1.4, если они не release-bound]
I --> J[README, changelog, Marketplace metadata, deprecation notes]Что именно версионируется
Публичный API action — это не только код. Для пользователя API состоит из:
- uses: acme/release-notes@v1
with:
changelog-path: CHANGELOG.md
fail-on-missing: "true"Здесь контрактом являются имя action, inputs, outputs, side effects, требуемые permissions, поддерживаемые runners, формат файлов, exit codes и даже ожидаемые annotations в логах. Если вы переименовали input, изменили default, перестали поддерживать Windows runner или начали требовать contents: write, это может быть breaking change.
Для Reusable workflows контракт ещё шире: workflow_call inputs, secrets, outputs, jobs, environments и permissions. Но принцип тот же: всё, что caller должен знать заранее, относится к совместимости.
SemVer: v1.4.2, v1.4, v1
На практике для actions обычно используют Semantic Versioning: MAJOR.MINOR.PATCH. Patch — совместимый bugfix, minor — новая совместимая функциональность, major — несовместимое изменение. У GitHub Actions есть своя привычка поверх SemVer: публиковать точный tag v1.4.2 и дополнительно поддерживать moving tags v1.4 и v1.
Пример ожиданий:
v1.4.2 -> конкретный immutable-ish release, удобно для воспроизводимости
v1.4 -> последняя patch-версия в ветке 1.4.x
v1 -> последняя совместимая версия major-линейки 1.x
main -> development branch; не рекомендуется для пользователей
SHA -> максимальная фиксация, но без автоматических bugfix-обновленийGitHub Docs рекомендует не заставлять пользователей ссылаться на default branch: main может содержать ещё нестабильный код. Хороший README показывает спокойный default:
- uses: acme/release-notes@v1А рядом объясняет более строгие варианты:
# Фиксация на конкретный patch release
- uses: acme/release-notes@v1.4.2
# Максимальная фиксация supply chain, но обновления только вручную
- uses: acme/release-notes@8f3c2a4b9d2e1f0a6c7d8e9f0011223344556677Это напрямую связано с Marketplace actions и pinning: автору удобно давать moving major tag, а потребитель в строгой среде может pin по full SHA.
Moving tags и immutable releases
Исторический паттерн для actions такой: при релизе v1.4.2 автор передвигает v1.4 и v1 на новый commit. Это даёт пользователям @v1 security fixes без правки всех workflow.
git tag v1.4.2
git tag -f v1.4 v1.4.2
git tag -f v1 v1.4.2
git push origin v1.4.2
git push -f origin v1.4 v1Но immutable releases меняют правила. Если release опубликован как immutable, связанные assets и Git tag защищены от изменения после публикации. Это хорошо для supply chain: уже опубликованный v1.4.2 не должен внезапно стать другим кодом. Цена — нельзя использовать release-bound tag как moving pointer. Поэтому разумная схема такая: точные release tags (v1.4.2) публикуются как immutable releases, а floating tags (v1, v1.4) остаются обычными Git tags, не привязанными к GitHub Release, если вы хотите их двигать.
Для immutable release GitHub рекомендует сначала создать draft release, прикрепить все assets, проверить notes, а потом publish. После публикации исправлять «забыл файл» уже нельзя без нового release.
Release workflow для автора action
Минимально зрелый процесс выглядит так:
Для JavaScript action добавляется важная деталь: если action исполняется из bundled dist/, release должен гарантировать, что dist/ соответствует исходникам. Иначе пользователь получает tag, где TypeScript поменяли, а compiled bundle забыли обновить. Это нормальная причина иметь отдельный release workflow.
name: release
on:
release:
types: [published]
permissions:
contents: write
jobs:
verify-release:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.event.release.tag_name }}
- uses: actions/setup-node@v6
with:
node-version: 24
cache: npm
- run: npm ci
- run: npm test
- run: npm run build
- run: git diff --exit-code dist/ action.ymlВ реальном проекте можно добавлять smoke-test workflow, который вызывает action как внешний пользователь. Это ловит ошибки уровня uses, with, outputs и path handling, которые unit-тесты не видят. Если action публикует отчёты, проверьте Artifacts и reports; если пишет summary, проверьте Workflow commands и summaries.
Marketplace metadata
GitHub Marketplace берёт карточку action из repository release и metadata-файла. Для публикации action repository должен быть public, в корне должен быть один основной action.yml или action.yaml, а name должен быть уникальным. В action.yml важны не только runs, inputs и outputs, но и описание, author и branding.
name: "Release Notes Guard"
description: "Validate changelog entries before publishing a release"
author: "Acme CI"
inputs:
changelog-path:
description: "Path to CHANGELOG.md"
required: false
default: "CHANGELOG.md"
outputs:
changed:
description: "true when the release section exists"
branding:
icon: "check-circle"
color: "green"
runs:
using: "node24"
main: "dist/index.js"Marketplace — не аудит безопасности. Публикация делает action discoverable, но не превращает её в trusted dependency. Поэтому README должен явно показывать required Permissions и GITHUB_TOKEN, supported runners, examples, upgrade notes и security contact.
Backward compatibility и deprecation
Самый частый maintenance-провал — «мы просто улучшили input». Например, было:
with:
token: ${{ secrets.GITHUB_TOKEN }}Потом автор решил переименовать input в github-token. Для новых пользователей красивее, но старые workflow падают. Совместимый вариант — поддерживать оба input в рамках v1, пометить старый как deprecated в README и warning annotation, а удалить только в v2.
v1.5.0: добавлен input github-token, token deprecated
v1.x: token продолжает работать
v2.0.0: token удалён, github-token обязателенDeprecation policy должна быть скучной и явной: что deprecated, с какой версии, чем заменить, когда будет удалено, есть ли codemod или пример миграции. Для security-sensitive изменений иногда нужен быстрый major, но всё равно лучше дать понятный migration guide.
Changelog, support window и security
Changelog для action должен быть написан с позиции пользователя workflow: «какие inputs изменились», «какие permissions теперь нужны», «какие runners больше не поддерживаются», «какой output добавлен». Внутреннее «refactor parser» полезно только если влияет на поведение.
Хорошая release note для action выглядит так:
v1.6.0
Added
- Added
format: json|markdowninput. Default remainsmarkdown.
Fixed
- Fixed Windows path handling for changelog files in nested folders.
Security
- Reduced default token usage;
contents: readis enough unlesscreate-release: true.
Deprecated
tokeninput is deprecated. Usegithub-token; removal planned for v2.
Maintenance также включает Dependabot для dependencies, vulnerability reporting через `SECURITY.md`, CI на pull requests и осторожность с untrusted PR. Если release workflow имеет `contents: write`, не запускайте его на коде из непроверенного fork. Это уже область [Secure use и threat model](/course/ec671477-2168-479f-9d68-bc3280c672bd/lessons/28) и [pull_request_target и untrusted PR](/course/ec671477-2168-479f-9d68-bc3280c672bd/lessons/29).
### See also
- [Marketplace actions и pinning](/course/ec671477-2168-479f-9d68-bc3280c672bd/lessons/22) — как потребители выбирают tag, SHA и trust model.
- [JavaScript actions](/course/ec671477-2168-479f-9d68-bc3280c672bd/lessons/25) — packaging, `dist/`, runtime compatibility и release artifacts.
- [Docker container actions](/course/ec671477-2168-479f-9d68-bc3280c672bd/lessons/26) — versioning container images и digest-подход.
- [Composite actions](/course/ec671477-2168-479f-9d68-bc3280c672bd/lessons/24) — совместимость shell steps, inputs и outputs.
- [Reusable workflows](/course/ec671477-2168-479f-9d68-bc3280c672bd/lessons/23) — versioning целых pipelines через `workflow_call`.
- [Permissions и GITHUB_TOKEN](/course/ec671477-2168-479f-9d68-bc3280c672bd/lessons/5) — как документировать минимальные права action.
- [Secure use и threat model](/course/ec671477-2168-479f-9d68-bc3280c672bd/lessons/28) — supply chain, pinning и release trust.
Внешние справки: GitHub Docs по release and maintain actions, managing custom actions, immutable releases, Marketplace publishing и metadata syntax; спецификация Semantic Versioning 2.0.0.Источники
- GitHub Docs: Releasing and maintaining actions
- GitHub Docs: Managing custom actions
- GitHub Docs: Using immutable releases and tags to manage your action's releases
- GitHub Docs: Immutable releases
- GitHub Docs: Preventing changes to your releases
- GitHub Docs: Verifying the integrity of a release
- GitHub Docs: Publishing actions in GitHub Marketplace
- GitHub Docs: Metadata syntax reference
- GitHub Docs: Managing releases in a repository
- Semantic Versioning 2.0.0
