Я большой поклонник семантический релиз Так как оказалось. Я следовал своему развитию, изучал его нефтяные. Я сделал внутренние отчеты, провел семинары и наконец привезли омрель к Наша сборная инфраструктуры Отказ Я написал плагины , плагин-фабрики и Тестирование-инструменты для этого. В течение нескольких лет я пытался объединить семантические релизы и монореспористы в Многие ОСС проекты:
- https://github.com/qiwi/semantic-release-monorepo-hooks
- https://github.com/dhoulb/multi-semantic-release
- https://github.com/qiwi/multi-semantic-release
И т. Д., И т. Д., Так далее. Я просто пытаюсь сказать, что Семел оказал значительное влияние на мою профессиональную жизнь.
Цель Семел
Основная цель семантического выпуска заключается в преобразовании семантического (обычного) коммитата в создание артефактов и развертываний. С версией ударов, изменяемых моментов, меткой, PKG Publishing. «Полностью автоматизированная релиз» – это правда. Есть также Десятки на плагинах Итак, вы, скорее всего, найдут решение для любого стандартного случая. Это действительно экономит время.
Но иногда
Возможно, вам понадобится минор Настраиваться. Например, протолкните несколько PKG для публичных, так и внутренних регистров. Ooops. «… публикация двух разных реестра не хорошая идея» Отказ В этом случае вы не можете полагаться на стабильные, удобные и тестируемые в миллионах Runs Плагин Semrel/NPM И вы должны просто написать пару команд вручную с Semantic-Release/Exec вместо:
echo "//npm-registry.domain.com/:_authToken=${TOKEN}" >> .npmrc
echo "\`jq '.name="@scope/pkg-name"' package.json\`" > package.json
npm config set registry https://npm-registry.domain.com
npm publish --no-git-tag-version
Еще один экземпляр – отключение Git Notes Fetching Отказ «Боюсь, что не будет возможно» Отказ
Конечно, вы можете вилить Семел и удалить упомянутую строку. Или создать плагин/крючок, который будет переопределенным нагруженным execa Модуль с установленной одной версией, чем просто пропустить Git Notes Вызов (это действительно разочаровывает, Я делал подобное ). Или … {{еще один сумасшедший обходной путь идет здесь}} Отказ
Это момент водосбора. Как только вы начнете бороться с инструментом, пришло время просто выбрать другой. Новая дилемма:
- Проведите дни и дни для поиска, тюнинга и тестирования аналогов.
- Напишите свой собственный семантический релиз.
Мое самоуверенное предложение: если ваше дело очень простое или, наоборот, очень сложный, второй вариант будет оптимальным. Сценарий выпуска – это не ракетная наука!
140 линиями альтернативы
Давайте посмотрим на то, что именно каждый релиз состоит из, если мы отменим договоры инструментов высокого уровня. Я использую ZX в примерах, но это может быть execa или родной child_process.exec слишком.
1. Git Configuration
Чтобы сделать коммит, вам нужен коммиттер: просто имя и электронное письмо, которое будет связано с автором. Также Пэт или SSH токен Требуется толкать коммит.
const {GIT_COMMITTER_NAME, GIT_COMMITTER_EMAIL, GITHUB_TOKEN} = process.env
if (!GITHUB_TOKEN || !GIT_COMMITTER_NAME || !GIT_COMMITTER_EMAIL) {
throw new Error('env.GITHUB_TOKEN, env.GIT_COMMITTER_NAME & env.GIT_COMMITTER_EMAIL must be set')
}
const gitAuth = `${GIT_COMMITTER_NAME}:${GITHUB_TOKEN}`
const originUrl = (await $`git config --get remote.origin.url`).toString().trim()
const [,,repoHost, repoName] = originUrl.replace(':', '/').replace(/\.git/, '').match(/.+(@|\/\/)([^/]+)\/(.+)$/)
const repoPublicUrl = `https://${repoHost}/${repoName}`
const repoAuthedUrl = `https://${gitAuth}@${repoHost}/${repoName}`
await $`git config user.name ${GIT_COMMITTER_NAME}`
await $`git config user.email ${GIT_COMMITTER_EMAIL}`
await $`git remote set-url origin ${repoAuthedUrl}`
2. Анализ фиксации
Обычные коммиты – это просто префиксные строки в журнале Git. Мы должны определить некоторые правила о том, как связать сообщения о сообщениях с соответствующими типами выпуска:
const semanticTagPattern = /^(v?)(\d+)\.(\d+)\.(\d+)$/
const releaseSeverityOrder = ['major', 'minor', 'patch']
const semanticRules = [
{group: 'Features', releaseType: 'minor', prefixes: ['feat']},
{group: 'Fixes & improvements', releaseType: 'patch', prefixes: ['fix', 'perf', 'refactor', 'docs']},
{group: 'BREAKING CHANGES', releaseType: 'major', keywords: ['BREAKING CHANGE', 'BREAKING CHANGES']},
]
Затем мы ищем тег предыдущего выпуска, что удовлетворяет СЕМВЕР шаблон:
const tags = (await $`git tag -l --sort=-v:refname`).toString().split('\n').map(tag => tag.trim())
const lastTag = tags.find(tag => semanticTagPattern.test(tag))
И сделать комбиниты, вырезанные из найденного Ref:
const newCommits = (lastTag
? await $`git log --format=+++%s__%b__%h__%H ${await $`git rev-list -1 ${lastTag}`}..HEAD`
: await $`git log --format=+++%s__%b__%h__%H HEAD`)
.toString()
.split('+++')
.filter(Boolean)
.map(msg => {
const [subj, body, short, hash] = msg.split('__').map(raw => raw.trim())
return {subj, body, short, hash}
})
Теперь нам просто нужно разбирать их:
const semanticChanges = newCommits.reduce((acc, {subj, body, short, hash}) => {
semanticRules.forEach(({group, releaseType, prefixes, keywords}) => {
const prefixMatcher = prefixes && new RegExp(`^(${prefixes.join('|')})(\\(\\w+\\))?:\\s.+$`)
const keywordsMatcher = keywords && new RegExp(`(${keywords.join('|')}):\\s(.+)`)
const change = subj.match(prefixMatcher)?.[0] || body.match(keywordsMatcher)?.[2]
if (change) {
acc.push({
group,
releaseType,
change,
subj,
body,
short,
hash
})
}
})
return acc
}, [])
Та-да. Семантические изменения:
semanticChanges= [
{
group: 'Fixes & improvements',
releaseType: 'patch',
change: 'perf: use git for tags sorting',
subj: 'perf: use git for tags sorting',
body: '',
short: 'a1abdae',
hash: 'a1abdaea801824d0392e69f9182daf4d5f4b97db'
},
{
group: 'Fixes & improvements',
releaseType: 'patch',
change: 'refactor: minor simplifications',
subj: 'refactor: minor simplifications',
body: '',
short: 'be847a2',
hash: 'be847a26e2b0583e889403ec00db45f9f9555e30'
},
{
group: 'Fixes & improvements',
releaseType: 'patch',
change: 'fix: fix commit url template',
subj: 'fix: fix commit url template',
body: '',
short: '3669edd',
hash: '3669edd7eb440e29dc0fcf493c76fbfc04271023'
}
]
3. Разрешите следующую версию:
const nextReleaseType = releaseSeverityOrder.find(type => semanticChanges.find(({releaseType}) => type === releaseType))
if (!nextReleaseType) {
console.log('No semantic changes - no semantic release.')
return
}
const nextVersion = ((lastTag, releaseType) => {
if (!releaseType) {
return
}
if (!lastTag) {
return '1.0.0'
}
const [, , c1, c2, c3] = semanticTagPattern.exec(lastTag)
if (releaseType === 'major') {
return `${-~c1}.0.0`
}
if (releaseType === 'minor') {
return `${c1}.${-~c2}.0`
}
if (releaseType === 'patch') {
return `${c1}.${c2}.${-~c3}`
}
})(lastTag, nextReleaseType)
const nextTag = 'v' + nextVersion
4. Создание заметок выпуска
const releaseDiffRef = `## [${nextVersion}](${repoPublicUrl}/compare/${lastTag}...${nextTag}) (${new Date().toISOString().slice(0, 10)})`
const releaseDetails = Object.values(semanticChanges
.reduce((acc, {group, change, short, hash}) => {
const {commits} = acc[group] || (acc[group] = {commits: [], group})
const commitRef = `* ${change} ([${short}](${repoPublicUrl}/commit/${hash}))`
commits.push(commitRef)
return acc
}, {}))
.map(({group, commits}) => `
### ${group}
${commits.join('\n')}`).join('\n')
const releaseNotes = releaseDiffRef + '\n' + releaseDetails + '\n'
5. Обновите Changelog.md.
Прикрепить Releasenotes подать. Только одна строка.
await $`echo ${releaseNotes}"\n$(cat ./CHANGELOG.md)" > ./CHANGELOG.md`
6. Обновить пакет версии
await $`npm --no-git-tag-version version ${nextVersion}`
7. Git Release.
Создать коммит. Создать тег. Толкать их.
const releaseMessage = `chore(release): ${nextVersion} [skip ci]`
await $`git add -A .`
await $`git commit -am ${releaseMessage}`
await $`git tag -a ${nextTag} HEAD -m ${releaseMessage}`
await $`git push --follow-tags origin HEAD:refs/heads/master`
8. Выпуск GitHub
Только один Curl Пост до GH REST API Отказ
const releaseData = JSON.stringify({
name: nextTag,
tag_name: nextTag,
body: releaseNotes
})
await $`curl -u ${GIT_COMMITTER_NAME}:${GITHUB_TOKEN} -H "Accept: application/vnd.github.v3+json" https://api.github.com/repos/${repoName}/releases -d ${releaseData}`
9. NPM публикация
await $`npm publish --no-git-tag-version`
Нужна несколько реестров? НП.
await $`npm config set registry https://registry.npmjs.org`
await $`npm publish --no-git-tag-version`
await $`echo "\`jq '.name="@${repoName}"' package.json\`" > package.json`
await $`npm config set registry https://npm.pkg.github.com`
await $`npm publish --no-git-tag-version`
Выводы
Это решение не покрывает угловые случаи и имеет значительные ограничения использования. В конечном счете, вам все равно, если бы другие инструменты имеют применимость 99,99999%, пока они не будут игнорировать только один конкретный случай – твой Отказ Но теперь вы полностью забрали контроль потока отпуска. Вы можете улучшить и изменить этот фрагмент, как вы хотите, и всякий раз, когда вам нравится.
Release.mjs GH Release.yaml Релиз-журнал
SEMREL-EXTRE/ZX-SEMREL
` Сценарий высвобождения на основе ZX как `Semantic-Release`
ZX Сценарий выпуска, как семантический релиз Альтернатива (POC)
Иногда кровавое предприятие обеспечивает не использовать какие-либо сторонние решения для чувствительных операций (например, выпуск, развертывание, так далее) старый хороший скрипт Копировальная вставка спешит к спасению!
Требования
- Mac/Linux.
- Node.js.
- Git.0
- zx.6.0
Ключевая особенность
- Нулевые зависимости
- Нулевая конфигурация
- Достаточно быстро
- Крошечный , менее 140 строк с комментариями
- Надежность, безопасность, простота и ремонтопригодность (сарказм)
Функциональность
- Бедный обычные комбиниты анализ
Changelog.mdпоколениеpackage.jsonВерсия наталки- Git Release Commit Create
- Выпуск GitHub
- Пакет публикации для обоих NPMJS. и gh реестры
🚀 Использование
- Скопировать
- Подпись, впрыскивая токены и т. Д.
- Бежать
curl https://raw.githubusercontent.com/antongolub/zx-semrel/master/release.mjs > ./release.mjs zx ./release.mjs
или просто это, как если ZX не установлен:
# Just replace GIT* env values with your own GIT_COMMITTER_NAME=antongolub GIT_COMMITER_EMAIL=mailbox@antongolub.ru GITHUB_TOKEN=token npx zx ./release.mjs
или беги как без редактирования, хотя NPX. :
# Cross your fingers for luck
Оригинал: “https://dev.to/antongolub/you-don-t-need-semantic-release-sometimes-3k6k”