Polyrepo
Интерактивный CLI для управления папкой локальных npm-пакетов: бамп версии через pull request, публикация в npm, релизы и отслеживание рассинхронизации зависимостей между пакетами — всё из одного инструмента, и всё можно предварительно проверить через --dry-run, прежде чем что-то реально изменится. Работает с GitHub и GitLab (в том числе self-hosted) — хостинг определяется автоматически для каждого репозитория, папка может свободно смешивать оба. Репозиторий, который сам является pnpm-воркспейсом, определяется автоматически и разворачивается в одну запись на каждого публикуемого участника — версионируется, тегируется и релизится каждый независимо.
Возможности
setup— добавление, редактирование и удаление директорий с пакетами, которые сканирует CLI, прямо из терминала. Здесь же регистрируется хост self-hosted GitLab (gitlab.comработает без какой-либо настройки).clone— сверяет список репозиториев GitHub-организации (либо, с--provider gitlab, GitLab-группы) с тем, что уже склонировано локально, и клонирует недостающее.list— одна таблица по всем пакетам: локальная версия, ветка, git-статус, версия на основной ветке origin (независимо от того, что сейчас реально выгружено локально), git-тег, статус релиза, версия в npm-реестре и рассинхронизация зависимостей между локальными пакетами.--quickпропускает сетевые проверки ради мгновенного вывода версии/ветки/git-статуса;--outputсохраняет ту же таблицу в Markdown, JSON, CSV, HTML или простым текстом.outdated— одна таблица устаревших зависимостей по всем пакетам сразу, сгруппированная по пакетам, с раскраской колонкиLatestпо тому, насколько версия отстала (major/minor/patch).audit— одна таблица уязвимостей npm по всем пакетам сразу, сгруппированная по пакетам, с раскраской по критичности (critical/high/moderate/low) и отметкой, есть ли готовый фикс.prs— одна таблица всех открытых pull/merge request'ов по всем пакетам.doctor— проверка состояния из семи разделов с несколькими безопасными автофиксами по пути: окружение (Node/git/npm, плюсgh/glab— смотря что реально используют ваши репозитории), дрейф основной ветки от реального состояния на хостинге, устаревшие remote-tracking ссылки, расхождение с origin, состояние detachedHEAD, отсутствие защиты ветки и мёртвые ветки после прошлых релизов — проверяются и локально, и на origin,--clean-branches/--clean-remote-branchesпревращают каждую из них в свою интерактивную чистку.switch-default— подтягивает выбранные репозитории до актуальной основной ветки — какой бы она ни называлась,master,mainили как-то иначе (определяется отдельно для каждого репозитория, а не предполагается заранее).--force/--clean— для полного сброса репозитория, когда он действительно нужен.bump— поднимает версию пакета (по умолчанию patch; либо--minor/--major; либо--prerelease/--preidдля старта или продвижения пререлиза; либо--custom-versionдля точной версии) через ветку → PR/MR → merge, затем ставит тег релиза. Безопасно перезапускать, если предыдущая попытка прервалась на середине — процесс продолжается с того места, где остановился. Сам пишет черновик записи вCHANGELOG.md, если у пакета такой файл уже есть. Тег ставится какv<version>, либо<name>@<version>для участника pnpm-воркспейса — так два пакета в одном репозитории, забамленных до одного номера версии, никогда не столкнутся;tag/releaseследуют той же конвенции.--publishсразу после тега публикует пакет и в npm (без флага в конце просто спросит) — подробнее вpublishниже.publish— запускаетnpm publish(либоpnpm publishдля участника pnpm-воркспейса — так зависимостьworkspace:*на соседний пакет резолвится корректно) только для тех пакетов, что реально обогнали реестр, предварительно проверяя (и при необходимости обновляя) логин в npm. Приватный пакет никогда не предлагается. Пререлизная версия (например,2.0.0-beta.0) автоматически публикуется под dist-тегомnextвместо принятого в npm по умолчаниюlatest—--dist-tagпереопределяет это для любой версии. Предупреждает (не блокируя), если у выбранного пакета локальная версия отличается от origin, репозиторий не на основной ветке или в нём есть незакоммиченные изменения.tag— ставит тег на текущую версию пакета без повторного бампа, если версия уже была поднята каким-то другим способом. Сначала подтягивает основную ветку до актуального состояния, затем заново читает версию — так тег всегда называет то, что реально тегируется — и предупреждает, если из-за этого имя тега изменилось. Сразу после предлагает создать релиз.release— создаёт релиз из тега, с текстом релиза из соответствующего разделаCHANGELOG.md, если он есть.sync-deps— обратная сторона колонки «Deps» вlist/doctor: обновляет диапазон версии на другой локальный пакет в package.json до его текущей версии (сохраняя стиль диапазона —^,~или точную версию) для тех пакетов, что вы выберете. Только правит файлы на диске — без коммита и push.exec— прогоняет любую команду по каждому выбранному пакету, один за другим, с реальным терминалом.commit— коммит того, чтоnpm audit fix,npm updateилиsync-depsоставили в рабочем дереве, без столкновения с правилами веток: на feature-ветке коммит ложится туда; на основной ветке команда читает правила хостинга и либо коммитит и отправляет, либо создаёт ветку, отправляет её и открывает pull/merge request. Прямой push, который хостинг всё же отклонил, переносится в ветку автоматически.ui— локальный веб-интерфейс для всего перечисленного: одна таблица всех пакетов с выделенными проблемами и монорепозиториями в виде блоков, форма для каждой команды со сводкой (и пробным запуском) перед любым изменением, мастер релиза, запуски в живую с отчётом и логом с поиском, подсказки, что делать после любого исхода (в том числе пошаговое исправлениеnpm audit), история и страница настроек конфига.- Любая команда, затрагивающая несколько репозиториев, поддерживает
--packagesи--yesдля полностью неинтерактивного использования в скриптах.
Как это работает
Каждая команда читает один и тот же список репозиториев из одного конфиг-файла (roots — папки, каждая подпапка которых является отдельным пакетом; packages — отдельные папки репозиториев; gitlabHosts — хосты self-hosted GitLab). Список настраивается один раз через setup, после чего всё остальное работает с ним же. Хостинг каждого репозитория (GitHub или GitLab) определяется по его origin-удалённому репозиторию, а не задаётся отдельно.
Репозиторий и npm-пакет — не всегда одно и то же: репозиторий-pnpm-воркспейс содержит сразу несколько пакетов. Команды, работающие с отдельными пакетами (list, outdated, audit, bump, publish, tag, release, sync-deps, exec), автоматически разворачивают воркспейс-репозиторий в одну запись на каждого участника; команды, работающие с самим репозиторием (switch-default, clone, prs и большая часть doctor), по-прежнему выполняются один раз на физический репозиторий. Правила определения — в разделе Конфиг и поиск репозиториев.
Read-only проверки (git-статус, теги, релизы, состояние реестра, статус PR) выполняются по всем репозиториям параллельно, поэтому полный list или doctor по многим пакетам работает быстро, а не ждёт каждый репозиторий по очереди. А вот всё, что реально меняет состояние — коммит, push, merge, тег — выполняется по одному репозиторию за раз, с выводом каждого шага по мере его выполнения. bump отдельно отслеживает, как далеко зашла предыдущая попытка (запушена ли ветка? открыт ли PR? смёрджен ли он?), так что повторный запуск после прерывания продолжается с нужного места вместо падения на «ветка уже существует» или создания дублирующего PR.