Skip to content

Релиз и публикация ​

Полный цикл релиза: поднять версию через PR/MR, поставить тег, создать релиз и опубликовать в npm — четыре отдельных, компонуемых шага, плюс sync-deps — чтобы поправить другие локальные пакеты, у которых после этого остался диапазон зависимости на устаревшую версию. Бампнуть партию пакетов и затем опубликовать или зарелизить только часть из них — разные по смыслу решения, которые не всегда происходят одновременно, поэтому они никогда не объединены принудительно. Работает с GitHub и GitLab, автоматически определяемыми для каждого репозитория — см. «Конфиг и поиск репозиториев».

bump ​

Выбор пакетов, поднятие версии (по умолчанию patch), открытие PR/MR, merge в основную ветку и тег релиза.

bash
polyrepo bump [options]
  1. Показывает чекбокс пакетов с текущей версией и версией, до которой она поднимется (1.2.9 → 1.2.10 для patch-бампа — --minor/--major поднимают другую часть версии, обнуляя всё, что ниже, как у любого semver-инструмента). Пакеты с грязным рабочим деревом помечены — они будут пропущены. В описании подсвеченного пакета показано, что реально изменилось с последнего git-тега — вычисляется для всех пакетов параллельно.
  2. После подтверждения — для каждого выбранного пакета по одному:
    1. git fetch origin → git checkout <default branch> → git merge --ff-only origin/<default branch> (bump-ветка всегда создаётся от актуальной основной ветки, а не от той, на которой репозиторий случайно оказался);
    2. проверяет состояние предыдущей попытки — есть ли уже смёрдженный PR/MR, открытый, либо просто запушенная ветка с именем <new-version>-version-bump (либо <sanitized-name>-<new-version>-version-bump для участника pnpm-воркспейса — так два пакета, забамленных до одной версии в одном репозитории, никогда не спорят за одно имя ветки). В зависимости от того, что найдено, процесс продолжается с нужного места вместо падения на «ветка уже существует» или создания дубликата;
    3. если package.json на ветке ещё не бампнут — поле "version" обновляется (текстовая замена — форматирование и порядок полей не трогаются). Если у пакета уже есть CHANGELOG.md, туда же добавляется черновик записи ## [x.y.z] - YYYY-MM-DD (в стиле Keep a Changelog) со списком коммитов с последнего тега — черновик для правки, не готовый changelog;
    4. gh pr create (GitHub) либо glab mr create (GitLab) в основную ветку (если PR/MR ещё не существует);
    5. с --wait-checks: ожидание CI перед merge — механизм отличается по хостингу, см. описание опции ниже; отсутствие настроенных проверок не считается ошибкой;
    6. gh pr merge / glab mr merge — через PR/MR, не прямым push;
    7. локальная основная ветка синхронизируется с только что смёрдженным PR/MR;
    8. git-тег v<new-version> создаётся и пушится, если его ещё нет — <name>@<new-version> для участника pnpm-воркспейса, по той же причине избежания коллизий, что и с именем ветки выше.
  3. Любая ошибка на этом пути помечает пакет ✗ с понятным сообщением, и процесс переходит к следующему пакету, не прерывая весь запуск целиком.
  4. После обработки всех выбранных пакетов — отдельная проверка по всем пакетам (не только только что бампнутым): не остался ли у какого-то локального пакета диапазон зависимости, не соответствующий новой версии бампнутого пакета — здесь ничего не меняется автоматически (см. sync-deps для исправления).
  5. Если хотя бы один пакет реально был затегован (и это не был --dry-run) — один раз для всей партии спрашивает, опубликовать ли эти пакеты в npm прямо сейчас, — если только не задан --publish, который пропускает вопрос и публикует сразу (под --yes без --publish вопрос пропускается целиком, точно так же, как вопрос про релиз у tag). В любом случае это ровно publish, запущенный для ровно тех пакетов, что только что были бампнуты — подробнее в «Публикации» ниже.

Публикация ​

Без --publish вопрос выше — единственное место, где bump вообще трогает npm. С флагом (или ответом «да») это ровно polyrepo publish для ровно тех пакетов, что только что были бампнуты: логин в npm проверяется один раз в начале, зависимости участника pnpm-воркспейса при необходимости сначала (пере)линкуются, а пререлизная версия (например, 2.0.0-beta.0) автоматически публикуется под dist-тегом next вместо latest — те же правила, что и у самой publish. Предлагаются только пакеты, реально затегованные в этом запуске — пропущенный из-за грязного рабочего дерева или упавший на середине пакет никогда не публикуется.

Реальный вывод — --dry-run, пока ещё ничего не существует:

[1/1] os-detect  2.1.5 → 2.1.6
  $ git fetch origin
  $ git checkout master
    Your branch is up to date with 'origin/master'.
    Already on 'master'
  $ git merge --ff-only origin/master
    Already up to date.
  ✓ master is up to date.
  [dry-run] would create branch 2.1.6-version-bump, ensure version 2.1.6 (+ a CHANGELOG.md entry if one exists), commit/push if needed, then open + merge a PR, then tag v2.1.6.

Повторный запуск bump на пакете, где предыдущая попытка уже прошла весь путь до конца, гораздо короче — всё уже сделанное просто подтверждается, а не выполняется заново:

[1/1] vue-toast-kit  1.0.7 → 1.0.8
  ✓ master is up to date.
  ✓ Already merged as PR #12 — master already has it.
  ✓ Tag v1.0.8 already exists on origin.

(На GitLab-репозитории это выглядит так же, но с «MR» вместо «PR» — провайдерный слой сам подставляет нужную метку, независимо от хостинга.)

--prerelease, либо --preid в паре с --major/--minor, вычисляют целевую версию иначе, но проходят через те же самые шаги ветка → PR/MR → merge → тег:

[1/1] os-detect  2.1.5 → 2.1.6-beta.0
  $ git fetch origin
  $ git checkout master
    Your branch is up to date with 'origin/master'.
    Already on 'master'
  $ git merge --ff-only origin/master
    Already up to date.
  ✓ master is up to date.
  [dry-run] would create branch 2.1.6-beta.0-version-bump, ensure version 2.1.6-beta.0 (+ a CHANGELOG.md entry if one exists), commit/push if needed, then open + merge a PR, then tag v2.1.6-beta.0.

Опции ​

--dry-run ​

Печатает план по каждому пакету, ничего не пушит и не меняет — включая запись в CHANGELOG.md, ожидание CI и git-тег.

--minor ​

Поднять minor-версию вместо patch (например, 1.2.9 → 1.3.0).

--major ​

Поднять major-версию вместо patch (например, 1.2.9 → 2.0.0).

--prerelease ​

Поднять (или начать) пререлиз вместо patch/minor/major (например, 1.2.9 → 1.2.10-alpha.0, либо 1.2.10-alpha.0 → 1.2.10-alpha.1). В паре с --preid задаётся имя — node-semver сам решает, добавить ли -alpha.0 к текущей версии или продвинуть номер уже существующего пререлиза.

--preid <name> ​

Идентификатор пререлиза для --prerelease, либо в паре с --minor/--major — для preminor/premajor-пререлиза (например, --major --preid beta на 1.2.9 → 2.0.0-beta.0). По умолчанию alpha.

--custom-version <version> ​

Задать точную версию вместо вычисления. Работает только вместе с --packages, называющим ровно один пакет — применять одну и ту же версию сразу к нескольким пакетам никогда не имеет смысла.

--packages <a,b,c> ​

Имена директорий пакетов через запятую вместо интерактивного чекбокса — для скриптов. Неизвестные имена выводятся как предупреждение и пропускаются.

--yes ​

Пропустить подтверждение «proceed?».

--wait-checks ​

Дождаться CI перед merge; не мёрджить, если проверки не прошли. На GitHub это gh pr checks --watch, привязанный к PR. У GitLab нет аналога, привязанного к MR — вместо этого используется glab ci status --branch --wait для пайплайна bump-ветки, суть та же. Отсутствие настроенных проверок не считается ошибкой в обоих случаях — просто нечего ждать.

--publish ​

После тегирования сразу опубликовать в npm — без вопроса (см. «Публикация» выше).

Пример:

bash
# сначала dry run — ничего не пушится, не коммитится, не мёрджится и не тегается
polyrepo bump --dry-run

# поднять или продвинуть beta-пререлиз
polyrepo bump --prerelease --preid beta

# начать premajor release candidate (например, 2.0.0-rc.0)
polyrepo bump --major --preid rc

# задать точную версию для одного пакета, например для хотфикса
polyrepo bump --packages os-detect --custom-version 2.1.6-hotfix.1

# бамп, тег и публикация, неинтерактивно
polyrepo bump --publish --yes

# полностью неинтерактивно, для скрипта/CI
polyrepo bump --packages vue-toast-kit,os-detect --yes

tag ​

Для пакета, версия которого уже была поднята каким-то другим способом (не через bump, либо до того, как он начал тегировать) — release не с чем работать, тега для текущей версии ещё нет. tag ставит недостающий тег на текущую версию без повторного бампа и без открытия PR/MR.

bash
polyrepo tag [options]
  1. Подтягивает основную ветку origin для каждого репозитория (один раз на физический репозиторий), затем проверяет по каждому пакету (параллельно), существует ли уже тег v<local version> (<name>@<local version> для участника pnpm-воркспейса). Пакет, у которого локальная версия отличается от того, что реально на origin, помечается уже здесь — это важно знать, потому что следующий шаг подтягивает локальную копию до основной ветки origin перед тегированием, так что создаваемый тег может в итоге назвать не ту версию, что реально будет затегована.
  2. Показывает чекбокс: пакет, версия, тег — с пометкой ⚠ origin has <version>, если версия отличается от origin. Незатегованные пакеты отмечены по умолчанию; уже затегованные тоже можно выбрать вручную (безвредно — просто подтверждает, что тег на месте).
  3. После подтверждения — для каждого выбранного пакета: синхронизирует основную ветку (так же, как bump), затем заново читает версию из package.json — теперь, когда локальная копия точно совпадает с origin. Версия на диске могла измениться, если локальная копия не была уже на основной ветке или отставала. Тег всегда называет версию, которая реально здесь сейчас, а не ту, что была до синхронизации — если из-за этого имя тега поменялось, печатается предупреждение. Создаёт и пушит (возможно, переименованный) тег, если его не хватает.
  4. Если хотя бы один пакет реально был затегован (и это не был --dry-run) — спрашивает: «Create a release for the N package(s) just tagged?» — ответ «да» запускает тот же процесс, что и release, но именно для этих пакетов.

Реальный вывод — у текущей версии тег уже есть, так что остаётся только его подтвердить:

[1/1] os-detect  v2.1.5
  $ git fetch origin
  $ git checkout master
    Your branch is up to date with 'origin/master'.
    Already on 'master'
  $ git merge --ff-only origin/master
    Already up to date.
  ✓ master is up to date.
  ✓ Tag v2.1.5 already exists on origin.

Реальный вывод — локальная копия отставала от origin, так что синхронизация основной ветки поменяла то, что реально тегируется:

[1/1] os-detect  v2.1.5  (origin has 2.1.6)
  $ git fetch origin
  $ git checkout master
  $ git merge --ff-only origin/master
    Fast-forwarded to origin/master.
  ✓ master is up to date.
  ! Version changed from 2.1.5 to 2.1.6 after syncing with origin — tagging v2.1.6 instead of v2.1.5.
  ✓ Tagged and pushed v2.1.6.

Опции ​

--dry-run ​

Печатает план; ничего не тегает, не пушит и не релизит.

--packages <a,b,c> ​

Список пакетов вместо интерактивного чекбокса.

--yes ​

Пропустить подтверждение «proceed?» (вопрос про релиз тоже пропускается — релиз не создаётся, пока не указан --release).

--release ​

Создать релиз сразу после тегирования, без вопроса — для скриптов.

Пример:

bash
polyrepo tag --packages vue-toast-kit,os-detect --yes --release

release ​

Выбор пакетов и создание релиза для тега их текущей версии.

bash
polyrepo release [options]
  1. Проверяет по каждому пакету (параллельно) наличие тега v<local version> (<name>@<local version> для участника pnpm-воркспейса) на origin (того самого, что создаёт bump или tag), и есть ли у этого тега уже релиз.
  2. Показывает чекбокс: пакет и его тег. Пакеты без тега для текущей версии показаны недоступными для выбора («run bump first»); уже зарелиженные — доступны, но не отмечены по умолчанию, на случай если нужно повторить.
  3. После подтверждения — для каждого выбранного пакета: gh release create <tag> --verify-tag (GitHub) либо glab release create <tag> (GitLab) — чекбокс и так предлагает только пакеты с уже существующим тегом, так что новый тег никогда не придумывается; --verify-tag у GitHub — это вторая, собственная гарантия того же самого, у GitLab такого флага нет. Текст релиза берётся из соответствующего раздела CHANGELOG.md, если он есть. Иначе — на GitHub --generate-notes (сводка по смёрдженным PR/коммитам); у GitLab аналога нет, поэтому вместо этого используется простой список коммитов с последнего тега.

Реальный вывод — на GitHub-репозитории:

[1/1] os-detect  v2.1.5
  ✓ No changelog entry — using --generate-notes.
  $ gh release create v2.1.5 --verify-tag --title os-detect@2.1.5 --generate-notes
  ✓ Created release os-detect@2.1.5.

Опции ​

--dry-run ​

Печатает, что было бы создано, ничего реально не создавая.

--packages <a,b,c> ​

Список пакетов вместо интерактивного чекбокса.

--yes ​

Пропустить подтверждение «proceed?».

Пример:

bash
polyrepo release --packages vue-toast-kit,os-detect --yes

publish ​

Выбор пакетов и запуск npm publish — по умолчанию отмечены те, что обогнали реестр.

bash
polyrepo publish [options]
  1. Подтягивает основную ветку origin для каждого репозитория (один раз на физический репозиторий), затем проверяет версию каждого пакета в реестре (npm view <pkg> version) в сравнении с локальной версией — параллельно. Пакет с "private": true (в том числе собственный корень pnpm-воркспейса) исключается полностью, ещё до построения чекбокса — он в принципе не предназначен для попадания в реестр.
  2. Показывает чекбокс: версия в реестре → локальная версия, плюс dist-тег, под которым пойдёт публикация (см. --dist-tag ниже), и пометку ⚠ origin has <version>, если у основной ветки origin версия отличается от локальной. Пакеты, у которых версия в реестре отличается от локальной, отмечены по умолчанию; уже опубликованные остаются доступны для выбора (например, чтобы republish после unpublish).
  3. После подтверждения — один раз для всей партии (пропускается под --dry-run) проверяет npm whoami — если логин не активен, запускает npm login (в реальном терминале, так что и браузерный OTP-флоу, и обычный запрос учётных данных работают как обычно) до начала публикации, вместо того чтобы узнать об этом только на середине публикации первого пакета.
  4. Для каждого выбранного пакета по одному: npm publish (либо npm publish --dry-run с флагом --dry-run) — либо, для участника pnpm-воркспейса, вместо этого pnpm publish --no-git-checks, так что зависимость workspace:* на соседний пакет резолвится в реальный номер версии, а не валит публикацию. Работает с реальным терминалом, без перехвата вывода — запрос 2FA/OTP от npm работает как обычно.

Реальный вывод — средняя часть это собственный вывод сборки/тестов/упаковки самого npm для этого пакета, показанный вживую в реальном терминале, а не то, что polyrepo как-то перехватывает или переформатирует:

[1/1] os-detect@2.1.5
  $ npm publish --dry-run
  … (сборка и тесты самого пакета, список содержимого тарбола от npm)
  ✓ Published os-detect@2.1.5 (dry run).

publish никогда не проверяет состояние git — как и обычный npm publish никогда не проверял — она всегда публикует ровно то, что на диске. Зато предупреждает (не блокируя) прямо перед подтверждением, если выбранный пакет не на основной ветке, содержит незакоммиченные изменения, или его локальная версия отличается от origin:

! os-detect is on branch fix-typo, not master — publishing what's on disk anyway.
! vue-toast-kit has uncommitted changes — publishing what's on disk anyway.

Dist-теги ​

Пререлизная версия (что угодно с -, например 2.0.0-beta.0) по умолчанию публикуется под dist-тегом next вместо принятого в npm по умолчанию latest — иначе она стала бы той версией, что получает любой, кто ставит пакет без явного указания версии, а это почти никогда не то, чего хочет пререлиз. --dist-tag переопределяет это для всех выбранных пакетов (включая автоопределение) — передайте флаг явно, чтобы опубликовать и стабильную версию под чем-то отличным от latest (например, под LTS-каналом).

Опции ​

--dry-run ​

npm publish --dry-run вместо реальной публикации.

--dist-tag <tag> ​

Dist-тег npm, под которым публикуется каждый выбранный пакет (по умолчанию: next для пререлизной версии, иначе принятый в npm по умолчанию latest). См. «Dist-теги» выше.

--packages <a,b,c> ​

Список пакетов вместо интерактивного чекбокса.

--yes ​

Пропустить подтверждение «proceed?».

Пример:

bash
polyrepo publish --packages vue-toast-kit,os-detect --yes
polyrepo publish --packages os-detect --dist-tag next   # принудительно задать dist-тег

sync-deps ​

Обратная сторона колонки «Deps» в list и раздела «Cross-package dependencies» в doctor: у локального пакета диапазон версии на другой локальный пакет больше не совпадает с текущей версией этого пакета (например, всё ещё стоит ^1.1.0, хотя зависимость уже переехала на 1.2.0). Все остальные места только сообщают об этом — эта команда единственная, кто реально чинит.

bash
polyrepo sync-deps [options]
  1. Читает все найденные пакеты (не только те, что названы в --packages) — чтобы найти устаревший диапазон, нужно знать текущую версию каждого локального пакета, а не только тех, что чинятся.
  2. Показывает чекбокс «до/после» для каждого найденного устаревшего диапазона: "depName" "oldRange" → "newRange", сохраняя стиль каждого диапазона (^ остаётся ^, ~ остаётся ~, точная версия остаётся точной — всё необычное сводится к диапазону ^, что видно в этом же превью до того, как что-либо будет записано). --packages сужает, для каких именно зависимых пакетов предлагаются проблемы — то же значение, что и везде в этом CLI.
  3. После подтверждения обновляет package.json на месте для каждой выбранной проблемы — текстовая замена ровно пары "depName": "oldRange", так что форматирование, порядок полей и стиль кавычек в остальном файле не трогаются.

Правит только package.json на диске — без коммита, без push, без ветки/PR. Просмотрите изменение (git diff), затем закоммитьте его так, как разрешают правила каждого репозитория, командой polyrepo commit.

Реальный вывод:

Sync local dependency ranges

  app-shell  @acme/ui-kit  "^1.1.0" → "^1.2.0"
  app-shell  @acme/api-client  "~2.0.0" → "~2.1.0"

✓ app-shell: "@acme/ui-kit" "^1.1.0" → "^1.2.0"
✓ app-shell: "@acme/api-client" "~2.0.0" → "~2.1.0"

Опции ​

--dry-run ​

Печатает, что было бы обновлено, без реальной записи в package.json.

--packages <a,b,c> ​

Предлагать проблемы только для этих зависимых пакетов — то же значение, что и везде.

--yes ​

Пропустить подтверждение «proceed?».

Пример:

bash
polyrepo sync-deps                          # посмотреть, что устарело, затем обновить
polyrepo sync-deps --dry-run                # напечатать план, ничего не менять
polyrepo sync-deps --packages a,b --yes     # неинтерактивно, для скриптов/CI