Процесс обновления (WIP)
Давайте рассмотрим команду pvm update
которая обновляет состояние нашего репозитория.
Прежде чем начнем, небольшое замечание: cама команда предназначения для работы в CI окружении и поэтому создает коммит с помощью Platform API,
либо пытается отправить коммит через git push
. Для локального обновления используйте команду yarn -s pvm local update
.
Этапы обновления
Команда update
работает в несколько этапов:
- Определение списка пакетов, которые нуждаются в обновлении.
- Вычисление следующий версии для пакетов
- Запись новых версий
- Обновление ченжлога
- Создание релизного тега
Или если в виде схемы, что принимаем на вход, что получаем на выходе:
<что поменялось?>, <как изменить?> -> update() -> {<новые версии>, <ченжлог>, <релизный тег>}
Ниже рассмотрим этапы более подробно
что поменялось ?
Конечная цель этого этапа – список пакетов. Но в начале мы будем его формировать на основе измененных файлов:
- Все что поменялось с последнего релиза. Если релиза не было, то вместо него берем git reference в порядке убывания приоритета
- из настройки
update.no_release_ref
- текущий бранч не
master
? тогда merge-base между ним и текущей веткой - иначе берем родителя первого не-мерж коммита
- из настройки
- Если включена опция
update.include_uncommited
, будут также учитываться незакомиченные изменения.
Ок, теперь оперируем списком пакетов, и добавляем к результату следующие позиции:
- Если задан массив
dangerously_opts.always_changed_workspaces
, то все пакеты которые попадут под эти маску тоже будут считаться измененными всегда. - Массив заматченных пакетов в
force-release.packages
в файлеupdate-hints.toml
.
Обновление зависимостей
По умолчанию зависимости между пакетами обновляются. То есть, если у вас есть пакет B
, и он зависит от пакета A
,
то при обновлении пакета A
пакет B
тоже обновит версию пакета A
в своем списке зависимостей и свою собственную версию.
как изменить ?
Теперь как pvm решает как поднять версию того или иного пакета. В порядке понижения приоритета будет выбран один из пунктов ниже:
- Если мы вручную обновили версию у пакета – оставляем как есть.
- Если не выключена опция
update.workspace_release_files
то учитываются наличие файловnone, prerelease, prepatch, patch, preminor, minor, premajor, major
, если такой файл присутствует, то тип релиза будет соответствовать имени файла. - Выполняется опциональный хук
release-type
. Если метод вернетfalse
илиundefined
вместо типа релиза, то продолжаем дальше. - Релизный тип в
update-hints.toml
для заданного пакета, при наличии. - Если в прошлом релизе не было версии для этого пакета, считаем пакет новым и версию оставляем как есть.
- Далее обрабатываем опцию
update.release_type_overrides
. В данном случае логика такая: release_type_overrides задает список кортежей, где каждый кортеж это тип релиза и список масок для файлов. Далее, берем список измененных файлов для пакета, и если этот список полностью "закрывается" масками из одного или нескольких кортежей, тогда переопределение считаем успешным и берем максимальный тип релиза из сматченных кортежей. - Результат вызова хука
release-type-by-commits
. Если хук пуст или он вернул falsy значение идем дальше. - Конфиг
update.default_release_type
.
При этом зависимые пакеты обновляется по другому.
За их обновление отвечает настройка update.dependants_release_type
которая либо может иметь тип релиза (по умолчанию patch
), либо равняться as-dep
и тогда типа релиза
зависимого пакета, будет равнятся типу релизу пакета, от которого зависит зависимый пакет.
Запись новых версий
И тут надо сразу определиться с тем, какие есть версии и еденицы смысла завязанные на них в разрезе работы pvm.
- Внутреняя версия для установщика пакетов, будь то yarn или npm или еще какой-то, хранится всегда в поле
version
файлаpackage.json
пакета. В рамках монорепозитория, мы например можем выставлять все версии всегда одинаковыми, чтобы получить гарантию того, что пакеты в репозитории и внутренние зависимости на них, это всегда одно и тоже. - Внешняя версия используемая для публикации и релиза пакетов. Храниться она может где угодно.
pvm update оперирует внешними версиями, и в зависимости от настроек, они могут храниться в разных местах:
versioning.source | место хранения версии |
---|---|
tag, версия одна на все пакеты | релизный тег вида vX.Y.Z |
tag, независимые версии | пачка тегов вида pkg-name-vX.Y.Z |
file | файл который задается настройкой versioning.source_file по умолчанию versions.json |
package | поле version в package.json пакетов |
Обновление ченжлога
Прежде всего формируется release notes на основе коммитов, сделанных начиная с последнего релиза (или соответствующего git reference если его не было, об этом рассказно выше).
При этом плагины могут реализовывать хук commits-to-notes
, c помощью которого как-то иначе преобразовать коммиты в release notes, чем это делает сам pvm.
Собственно это и делает плагин @pvm/plugin-conventional-changelog, добавляющий поддержку conventional-changelog для преобразования коммитов в markdown описание.
Допустим, с предыдущего релиза мы сделали две задачи в двух коммитах:
[skip-ci] исправлен парсинг аргумента -S для pvm update
добавлена документация на русском языке
Pvm обработает эти коммиты, и на выходе получится описание релиза в markdown синтаксисе:
- исправлен парсинг аргумента -S для pvm update
- добавлена документация на русском языке
Далее на основе полученных release notes формируется (или нет, если включить опцию release.disable_changelog
) новая запись в ченжлог через механизм отрисовщика ченжлогов.
Отрисовщик ченжлога задается опцией changelog.renderer
, это просто строка. Непосредственно связь между именем и конкретной реализации отрисовщика реализуется через хук: changelog.<имя>
. Т.е. если вы зададите имя my-renderer
, будет взят хук changelog.my-renderer
.
По умолчанию используется отрисовщик builin.list
отрисовывющий коммиты в виде обычного списка.
Помимо прочих, стоит упомянуть еще опцию changelog.path
– куда сохранить ченжлог.
Теперь насчет ченжлогов индивидуально для каждого пакета. По умолчанию они отключены, включить их можно через опцию changelog.for_packages.enabled
.
При этом pvm будет генерировать ченжлоги для пакетов на основе только тех коммитов, которые имели отношение к заданному пакету.
Опции здесь:
changelog.for_packages.path
– куда сохранять ченжлог, путь относителен для каждого пакета. Илиchangelog.for_packages.output_dir
– отменяет предыдущюю опцию, если задан данная директория будет использована для сохранения всех ченжлогов пакетов в одной директории.
В обоих случаях можно задать опцию front_matter
. При этом задавать дефисы сверху и снизу не нужно.
Инкрементальная генерация
Pvm по умолчанию не будет перезаписывать каждый раз ченжлог целиком, а только добавлять информацию с последнего релиза. Т.е. при необходимости, вы можете править ченжлог как обычный файл, эти изменения не будут переписаны.
Неинкрементальные ченжлоги и локальные релизы
Есть два вида отрисовщиков ченжлогов: инкрементальные и нет. В зависимости от реализуемого интерфейса:
export interface Renderer {
render(releases: Iterable<ReleaseInfo>, forPkg?: string): string,
}
export interface IncrementalRenderer extends Renderer {
append(changelog: string, release: ReleaseInfo, forPkg?: string): string,
}
Инкрементальный рендерер обязан уметь добавлять в существующий ченжлог информацию о новом релизе, но не всегда это удобно. Вы можете иметь неинкрементальный рендерер, однако, в данном случае pvm должен где-то хранить все релизы под рукой, чтобы все их отдать отрисовщику, и не бегать за release notes в платформу, что может быть долго и дорого.
Для этого есть опция local_releases.enabled
, включив которую, pvm начнет складывать информацию о релизах локально в файл .pvm/releases.toml
для того
чтобы быстро отдавать весь список релизов отрисовщику.
Включив опцию первый раз, имеет смысл выполнить команду yarn pvm fetch-releases
для того чтобы наполнить локальный релизный файл в первый раз.
Далее он будет обновляться автоматически командой pvm update
при релизах.
Создание релизного тега
В зависимости от выбранных настроек pvm будет по разному создавать релизный тег:
Настройки | Вид тегов или тега |
---|---|
Все пакеты имеют одну версию | vX.Y.Z |
Простой репозиторий с одним пакетом | vX.Y.Z |
Монорепозиторий с разными версиями | release-YYYY.MM.DD-{random-word} |
Если опция versioning.source
равна tag
и пакеты имеют независимые версии, то также будет создаваться пачка тегов вида pkg-name-vX.Y.Z
.
Однако такой подход не рекомендуется, в виду излишнего замусоривания тегами репозитория.
К релизному тегу через platform API также записываются release notes, о которых мы говорили выше.
После создания всех необходимых тегов, команда pvm update
(или pvm local update
) завершает свою работу.