Пошук уроків, статей та іншого контенту
Присвоюйте версіям формат MAJOR.MINOR.PATCH і визначайте правила їх зміни відповідно до сумісності API.
Semantic Versioning, або SemVer, — це правило нумерації версій програмного забезпечення у форматі:
MAJOR.MINOR.PATCHНаприклад:
2.4.1Кожна частина номера повідомляє користувачам, які зміни відбулися:
MAJOR — несумісні зміни API;
MINOR — нові функціональні можливості зі збереженням сумісності;
PATCH — виправлення помилок без зміни API.
Основна мета SemVer — дозволити користувачеві зрозуміти, чи безпечно оновлювати залежність.
Базова версія має вигляд:
MAJOR.MINOR.PATCHУсі три частини є невід’ємними цілими числами без провідних нулів:
1.0.0 # коректно
2.15.3 # коректно
01.2.3 # некоректно
1.2 # неповна версіяПровідний нуль не використовується, щоб не створювати неоднозначність:
1.02.3не є коректним записом SemVer.
Збільшуйте MAJOR, якщо зміна порушує сумісність із попереднім API.
Наприклад, бібліотека має функцію:
getUser(id)У новій версії функцію перейменували:
findUser(id)Код користувача, який викликає getUser, перестане працювати. Це breaking change, тому версія змінюється, наприклад, так:
2.3.4 → 3.0.0Типові зміни MAJOR-рівня:
видалення публічної функції;
перейменування методу або властивості;
зміна формату аргументів;
зміна типу значення, яке повертає функція;
зміна формату відповіді API;
зміна поведінки, на яку покладалися клієнти;
підвищення мінімально підтримуваної версії платформи, якщо це ламає сумісність.
Було:
createUser(name, email)Стало:
createUser({ name, email, role })Старий виклик більше не працює без адаптації:
createUser("Olena", "olena@example.com")Така зміна потребує збільшення MAJOR.
Збільшуйте MINOR, якщо додаєте нову функціональність, але не ламаєте наявний API.
Наприклад, до бібліотеки додали нову функцію:
deleteUser(id)Усі попередні функції продовжують працювати. Тоді:
2.3.4 → 2.4.0Типові зміни MINOR-рівня:
додавання нової функції;
додавання нового необов’язкового параметра;
додавання нового поля у відповідь, якщо клієнти можуть безпечно його ігнорувати;
додавання нового endpoint без зміни наявних endpoint;
додавання нового режиму роботи за замовчуванням без зміни старої поведінки.
Важливо, щоб нова можливість не змушувала користувачів змінювати наявний код.
Збільшуйте PATCH, якщо виправляєте помилки або покращуєте внутрішню реалізацію без зміни публічного API.
Наприклад:
виправили неправильний розрахунок;
усунули витік пам’яті;
виправили обробку помилки;
оптимізували алгоритм;
оновили внутрішню реалізацію, зберігши ту саму поведінку API.
Приклад:
2.3.4 → 2.3.5Виправлення безпеки також зазвичай випускають як PATCH, якщо воно не змінює API несумісним способом.
Після збільшення старшої частини всі молодші частини скидаються до нуля:
1.4.7 → 1.4.8 # PATCH
1.4.8 → 1.5.0 # MINOR
1.5.0 → 2.0.0 # MAJORНе можна випускати версію:
1.4.7 → 2.5.8Якщо змінився MAJOR, MINOR і PATCH починаються з нуля.
Якщо змінився MINOR, PATCH починається з нуля.
SemVer працює лише тоді, коли команда чітко визначає, що є публічним API.
До API можуть належати:
експортовані функції;
публічні класи;
назви та типи параметрів;
HTTP endpoint;
структура JSON-відповідей;
CLI-команди та їхні параметри;
формати конфігураційних файлів;
події та їхні payload.
Внутрішні функції, які не доступні користувачам, зазвичай не впливають на MAJOR-версію.
Наприклад, перейменування внутрішньої функції:
function calculateInternalValue() {
// Внутрішня реалізація не є частиною публічного API
}може бути PATCH-зміною або взагалі не вимагати окремого релізу, якщо зовнішня поведінка не змінилася.
Перед релізом перевірте зміни в такому порядку:
Чи порушено сумісність із публічним API?
Так — збільшіть MAJOR.
Якщо ні, чи додано нову сумісну функціональність?
Так — збільшіть MINOR.
Якщо ні, чи виправлено помилки або внутрішню реалізацію?
Так — збільшіть PATCH.
Якщо зміни не впливають на програму, наприклад виправлено документацію, номер версії можна не змінювати.
Приклад:
Поточна версія: 1.8.2Зміни:
виправлено помилку в кешуванні;
додано метод clearCache();
видалено метод resetCache().
Оскільки видалення методу порушує сумісність, підсумкова версія:
2.0.0MAJOR має пріоритет над MINOR і PATCH.
Версії до 1.0.0 часто використовують для програм, API яких ще не вважається стабільним:
0.1.0
0.2.0
0.2.1У такому періоді команда може частіше змінювати API. Проте це не означає, що правила можна ігнорувати.
Корисна домовленість:
0.MINOR.PATCH — MINOR може містити несумісні зміни;
PATCH — виправлення без істотної зміни API;
1.0.0 — перша стабільна версія публічного API.
Точне трактування версій 0.x варто зафіксувати в документації проєкту.
До базової версії можна додати ідентифікатор попереднього релізу через дефіс:
2.0.0-alpha
2.0.0-beta.1
2.0.0-rc.2Такі версії називають prerelease-версіями. Вони призначені для тестування і можуть бути нестабільними.
Порядок попередніх версій:
2.0.0-alpha
2.0.0-beta
2.0.0-rc.1
2.0.0Стабільна версія 2.0.0 має вищий пріоритет, ніж будь-яка її prerelease-версія.
Поширені позначення:
alpha — рання експериментальна версія;
beta — версія для ширшого тестування;
rc — release candidate, кандидат у стабільні версії.
Після символу + можна вказати метадані збірки:
1.4.2+20260902
1.4.2+linux.x64Метадані можуть описувати середовище або ідентифікатор збірки. Вони не впливають на порядок версій:
1.4.2+build-101
1.4.2+build-102мають однаковий пріоритет як версії SemVer.
Не використовуйте метадані збірки для позначення функціональних або breaking changes. Для цього призначені MAJOR, MINOR і PATCH.
Git не змінює номер версії автоматично. Зазвичай версію фіксують у Git за допомогою тегу.
Припустімо, поточна версія — 1.4.2, а виправлення вже закомічено:
git status
git log --oneline -5Створіть анотований тег:
git tag -a v1.4.3 -m "Release v1.4.3"Перевірте тег:
git show v1.4.3Опублікуйте тег у віддаленому репозиторії:
git push origin v1.4.3Після цього список тегів можна переглянути так:
git tag --listПоширений формат тегів:
v1.0.0
v1.1.0
v1.1.1Літера v є домовленістю про назву Git-тегу, а сама SemVer-версія — це 1.1.1. Важливо, щоб команда використовувала один формат послідовно.
Невеликий скрипт може перевірити базову версію і збільшити потрібну частину.
function parseVersion(version) {
const match = version.match(/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/);
if (!match) {
throw new Error(`Некоректна версія: ${version}`);
}
return {
major: Number(match[1]),
minor: Number(match[2]),
patch: Number(match[3]),
};
}
function bumpVersion(version, releaseType) {
const parsed = parseVersion(version);
if (releaseType === "major") {
parsed.major += 1;
parsed.minor = 0;
parsed.patch = 0;
} else if (releaseType === "minor") {
parsed.minor += 1;
parsed.patch = 0;
} else if (releaseType === "patch") {
parsed.patch += 1;
} else {
throw new Error(`Невідомий тип релізу: ${releaseType}`);
}
return `${parsed.major}.${parsed.minor}.${parsed.patch}`;
}
console.log(bumpVersion("1.4.2", "patch")); // 1.4.3
console.log(bumpVersion("1.4.2", "minor")); // 1.5.0
console.log(bumpVersion("1.4.2", "major")); // 2.0.0Цей приклад працює лише з базовими версіями MAJOR.MINOR.PATCH. Для prerelease-версій і метаданих потрібен окремий розбір суфіксів.
Пакетні менеджери часто використовують діапазони версій, щоб дозволити сумісні оновлення.
Наприклад, діапазон:
^1.4.2зазвичай означає: дозволити оновлення від 1.4.2 до версій, сумісних у межах MAJOR 1.
Діапазон:
~1.4.2зазвичай дозволяє PATCH-оновлення в межах 1.4.x.
Точне трактування залежить від інструмента та його правил. SemVer визначає значення номерів версій, а не синтаксис конкретного менеджера пакетів.
Послідовність релізу може виглядати так:
Переглянути зміни від попереднього тегу.
Визначити, чи є breaking changes.
Обрати MAJOR, MINOR або PATCH.
Оновити номер версії в проєкті.
Запустити тести та перевірки.
Створити коміт із новою версією.
Створити анотований Git-тег.
Опублікувати коміт і тег у віддаленому репозиторії.
Додати опис змін до release notes.
Приклад команд:
git add package.json
git commit -m "chore: bump version to 1.5.0"
git tag -a v1.5.0 -m "Release v1.5.0"
git push origin main
git push origin v1.5.0Версія має відповідати фактичним змінам, а не лише назві коміту.
Якщо старий код перестає працювати, версія 1.2.4 → 1.2.5 вводить користувачів в оману.
Для несумісних змін потрібен перехід на новий MAJOR:
1.2.4 → 2.0.0Додавання сумісної функції не потребує MAJOR:
1.2.0 → 1.3.0MAJOR призначений саме для змін, які порушують сумісність.
Некоректно:
1.4.2 → 2.4.3Коректно:
1.4.2 → 2.0.0Якщо команда не визначила, які функції, поля чи endpoint є публічними, оцінити сумісність буде складно.
Зафіксуйте:
що підтримується офіційно;
що може змінюватися без попередження;
які зміни вважаються breaking;
як випускаються prerelease-версії.
Тег release-final-2 не передає інформації про сумісність. Краще використовувати послідовні теги:
v2.0.0
v2.1.0
v2.1.1Номер версії сам по собі не гарантує сумісність. Після змін потрібно запускати тести, перевіряти приклади використання та аналізувати публічний API.
Semantic Versioning використовує формат MAJOR.MINOR.PATCH.
MAJOR збільшується для несумісних змін API.
MINOR збільшується для нової сумісної функціональності.
PATCH збільшується для виправлень без зміни API.
Після збільшення MAJOR або MINOR молодші частини скидаються до нуля.
Prerelease-версії мають суфікс на кшталт -alpha або -rc.1.
Метадані збірки після + не впливають на порядок версій.
У Git версії зручно фіксувати анотованими тегами, наприклад v1.5.0.
Правильний номер версії має відображати сумісність публічного API, а не кількість змінених файлів.