# Релизный флоу: независимый деплой окружений (FF-указатели на теги dev) Линейная модель без merge и без конфликтов. Версию бампает `lerna` **один раз на `dev`** (вешает тег `vYYYY.M.D`), и дальше каждое окружение — **самостоятельный fast-forward-указатель** на выбранный релизный тег. `testnet` и `main` не несут собственных коммитов и не образуют паровоз: это два независимых указателя на ЛИНЕЙНУЮ историю `dev`, поэтому ветки не диверджатся и merge-конфликтов не бывает, **и при этом прод и тест можно катить разным темпом и на разные версии одновременно**. ## Как релизить (типичный путь) ```bash # стоишь на dev pnpm run cut # бамп версии lerna + тег + push dev (деплой НЕ запускает) pnpm run testnet # текущий HEAD (= свежий cut) → testnet (staging), деплой пошёл pnpm run production # тот же HEAD → main (production), деплой пошёл ``` `promote` по умолчанию шлёт **текущий HEAD** в указанный контур, поэтому после `cut` оба промоута идут «оттуда же» (с dev). Контуры независимы — можно гнать прод и тест разным темпом: ```bash scripts/promote.sh main v2026.6.16 # конкретную версию (тег) в прод scripts/promote.sh main testnet # ровно то, что сейчас на testnet, в прод # на другой ветке: promote main → улетит HEAD этой ветки (FF-гард не пустит, если # main не её предок) ``` - `cut-release.sh` — строго на `dev`. Версия `vYYYY.M.D` (повторный релиз того же дня → суффикс `-N`), `lerna version` (бамп всех package.json + lerna.json, коммит `chore(release): publish`, тег, push `dev`). **Деплой не запускает** — CI не слушает `dev`. - `promote.sh []` — server-side **fast-forward** push: по умолчанию `HEAD`, иначе указанный ветка/тег/sha. Рабочее дерево не трогается. Только вперёд (FF). **Деплой стартует только если в улетающем коммите есть бамп `lerna.json`, которого ещё нет в целевой ветке** — то есть нужен свежий `cut`. ## Что триггерит деплой `.github/workflows/release.yaml`: 1. **Авто** — push в `testnet`/`main` с изменением `lerna.json`. lerna.json меняется только при релизном бампе (на `dev`), и этот коммит входит в диапазон FF-промоушна — поэтому деплоятся именно релизы, а не обычные feature-пуши. Это путь `promote.sh`. 2. **Ручной** (`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-указатели на теги одной линии.