Паровоз dev→testnet→main заменён независимыми указателями: каждое окружение — самостоятельный fast-forward-указатель на выбранный релизный тег dev. Прод и тест катятся разным темпом и на разные версии одновременно, без диверджа и конфликтов (оба — FF-указатели на линейную историю dev). - promote.sh <testnet|main> [ref]: FF выбранного тега (по умолчанию — последний на origin/dev) на ветку окружения; main больше не зависит от testnet; только вперёд. - release.yaml: workflow_dispatch получил inputs environment+ref — откат на старую версию / редеплой без бампа / hotfix в один контур (то, что FF не умеет). Сборка идёт из вычекнутого ref, окружение — из inputs.environment. Авто-триггер по изменению lerna.json сохранён. - RELEASE.md: модель и инварианты переписаны под независимые указатели. Принципы деплоя сохранены: бамп версии один раз на dev, образы по версии, BUILD_MODE по окружению, webhooks per env, npm publish/доки только на main. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
6.5 KiB
Релизный флоу: независимый деплой окружений (FF-указатели на теги dev)
Линейная модель без merge и без конфликтов. Версию бампает lerna один раз на
dev (вешает тег vYYYY.M.D), и дальше каждое окружение — самостоятельный
fast-forward-указатель на выбранный релизный тег. testnet и main не несут
собственных коммитов и не образуют паровоз: это два независимых указателя на
ЛИНЕЙНУЮ историю dev, поэтому ветки не диверджатся и merge-конфликтов не бывает,
и при этом прод и тест можно катить разным темпом и на разные версии
одновременно.
Как релизить
# 1. Нарезать релиз на dev (бамп версии lerna + тег, БЕЗ деплоя)
pnpm run cut # = scripts/cut-release.sh
# 2. Выкатить в окружения — НЕЗАВИСИМО, в любом порядке и темпе
pnpm run testnet # последний тег → testnet (staging)
pnpm run production # последний тег → main (production)
# Точечно: конкретную версию в конкретный контур
scripts/promote.sh main v2026.6.16 # эту версию в прод
scripts/promote.sh main testnet # ровно то, что сейчас на testnet, в прод
Рекомендуемая практика (не обязательная): сначала promote.sh testnet, проверить
на staging, затем promote.sh main <та же версия>. Это уже не топологический
гард (как в старом паровозе), а ваш процесс — контуры независимы.
cut-release.sh— строго наdev. Считает версиюvYYYY.M.D(повторный релиз того же дня → суффикс-N), вызываетlerna version(бамп всех package.json + lerna.json, коммитchore(release): publish, тег, pushdev). Деплой не запускает — CI не слушаетdev.promote.sh <testnet|main> [<версия|ref>]— server-side fast-forward push выбранного релизного тега на ветку окружения.REFпо умолчанию — последний тег на линииorigin/dev. Рабочее дерево не трогается. Только вперёд (FF).
Что триггерит деплой
.github/workflows/release.yaml:
- Авто — push в
testnet/mainс изменениемlerna.json. lerna.json меняется только при релизном бампе (наdev), и этот коммит входит в диапазон FF-промоушна — поэтому деплоятся именно релизы, а не обычные feature-пуши. Это путьpromote.sh. - Ручной (
workflow_dispatch) — выбратьenvironment(testnet/main) и опциональноref(тег/коммит). Для того, что FF не умеет: откат на старую версию, редеплой без бампа, hotfix в один контур. Запуск — кнопкой в Gitea (Actions → Release → Run workflow) или черезtea/API.
Окружение определяет выбранный контур (ветка push'а или inputs.environment),
не суффикс версии:
| Контур | Окружение | Деплой-webhook | npm publish / доки |
|---|---|---|---|
testnet |
staging | TESTNET_WEBHOOK_URL |
нет |
main |
production | PRODUCTION_WEBHOOK_URL |
да (main) |
Версия для образов (dicoop/*:vX), webhook-payload и lerna publish from-package
читается из закоммиченного lerna.json вычекнутого дерева — она «приезжает» с
тегом. Для приёмника деплоя (playbooks) ничего не меняется.
Инварианты (не нарушать)
- В
testnet/main— только FF на тег dev, никаких прямых коммитов. Прямой коммит сделает ветку не-FF;promote.shтогда отвергнется push'ем (гард, не баг — выровняй ветку на нужный тег). - Версия бампается только на
dev(cut-release.sh). Никаких повторных бампов наtestnet/main— иначе вернутся расхождение и конфликты. promote.shдвигает только вперёд. Откат назад на старую версию — черезworkflow_dispatch(environment + ref), а не force-push ветки окружения.- Тег (
vX) — маркер версии и основа для GitHub Release (scripts/publish-release.sh); сам по себе триггером деплоя он не является.
Откуда ушли (история)
- Старые
publish-alpha.sh/publish-prod.shбампали версию на каждой ветке черезgit merge -X theirs+ back-merge → два бампа за цикл плодили расхождение и 20 конфликтов package.json. FF-модель это устранила конструктивно. - Затем был паровоз
dev → testnet → main: один тег ехал строго линейно,mainмог получить только то, что уже наtestnet. Безопасно, но неудобно — нельзя катить прод и тест разным темпом, нет независимого отката/hotfix. Заменён на независимые указатели:mainпромоутится изdev(а не изtestnet), оба контура — самостоятельные FF-указатели на теги одной линии.