Некоторые знания Javascript и Git и учетная запись Github. Также на вашем компьютере должен быть установлен NodeJS. Если он у вас еще не установлен, я рекомендую сделать это с помощью диспетчера версий, такого как nvm.
Контекст
монорепо
Монорепозиторий (моно = один, репо = репозиторий) — это подход к управлению несколькими программными проектами внутри одного репозитория, часто называемого пакетами.
Лерна
Lerna — это инструмент для управления проектами JavaScript с несколькими пакетами.
Обычные коммиты
Обычные коммиты — это соглашение, основанное на коммитах и состоящее из набора правил, которым нужно следовать при написании сообщений коммитов. Чтобы указать характер измененного кода, необходимо выполнить набор инструкций, соответствующих спецификации SemVer (Semantic Versioning).
Пакеты GitHub
Пакеты Github — это реестр пакетов Github. Это позволяет разработчикам хранить пакеты программного обеспечения для некоторых из наиболее часто используемых реестров пакетов (Npm, Docker, Maven…). В нашем случае мы будем использовать npm.
Что будем строить?
Мы создадим монорепозиторий, который будет содержать два проекта (пакета). После внесения изменений в любой из проектов мы зафиксируем их в соответствии с обычной спецификацией коммитов.
После завершения внесения изменений мы будем использовать Lerna в сочетании с обычными коммитами для анализа истории коммитов и определения того, какие пакеты были изменены, уровня влияния этих изменений и определения версий, которые должны быть изменены и опубликованы в реестре.
Руки вверх
Настройка монорепозитория
Самое первое, что нужно сделать, это создать новый репозиторий Github. Я назову его monorepo
.
Клонируйте репозиторий, перейдите в корневую папку и выполните следующую команду, чтобы инициализировать проект npm.
$ npm init
После этого установите Lerna как зависимость и выполните команду для инициализации проекта Lerna:
$ npm install --save lerna
$ lerna init --independent
Будет сгенерирован следующий файл lerna.json. Этот файл используется для настройки различных параметров, поддерживаемых Lerna. Флаг --independent
важен, потому что мы хотим, чтобы каждый пакет в репозитории имел независимую версию, а не одну версию для всех пакетов.
{
"packages": [
"packages/*" <-- folder where the packages will be located
],
"version": "independent" <-- versioning strategy
}
Чтобы не публиковать папку node_modules
в репозиторий, создайте файл .gitignore
со следующим содержимым:
node_modules
Структура нашего проекта должна выглядеть так:
/
.gitignore <-- avoid publish certain files to the repository
package.json <-- Lerna installed in the root dependencies
lerna.json <-- Lerna configuration file
packages/ <-- folder where the packages will be located
Теперь давайте опубликуем эти первоначальные изменения в репозитории, следуя стандартной спецификации коммитов (обратите внимание, что мы используем feat
в качестве типа фиксации и root
в качестве области действия). Позже, в разделе scope
коммита, мы установим имя затронутого пакета, но, поскольку текущие изменения являются глобальными, мы просто выберем имя, такое как root
, или любое другое, которое вы предпочитаете:
$ git add .
$ git commit -m "feat(root): adds npm, lerna and packages"
$ git push
Создание пакетов
Мы создадим следующие два пакета:
date-logic
: будет экспортирована функция, которая возвращает текущую дату.date-renderer
: он будет использоватьdate-logic
для вывода текущей даты на консоль.
Пакет 1 (дата-логика)
Создайте новую папку с именем date-logic
внутри папки packages
, перейдите к ней и выполните npm i
, чтобы сгенерировать собственный файл package.json
. После этого примените следующие изменения:
- Добавьте область действия npm к атрибуту
name
, чтобы указать, кто является владельцем пакета. В моем случае@xcanchal
. - Добавьте атрибут
repository
с URL-адресом репозитория Github. - Добавьте атрибут
publishConfig.registry
, указывающий на реестр Github Packages. Это указывает реестр npm, в котором будут опубликованы пакеты.
package.json
должен выглядеть следующим образом:
{
"name": "@xcanchal/date-logic", <-- @{scope}/{package-name}
"version": "1.0.0",
"description": "A package that returns the current date",
"main": "index.js",
"repository": "https://github.com/xcanchal/monorepo", <-- repo
"publishConfig": { <-- publish config
"@xcanchal:registry": "https://npm.pkg.github.com/xcanchal"
}
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Xavier Canchal",
"license": "ISC"
}
Теперь мы реализуем очень простой скрипт для пакета date-logic
. Создайте новый файл index.js
со следующим содержимым:
module.exports = function getDate() {
return new Date();
};
Давайте внесем изменения в репозиторий (помните, что мы должны следовать стандартной спецификации коммитов). Поскольку изменения касаются добавления новой функции в пакет date-logic
, мы будем использовать тип фиксации feat
и область действия date-logic
:
$ git add .
$ git commit -m "feat(date-logic): creates package"
$ git push
Теперь мы опубликуем самую первую версию пакета в реестре Github Packages npm, чтобы мы могли установить его из второго пакета, который мы реализуем позже (date-renderer
).
Аутентификация в пакетах Github и npm
Прежде чем мы сможем публиковать пакеты, мы должны настроить токен личного доступа Github и изменить файл конфигурации .npmrc
, чтобы иметь возможность аутентифицироваться при выполнении команд publish
или install
.
- Перейдите в «Github › Настройки › Настройки разработчика › Токены личного доступа» и нажмите «Создать новый токен». В форме задайте описательное имя и проверьте разрешения write:packages, (read:packages неявно) и delete:packages:
Вы можете узнать больше об аутентификации пакетов Github в документах.
- Добавьте следующие строки в файл
.npmrc
, который является файлом конфигурации для npm:
@xcanchal:registry=https://npm.pkg.github.com/xcanchal
always-auth= true //npm.pkg.github.com/:_authToken={YOUR_GITHUB_TOKEN}
Наконец, мы можем опубликовать наш пакет date-logic
. Для этого выполните следующую команду из папки пакета:
$ npm publish
Мы увидим следующий вывод (обратите внимание, что версия 1.0.0
была опубликована):
npm notice npm notice 📦 @xcanchal/[email protected]
npm notice === Tarball Contents ===
npm notice 61B index.js
npm notice 400B package.json
npm notice === Tarball Details ===
npm notice name: @xcanchal/date-logic
npm notice version: 1.0.0
npm notice filename: @xcanchal/date-logic-1.0.0.tgz
npm notice package size: 397 B npm notice unpacked size: 461 B
npm notice shasum: 4e48d9d684539e0125bf41a44ae90d6c6fc4b7df
npm notice integrity: sha512-DowuECiLPHd55[...]/LV5T/2pFqucQ==
npm notice total files: 2 npm notice
+ @xcanchal/[email protected]
Давайте посмотрим, как это выглядит в Github. Откройте браузер и перейдите в свой репозиторий Github. Там вы можете увидеть опубликованные пакеты в правом нижнем углу страницы:
Нажав на название пакета, вы будете перенаправлены на страницу сведений. Там доступна некоторая информация, такая как инструкции по установке, опубликованные версии или активность загрузки.
Пакет 2 (рендерер даты)
Теперь давайте реализуем наш второй пакет: файл date-renderer
. Создайте новую папку date-renderer
под packages
и повторите те же действия, что и для пакета date-logic
.
Затем установите пакет date-logic
в качестве зависимости (помните, что date-renderer
будет использовать логику даты для вывода значения на консоль).
$ npm install --save @xcanchal/date-logic
Отлично, мы установили пакет из нашего реестра пакетов Github! После этого мы создадим новый файл index.js
и добавим следующий код, представляющий собой простой скрипт, который импортирует пакет date-logic
и выполняет экспортированную туда функцию для вывода даты на консоль.
const getDate = require('@xcanchal/date-logic');
(() => {
console.log(`Date: ${getDate()}`);
})();
Мы можем протестировать его, чтобы убедиться, что он работает правильно:
$ node index.js
// -> Date: Wed Sep 22 2021 22:50:51 GMT+0200 (Central European Summer Time)
Структура нашего проекта теперь должна выглядеть так (так выглядит типичный проект Lerna):
/
package.json
lerna.json
packages/
date-logic/
index.js
package.json
date-renderer/
index.js
package.json <-- date-logic installed as a dependency
Давайте также опубликуем пакет date-renderer
в реестре пакетов Github, запустив npm publish
из папки пакета.
Изменение пакетов
Давайте внесем некоторые изменения в наши пакеты. Измените код в файле index.js
пакета date-logic
, чтобы дата отображалась в формате в соответствии с заданным языковым стандартом и некоторыми параметрами:
module.exports = function getDate(
locale = 'en-US',
options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }
) {
return new Date().toLocaleDateString(locale, options);
};
Прежде чем вносить эти изменения, мы должны определить тип коммита, так как он повлияет на потребителей, которые используют наш пакет. Поскольку мы изменили возвращаемый тип функции с объекта Date
на String
, мы можем считать это критическим изменением. Чтобы указать его с помощью обычных коммитов, тело нижнего колонтитула должно быть многострочным, а строка нижнего колонтитула должна начинаться с «BREAKING CHANGE:».
$ git add .
$ git commit -m "feat(date-logic): returns localized date string
BREAKING CHANGE: changes the return type of the getDate function"
$ git push
Использование силы Лерны
Выполните git log
, чтобы увидеть три разных коммита, которые мы сделали до сих пор (от самого нового к самому старому):
commit 7decbab3aab121c2235e3fa8fd79fe30ad4350c4 (HEAD -> main, origin/main, origin/HEAD)
Author: Xavier Canchal <[email protected]>
Date: Thu Sep 23 13:45:02 2021 +0200
feat(date-logic): returns localized date string
BREAKING CHANGE: changes the return type of the getDate function
commit d2497bbb357d41b0f4ed81e9a5f1af45b38e5fce
Author: Xavier Canchal <[email protected]>
Date: Thu Sep 23 12:48:59 2021 +0200
feat(date-renderer): creates package
commit 857efc7057941c254f97d7cf2d49b4f8eae3b196
Author: Xavier Canchal <[email protected]>
Date: Thu Sep 23 09:48:02 2021 +0200
feat(date-logic): creates package
Теперь мы будем использовать Lerna для анализа истории обычных коммитов, чтобы определить, какие пакеты были изменены, а также уровень влияния этих изменений, чтобы определить, какую версию следует обновить.
Выполните следующую команду из корневой папки монорепозитория (обратите внимание на флаг --conventional-commits
).
$ lerna version --conventional-commits
Появятся некоторые журналы, и Lerna перечислит пакеты, для которых будут установлены версии, и запросит подтверждение:
[...]
Changes: - @xcanchal/date-logic: 1.0.0 => 2.0.0
? Are you sure you want to create these versions? (ynH)
Если мы подтвердим, нажав клавишу y
, Lerna обновит атрибут version
в package.json
date-logic
и отправит тег на Github. Смотрите вывод:
lerna info execute Skipping releases
lerna info git Pushing tags...
lerna success version finished
Если мы посетим страницу тегов нашего репозитория Github, мы увидим созданный тег:
Но это еще не все! Lerna также сгенерировала отдельный CHANGELOG.md
для пакета date-logic
со всей историей изменений. Довольно аккуратно, правда?
Мы до сих пор не опубликовали эту новую версию 2.0.0
. Для этого воспользуемся другой командой Lerna: lerna publish
с аргументом from-git
. Этот аргумент говорит Lerna решить, какие версии должны быть опубликованы, просматривая теги Git, которые используются в качестве источника правды.
Но сначала мы должны расширить конфигурацию Lerna, добавив URL-адрес реестра под атрибутом commands.publish.registry
в наш файл lerna.json
, который теперь выглядит так:
{
"packages": [
"packages/*"
],
"version": "independent",
"command": {
"publish": {
"registry": "https://npm.pkg.github.com/xcanchal"
}
}
}
Зафиксируйте и опубликуйте изменение конфигурации Lerna:
$ git add .
$ git commit -m "feat(root): adds publish registry to lerna config"
$ git push
И выполните команду публикации Lerna:
$ lerna publish from-git
Который также запросит подтверждение, как на этапе version
(добавьте флаг --yes
, если вы хотите автоподтверждение):
[...]
Found 1 package to publish: - @xcanchal/date-logic => 2.0.0
? Are you sure you want to publish these packages? (ynH)
Подтверждаем и получаем следующий вывод:
[...]
Successfully published:
- @xcanchal/[email protected]
lerna success published 1 package
Давайте посетим нашу страницу пакетов репозитория и посмотрим, как теперь у нашего пакета опубликованы две разные версии:
Теперь мы можем использовать новую версию пакета date-logic
в пакете date-renderer
. Обновите package.json
date-renderer
до целевой версии 2.0.0
и выше и выполните npm install
.
{
...
"dependencies": {
"@xcanchal/date-logic": "^2.0.0"
}
...
}
Перейдите в папку пакета date-renderer
и выполните узел index.js
, чтобы увидеть обновленный результат:
$ node index.js
// -> Date: Thursday, September 23, 2021
И это все!
Вывод
Что мы рассмотрели в этой статье?
- Спецификация обычных коммитов.
- Использование пакетов Github в качестве реестра npm.
- Настройка аутентификации в пакетах Github и npm.
- Использование Lerna в сочетании с обычными коммитами для версии и публикации пакетов, а также получение приятного файла CHANGELOG.md в качестве бонуса.
Следующие шаги
- Настройка проверки синтаксиса коммита (например, commitlint), чтобы избежать человеческих ошибок, которые могут повлиять на управление версиями из-за неправильной истории коммитов.
- Автоматизируйте рабочий процесс управления версиями и публикации пакетов при отправке нового кода в репозиторий с помощью действий Github.
- Публикуйте разные типы версий: бета-версии при отправке в разработку и окончательные версии при отправке в мастер в рамках предыдущего действия Github. См. флаги Лерны — обычный-пререлиз и — обычный-выпускник.
Последние два шага описаны в этой следующей статье.
Вы когда-нибудь использовали монорепозиторий для управления пакетами? Вы использовали Lerna или любой другой инструмент? Не стесняйтесь оставлять отзывы!
Первоначально опубликовано на https://dev.to 23 сентября 2021 г.