Mundarija (36)
- Bu darsda
- 1. Nega bu kerak?
- 2. SemVer: qisqa takror va yangi detallar
- 2.1 Uch raqam
- 2.2 0.x va pre-release
- 2.3 Keyingi versiyani hisoblaymiz
- 3. CHANGELOG: kim uchun va qanday
- 3.1 Keep a Changelog
- 3.2 Avtomatik CHANGELOG
- 4. Reliz quvuri
- 5. Uch vosita
- 5.1 conventional-changelog — eng sodda
- 5.2 semantic-release — to'liq avtomat
- 5.3 changesets — har PR bilan o'zgarish fayli
- 5.4 release-please — reliz PR'i
- 5.5 Qaysi birini tanlash
- 6. GitHub Release va tag
- 7. Loyiha qadami: 4.0.1 relizi
- 7.1 Kanon tajribasi: uch vosita, bitta javob
- 7.2 Versiya va CHANGELOG
- 7.3 Reliz paytida topilgan xato
- 7.4 Commit va tag
- 8. Ko'p uchraydigan xatolar
- 8.1 Versiya ikki joyda
- 8.2 CHANGELOG'da yangi bo'lim yo'q
- 8.3 Buzuq havolalar
- 8.4 changeset init osilib qoldi yoki exit 13
- 8.5 "Packages to be bumped:" bo'sh
- 8.6 Tag yuborilmadi
- 9. Mashqlar
- 1-mashq (oson): bo'shliqlarni to'ldiring
- 2-mashq (o'rta): pre-release'larni tartiblash
- 3-mashq (qiyin): o'z CHANGELOG generatoringiz
- 10. Real ishda
- Xulosa
- Manbalar
CHANGELOG va reliz avtomatikasi: release-please, semantic-release, changesets
Qisqacha: Reliz — foydalanuvchiga chiqarilgan, raqamlangan versiya. Uning ikki hujjati bor: versiya raqami (SemVer:
fix→ patch,feat→ minor, buzuvchi o'zgarish → major) va CHANGELOG — "nima o'zgardi" ro'yxati. Ikkalasini qo'lda yuritish unutiladi va eskiradi. Shuning uchun ular Conventional Commits xabarlaridan avtomatik hosil qilinadi: semantic-release (CI'da to'liq avtomat), release-please (reliz PR'i orqali), changesets (har PR bilan alohida o'zgarish fayli). Kanon tajribasida uchala vositavazifalar-apiuchun bir xil javob berdi — 4.0.1.
Bu darsda
- SemVer qoidalarini,
0.xva pre-release (-beta.1) versiyalarini qo'llaysiz. - Keep a Changelog formatidagi CHANGELOG'ni o'qiysiz va yozasiz.
- Commit xabarlaridan keyingi versiyani o'zingiz hisoblaydigan funksiya yozasiz.
- conventional-changelog, semantic-release va changesets'ni lokal ishga tushirasiz, release-please qanday ishlashini bilasiz.
vazifalar-apining 4.0.1 relizini chiqarasiz: CHANGELOG, versiya, tag.
Oldin bilishingiz kerak: Tag va relizlar, Semver va versiya diapazonlari, Conventional Commits va commitlint, Bisect.
1. Nega bu kerak?
Bisect darsida breaker nuqsonini tuzatdik va fix(ai): … commitini qildik. Endi bu tuzatish foydalanuvchiga yetib borishi kerak. Ikki savol tug'iladi.
Birinchisi: qaysi versiya? package.json da 4.0.0 turibdi. Keyingisi 4.0.1 mi, 4.1.0 mi, 5.0.0 mi? Javob noto'g'ri bo'lsa, API'dan foydalanayotganlar adashadi. Masalan, ^4.0.0 deb bog'langan loyiha buzuvchi o'zgarishni "xavfsiz yangilanish" deb oladi.
Ikkinchisi: nima o'zgardi? Foydalanuvchi har commitni o'qimaydi. Unga qisqa ro'yxat kerak: "4.0.1 da — AI so'rovlari endi 25 soniyada tugaydi, zaxira model to'silmaydi". Bu ro'yxat CHANGELOG (o'zgarishlar tarixi) faylida turadi.
Kanon reliz paytida yana bir haqiqiy xatoni topdi. MCP server o'z versiyasini mijozga aytadi — va u mcp-server.ts ichida "4.0.0" deb qotirib yozilgan edi. package.json 4.0.1 ga o'tdi, MCP esa "men 4.0.0" deyishda davom etardi. Bir narsa ikki joyda yozilsa, biri albatta eskiradi. Versiya va CHANGELOG ham shunday: ularni qo'lda yuritsangiz, bir kun unutasiz.
Hayotiy o'xshatish: choyxonadagi menyu. Oshpaz retseptni o'zgartirdi, lekin devordagi menyu va kassadagi narx ro'yxati eski qoldi. Mehmon bir narsani ko'radi, boshqasini oladi. Yechim — bitta manbadan (oshxona daftari) hammasini avtomatik chop etish. Bizda bu manba — commit xabarlari.
2. SemVer: qisqa takror va yangi detallar
2.1 Uch raqam
Tag va relizlar va Semver darslaridan bilasiz: versiya MAJOR.MINOR.PATCH.
| O'zgarish | Commit turi | Misol |
|---|---|---|
| xato tuzatildi, hech narsa buzilmadi | fix: |
4.0.0 → 4.0.1 |
| yangi imkoniyat, eskisi ishlaydi | feat: |
4.0.1 → 4.1.0 |
| eski kod buziladi | feat!: yoki BREAKING CHANGE: |
4.1.0 → 5.0.0 |
| hujjat, sozlama, test | docs:, chore:, test: |
reliz yo'q |
Conventional Commits darsidagi xabar formati shu jadval uchun yaratilgan. ! sarlavhada yoki tanadagi BREAKING CHANGE: qatori — "bu o'zgarish eski foydalanuvchilarni buzadi" degan belgi. Bir nechta commit bo'lsa, eng kattasi yutadi: bitta feat va o'nta fix — minor.
2.2 0.x va pre-release
Ikki holat alohida qoidaga ega (semver.org, 2.0.0):
0.y.z— boshlang'ich ishlab chiqish. "Hamma narsa istalgan payt o'zgarishi mumkin, ommaviy API'ni barqaror deb hisoblamang." Loyiha hali shakllanayotgan bo'lsa —0.x. Birinchi barqaror reliz —1.0.0.- Pre-release (oldindan chiqariladigan versiya) — chiziqcha va belgi:
4.1.0-beta.1,5.0.0-rc.2. Bu "tayyor emas, sinab ko'ring" degani. Pre-release asosiy versiyadan oldin turadi:4.1.0-beta.1<4.1.0.
Pre-release'lar o'zaro qanday tartiblanadi? Nuqta bilan ajratilgan qismlar chapdan solishtiriladi. Raqamlar — son sifatida (beta.2 < beta.11), so'zlar — alifbo bo'yicha (alpha < beta < rc). Buni 2-mashqda funksiya qilib yozasiz.
^ va ~ belgilarini eslang: ^4.0.0 — 4.x.x ning istalgani (major o'zgarmasa), ~4.0.0 — faqat 4.0.x. Ikkalasi ham pre-release'larni sukut bo'yicha olmaydi (Semver darsi). Demak, 5.0.0-beta.1 chiqarib, foydalanuvchilarni buzib qo'yish xavfi yo'q — beta faqat aniq so'raganlarga yetadi.
2.3 Keyingi versiyani hisoblaymiz
Reliz vositalari ichida xuddi shu mantiq ishlaydi. Uni o'zimiz yozib ko'ramiz:
const SARLAVHA = /^(\w+)(?:\(([^)]*)\))?(!)?: (.+)$/;
const DARAJA = { patch: 1, minor: 2, major: 3 };
function ozgarishTuri(xabar) {
const [sarlavha, ...tana] = xabar.split("\n");
const m = sarlavha.match(SARLAVHA);
if (!m) return null;
const [, tur, , undov] = m;
const buzuvchi = tana.some((q) => q.startsWith("BREAKING CHANGE:"));
if (undov || buzuvchi) return "major";
if (tur === "feat") return "minor";
if (tur === "fix") return "patch";
return null;
}
function keyingiVersiya(joriy, xabarlar) {
let eng = null;
for (const x of xabarlar) {
const t = ozgarishTuri(x);
if (t && (!eng || DARAJA[t] > DARAJA[eng])) eng = t;
}
if (!eng) return null;
const [ma, mi, pa] = joriy.split(".").map(Number);
if (eng === "major") return `${ma + 1}.0.0`;
if (eng === "minor") return `${ma}.${mi + 1}.0`;
return `${ma}.${mi}.${pa + 1}`;
}
console.log(keyingiVersiya("4.0.0", ["fix(ai): alohida breaker"]));
console.log(keyingiVersiya("1.2.0", [
"feat(cli): --baza bayrog'i",
"fix: yaxlitlash 2 xonagacha",
"feat(cli)!: --json chiqish formati sukut bo'yicha",
]));
console.log(keyingiVersiya("1.2.0", ["docs: README", "chore: kesh"]));Konsolda:
4.0.1
2.0.0
nullBirinchi qator — vazifalar-api: bitta fix → patch. Ikkinchisi — uchta commit, eng kattasi ! → major. Uchinchisi — faqat hujjat va sozlama: reliz kerak emas, null.
Muntazam ifoda (regex) sarlavhani to'rt qismga ajratadi: tur (fix), qavs ichidagi soha (ai), ixtiyoriy ! va tavsif. Uni Conventional Commits darsidagi commitlint qoidasi bilan solishtiring — ular bir formatni o'qiydi.
Tekshirib ko'ring: Joriy versiya
2.3.1. Oxirgi relizdan beri uchta commit:fix: sana formati,refactor: nomlash,perf: ro'yxat tezroq. BizningkeyingiVersiyanima qaytaradi?
Javob
2.3.2. fix — patch; refactor va perf bizning funksiyada reliz bermaydi. Haqiqiy vositalarda perf qanday hisoblanishi presetga (vosita ishlatadigan tayyor qoidalar to'plamiga) bog'liq — sozlamasini hujjatdan tekshiring (biz sinamadik). Qoida: versiyaga ta'sir qiladigan turlar ro'yxatini jamoa kelishib, sozlamaga yozib qo'yadi.
3. CHANGELOG: kim uchun va qanday
3.1 Keep a Changelog
CHANGELOG — odamlar uchun yozilgan o'zgarishlar ro'yxati. Eng mashhur kelishuv — Keep a Changelog (keepachangelog.com, 1.1.0). Uning asosiy qoidalari (rasmiy sahifadan, 2026-11-04 da tekshirildi):
- eng yangi versiya — tepada;
- har versiyada sana (
2026-11-04shaklida); - o'zgarishlar turlarga bo'linadi: Added, Changed, Deprecated, Removed, Fixed, Security;
- tepada Unreleased bo'limi — hali relizga chiqmagan o'zgarishlar shu yerda yig'iladi.
Muhim fikr: CHANGELOG — git log emas. Unda "lint tuzatildi", "test qo'shildi" kabi ichki ishlar bo'lmaydi. Foydalanuvchiga ta'sir qiladigan narsalargina yoziladi.
3.2 Avtomatik CHANGELOG
Commit xabarlari to'g'ri yozilsa, CHANGELOG'ni ulardan hosil qilish mumkin: feat → "Features", fix → "Bug Fixes", ! → "BREAKING CHANGES". Turlar Keep a Changelog'dagidan biroz boshqacha nomlanadi, lekin g'oya bir xil. docs, chore, test kirmaydi — ular foydalanuvchi uchun emas.
Narxi: sifat commit xabarlariga bog'liq. "fix: tuzatdim" degan xabar CHANGELOG'da ham "tuzatdim" bo'lib chiqadi. Avtomatika yaxshi xabar yozish odatini majburiy qiladi — va bu yaxshi.
4. Reliz quvuri
Reliz vositalari ichida bir xil qadamlar turadi:
flowchart LR
C["commitlar: fix, feat, !"] --> A["tahlil: patch / minor / major"]
A --> V["versiya: package.json"]
A --> L["CHANGELOG.md"]
V --> T["git tag v4.0.1"]
L --> T
T --> R["GitHub Release, npm"]Chapdan o'qing. Oxirgi tagdan beri commitlar tahlil qilinadi va eng katta o'zgarish versiyani belgilaydi. Keyin package.json va CHANGELOG yangilanadi, tag qo'yiladi, oxirida reliz e'lon qilinadi. Vositalar shu zanjirni kim va qachon boshlashida farq qiladi.
5. Uch vosita
Uchala vosita ham vazifalar-api tarixida sinaldi: v4.0.0 tagi va undan keyin bitta fix(ai): … commiti. Hammasi lokal, GitHub'ga hech narsa yuborilmadi. Versiyalar 2026-10-27 dan oldin chiqqan, ya'ni kamida bir hafta sinovdan o'tgan.
| Vosita | Qanday ishlaydi | Kanon natijasi |
|---|---|---|
| conventional-changelog-cli 5.0.0 | commitlardan Markdown | ## 4.0.1 → "Bug Fixes" |
| semantic-release 25.0.9 | CI'da: tahlil → versiya → tag → reliz | "The next release version is 4.0.1" |
| @changesets/cli 3.0.3 | PR bilan .changeset/*.md → changeset version |
package.json 4.0.1 |
| release-please 17.11.2 | GitHub'da reliz PR'i | sinalmagan |
5.1 conventional-changelog — eng sodda
Faqat CHANGELOG yozadi. Versiyani o'zi tanlamaydi — uni package.json dan oladi. Kanon CHANGELOG'i aynan shu vosita bilan qurildi.
Kichik namuna repo'da sinab ko'ramiz: valyuta CLI paketi, v1.2.0 tagidan keyin 5 ta commit, oxirgisi buzuvchi:
94b9c07 (HEAD -> main) feat(cli)!: --json chiqish formati sukut bo'yicha
3b14fc0 chore: kesh papkasi .gitignore ga
31ff4f4 docs: README misollari
b5293bf fix: yaxlitlash 2 xonagacha
455a92e feat(cli): --baza bayrog'i
1423afd (tag: v1.2.0) feat: kurslarni CBU API'dan olishOxirgi commit tanasida: BREAKING CHANGE: jadval endi --jadval bayrog'i bilan; skriptlar --jadval qo'shsin.
npm version 2.0.0 --no-git-tag-version
npx --yes conventional-changelog-cli@5.0.0 -p conventionalcommitsBiz ishga tushirdik (vosita kanon o'rnatgan nusxadan, Node 24.21.0; sarlavhadagi havola manzili (…) bilan qisqartirildi — u pastda alohida):
## [2.0.0](…) (2026-11-04)
### ⚠ BREAKING CHANGES
* **cli:** jadval endi --jadval bayrog'i bilan; skriptlar --jadval qo'shsin.
### Features
* **cli:** --baza bayrog'i 455a92e
* **cli:** --json chiqish formati sukut bo'yicha 94b9c07
### Bug Fixes
* yaxlitlash 2 xonagacha b5293bfUch narsaga e'tibor bering:
docsvachoreyo'q — foydalanuvchi uchun emas.- BREAKING CHANGES tepada, alohida — yangilanishdan oldin o'qilishi shart.
- Sarlavhadagi havola buzuq: uning manzili —
///compare/v1.2.0...v2.0.0. Repo'daoriginremote yo'q edi, vosita GitHub manzilini bilmadi. Kanon tajribasida esa remote lokal papka edi va havolalarga kompyuter yo'li tushdi. Shuning uchun kanon CHANGELOG'idan havolalar olib tashlangan. GitHub'dagi repo'da havolalar to'g'ri chiqadi.
Yana bir tuzoq: yangi bo'lim sarlavhasi package.json versiyasidan olinadi. Avval npm version qilmasangiz, vosita yangi versiyani bilmaydi. Tartib: avval versiya, keyin CHANGELOG.
Diqqat: npm'da
conventional-changelog-clipaketi "This package is no longer maintained" — "endi qo'llab-quvvatlanmaydi" deb belgilangan (2026-11-04 holati). Vorisi —conventional-changelogpaketining o'z CLI'si. Biz uning 8.1.3 versiyasini xuddi shuvalyutarepo'sida sinadik: natija yuqoridagi bilan bir xil chiqdi. Ikki farqi bor. Preset (tayyor qoidalar to'plami) — alohida paket:conventional-changelog-conventionalcommits. Sukut bo'yicha natija ekranga emas,CHANGELOG.mdfayliga yoziladi; ekranda ko'rish uchun--stdoutbayrog'i kerak. Kanon CHANGELOG'i 5.0.0 bilan qurilgan, shuning uchun darsdagi buyruqlar shu versiyada qoldi.
5.2 semantic-release — to'liq avtomat
semantic-release hamma qadamni o'zi bajaradi: tahlil, versiya, CHANGELOG (plaginlar bilan), tag, GitHub Release, npm'ga chiqarish. U CI'da ishlash uchun yaratilgan: hujjatiga ko'ra, reliz branch'idagi (odatda main) har muvaffaqiyatli build'dan keyin ishga tushadi. Odam versiya raqamini umuman tanlamaydi.
Lokal sinash uchun --dry-run (hech narsani o'zgartirmay, faqat ko'rsatish) va --no-ci bayroqlari bor. Xuddi shu valyuta repo'sida biz ishga tushirdik (remote — lokal "bare" repo; vaqt belgilari olib tashlandi, faqat asosiy qatorlar). Chiqishda uch narsani qidiring: oxirgi tag, commitlar soni va "next release version":
[semantic-release] » ℹ Running semantic-release version 25.0.9
[semantic-release] » ✔ Allowed to push to the Git repository
[semantic-release] » ℹ Found git tag v1.2.0 associated with version 1.2.0 on branch main
[semantic-release] » ℹ Found 5 commits since last release
[semantic-release] [@semantic-release/commit-analyzer] » ℹ The release type for the commit is major
[semantic-release] [@semantic-release/commit-analyzer] » ℹ Analysis of 5 commits complete: major release
[semantic-release] » ℹ The next release version is 2.0.0
[semantic-release] » ⚠ Skip v2.0.0 tag creation in dry-run mode"5 commit tahlil qilindi: major reliz. Keyingi versiya — 2.0.0. Dry-run'da tag yaratilmadi." Bizning keyingiVersiya funksiyasi bilan aynan bir xil javob.
Allowed to push qatoriga qarang. semantic-release dry-run'da ham remote'ga yozish huquqini tekshiradi — u tag va relizni o'zi yuboradi. Shuning uchun lokal sinov uchun remote kerak bo'ldi.
Diqqat: Lokal sinovdagi tuzoq.
git init --bareyangi repo'ning sukut branch'ini Git sozlamasidan oladi. Umasterbo'lsa, siz esamainyuborsangiz, bare repo'ningHEADi bo'sh branch'ga qaraydi. Biz shu holatni qayta yaratdik:
fatal: couldn't find remote ref HEAD"Remote'da HEAD topilmadi" — semantic-release ichidagi
git fetch128 kod bilan yiqildi. Davosi:git init --bare -b main.
5.3 changesets — har PR bilan o'zgarish fayli
changesets boshqacha yondashadi: versiyani commit xabaridan emas, odam yozgan fayldan oladi. Har PR bilan birga kichik fayl qo'shiladi:
---
"valyuta": minor
---
--baza bayrog'i: istalgan valyutaga nisbatan kurs.Tepada — qaysi paket va qanday o'zgarish (patch, minor, major). Pastda — CHANGELOG'ga tushadigan matn. Bu fayl PR review'dan o'tadi: "minor deb belgilabsiz, lekin bu buzuvchi o'zgarish-ku" degan izoh aynan shu yerda yoziladi.
Reliz paytida bitta buyruq hamma fayllarni yig'adi:
npx changeset status
npx changeset versionvalyuta repo'sida ikki fayl (minor va patch) bilan biz ishga tushirdik:
🦋 changeset v3.0.3
Packages to be bumped:
- minor
- valyuta
🦋 changeset v3.0.3
All files have been updated. Review them and commit at your leisureNatija: package.json — 1.3.0, .changeset/ papkasida faqat config.json qoldi, CHANGELOG.md:
# valyuta
## 1.3.0
### Minor Changes
- --baza bayrog'i: istalgan valyutaga nisbatan kurs.
### Patch Changes
- Kurslar 2 xonagacha yaxlitlanadi.Ikki o'zgarish bitta relizga birlashdi, eng kattasi (minor) yutdi. changesets ayniqsa monorepo'da kuchli: bitta repo'da bir nechta paket bo'lsa, har PR qaysi paketga tegishini aniq aytadi. Monorepo'ni Git va monorepo darsida ko'ramiz.
Kanon topgan ikki tuzoq, ikkalasini biz ham qayta ko'rdik:
changeset initinteraktiv. 3.x versiyada u savol beradi: "Should the GitHub integration be used for changelogs?". Kiritish bo'lmasa (CI, skript) jarayonexit 13bilan tugaydi. Yechim —.changeset/config.jsonni qo'lda yozish."private": truepaket.vazifalar-apinpm'ga chiqmaydi, shuning uchunpackage.jsondaprivate: true. changesets bunday paketni sukut bo'yicha versiyalamaydi:changeset status"Packages to be bumped:" deydi va ro'yxat bo'sh. Config'ga"privatePackages": { "version": true, "tag": false }qo'shilgach — ishladi.
5.4 release-please — reliz PR'i
release-please (Google) GitHub bilan ishlaydi. U Actions'da yuradi va har main ga merge'dan keyin reliz PR'ini ochadi yoki yangilaydi. PR ichida — yangi versiya va CHANGELOG. Jamoa relizga tayyor bo'lganda shu PR'ni merge qiladi. Shunda release-please tag va GitHub Release yaratadi (github.com/googleapis/release-please, sinalmagan, 2026-11).
Kanonda u sinalmagan: lokal repoda ishlamaydi (GitHub API kerak), sinov reposida esa Actions o'chiq edi. Bu darsdagi tavsif — rasmiy hujjatdan.
5.5 Qaysi birini tanlash
| Holat | Mos vosita |
|---|---|
| CHANGELOG kerak, versiyani o'zingiz tanlaysiz | conventional-changelog |
| npm kutubxona, har merge — reliz | semantic-release |
| reliz vaqtini jamoa tanlaydi, GitHub'da | release-please |
| monorepo, ko'p paket | changesets |
Kanon vazifalar-api uchun conventional-changelog ni tanladi: lokal ishlaydi, token va CI talab qilmaydi (loyihaning CI fayli hozircha qo'lda ishga tushiriladi). CI to'liq ishlaganda (GitHub Actions chuqur darsi) release-please yoki semantic-release'ga o'tish oson: commit xabarlari allaqachon tayyor.
Tekshirib ko'ring: Jamoangizda commit xabarlari tartibsiz ("tuzatdim", "update"), lekin har PR'ga tavsif yoziladi. Qaysi vosita mosroq va nega?
Javob
changesets. U versiya va CHANGELOG matnini commit xabaridan emas, PR bilan qo'shilgan .changeset/*.md fayldan oladi. semantic-release va release-please xabarlarni tahlil qiladi — tartibsiz xabarlarda ular "reliz yo'q" deydi yoki noto'g'ri versiya beradi. Uzoq muddatda baribir Conventional Commits'ga o'tish yaxshi, lekin changesets'ni hozir boshlash mumkin.
6. GitHub Release va tag
Tag — Git'ning o'zida, GitHub Release esa GitHub'dagi sahifa: tag + sarlavha + izoh + fayllar. Tag va relizlar darsida uni brauzerda yaratish yo'lini ko'rgansiz. Avtomatik yo'l — gh buyrug'i (cli.github.com/manual/gh_release_create, sinalmagan, 2026-11):
gh release create v4.0.1 --title "4.0.1" --notes-file eslatma.mdKanonda GitHub Release yaratilmadi — faqat annotated tag yuborildi. Tag uchun bitta foydali odat: git push --follow-tags — joriy branch bilan birga unga tegishli annotated taglarni ham yuboradi. Oddiy git push taglarni yubormaydi (07-qismda ko'rgansiz).
7. Loyiha qadami: 4.0.1 relizi
7.1 Kanon tajribasi: uch vosita, bitta javob
Kanon uchala vositani vazifalar-api tarixida ishga tushirdi (v4.0.0 + fix(ai): …). Natija:
| Vosita | Javob | Vaqt |
|---|---|---|
| conventional-changelog | ## 4.0.1 → Bug Fixes |
16.6 s |
semantic-release --dry-run |
"Analysis of 1 commits complete: patch release" | 31.4 s |
| changesets | package.json 4.0.1, "Patch Changes" |
— |
Uchalasi ham 4.0.1. Vaqtlar yuklangan mashinada o'lchangan — taqqoslash uchun emas.
7.2 Versiya va CHANGELOG
O'z repo'ngizda tag bo'lmasa, avval qo'ying: 30-qism oxiridagi commitga v3.0.0, 31-qism oxiridagisiga v4.0.0 (Tag va relizlar darsidagi git tag -a). Keyin:
npm version 4.0.1 --no-git-tag-version
npx --yes conventional-changelog-cli@5.0.0 \
-p conventionalcommits -r 0 > CHANGELOG.mdnpm version package.json va package-lock.json dagi versiyani o'zgartiradi. --no-git-tag-version — commit va tag qilmasin, ularni o'zimiz qilamiz. -r 0 — CHANGELOG'ni butun tarixdan qayta quradi. Kanon faylning boshiga qisqa izoh qo'shdi va commit havolalarini olib tashladi:
# O'zgarishlar tarixi
Format — [Conventional Commits](https://www.conventionalcommits.org/) dan `conventional-changelog -p conventionalcommits` bilan hosil qilinadi (32-qism #02);
versiyalar — [SemVer](https://semver.org/): `fix` → patch, `feat` → minor, `!`/`BREAKING CHANGE` → major. Qo'lda tahrirlanmaydi — commit xabarlari to'g'ri yozilsin.
## 4.0.1 (2026-11-04)
### Bug Fixes
* **ai:** har modelga alohida circuit breaker va umumiy deadline; 31-qism nuqsonlari (b3157bc)
## 4.0.0 (2026-11-02)
### Features
* **ai:** kunlik kvota va javob keshi (foydalanuvchi bo'yicha), AI hodisalari; MCP server (stdio, API kalit bilan) (ddeead9)
...Kanon faylidan boshi; 4.0.0 ostida yana 6 ta feat va oxirida 3.0.0 bor. Sizda SHA'lar va sanalar boshqacha, GitHub remote bo'lsa — commitlar havola bo'lib chiqadi, ularni qoldiring.
API.md dagi qo'lda yozilgan "O'zgarishlar tarixi" bo'limi o'chirilmadi: tepasiga "4.0.1 dan boshlab — CHANGELOG.md" havolasi qo'shildi, eski qaydlar tarix uchun qoldi.
7.3 Reliz paytida topilgan xato
MCP server versiyasi ikki joyda edi. Endi src/mcp.ts uni package.json dan o'qiydi (kanon kodidan parcha, telefon uchun bo'lingan):
import { readFileSync } from "node:fs";
// ...
const { version } = JSON.parse(
readFileSync(new URL("../package.json", import.meta.url), "utf8"),
) as { version: string };
const server = mcpServerYarat(apiMijoz(url, kalit), version);new URL("../package.json", import.meta.url) — fayl yo'li joriy modulga nisbatan, qayerdan ishga tushirilishidan qat'i nazar (ESM import darsidagi import.meta). Bo'lingan nusxani biz loyihaning shu bosqichi nusxasida tsc --noEmit va ESLint bilan tekshirdik.
Kanon tekshiruvi: npm run check yashil (Vitest 346 + 1 skip), node dist/mcp.js ishga tushdi.
7.4 Commit va tag
git add -A
M="chore(release): 4.0.1 — CHANGELOG.md;"
M+=" fix(mcp): server versiyasi package.json dan"
git commit -m "$M"
git tag -a v4.0.1 -m "vazifalar-api 4.0.1"
git push --follow-tagsKanon xabarini aynan oldik. Lekin uning narxi bor. Vositalar faqat sarlavha boshidagi turni o'qiydi — bu yerda chore. Ichidagi fix(mcp) ni hech qaysi vosita ko'rmaydi va u keyingi CHANGELOG'ga tushmaydi. To'g'ri yo'l — ikki commit: avval fix(mcp): …, keyin chore(release): 4.0.1. "Bitta commit — bitta tur" qoidasi aynan shuning uchun.
Kanon sinov reposida (u monorepo: 07-qism portfoliosi va vazifalar-api yonma-yon) tag nomi vazifalar-api-v4.0.1 bo'ldi — portfolioning v1.0.0 tagi bilan to'qnashmasin. PR #11: github.com/Sarvarbek0704/ilmhamroh-git-sinov/pull/11. Sizning repo'ngizda bitta paket — oddiy v4.0.1 yetadi.
8. Ko'p uchraydigan xatolar
8.1 Versiya ikki joyda
package.json 4.0.1, ilova esa "4.0.0" deydi. Belgisi: kodda versiya satri qotirilgan. Davosi: bitta manba — package.json; qolganlari undan o'qisin. Bunday joylarni topish oson: git grep '"4.0.0"'.
8.2 CHANGELOG'da yangi bo'lim yo'q
conventional-changelog eski versiya bo'yicha yozdi yoki hech narsa qo'shmadi. Sabab: npm version qilinmagan, package.json hali eski versiyada. Davosi: avval versiya, keyin CHANGELOG.
8.3 Buzuq havolalar
CHANGELOG sarlavhasidagi havola ///compare/v1.2.0...v2.0.0 ga yoki kompyuteringizdagi papkaga qaraydi. Sabab: repo'da remote yo'q yoki u lokal papka. Davosi: git remote -v da GitHub manzili bo'lsin, yoki havolalarni olib tashlang.
8.4 changeset init osilib qoldi yoki exit 13
Biz stdin'siz ishga tushirganimizda vosita savol berdi va to'xtadi (terminal boshqaruv belgilari olib tashlandi):
◆ Should the GitHub integration be used for changelogs?
○ Yes / ● NoKeyin Warning: Detected unsettled top-level await … va exit 13. Bu — "javob kutyapman, lekin kiritish yo'q" degani. Terminalda o'zingiz javob bering yoki config.json ni qo'lda yozing.
8.5 "Packages to be bumped:" bo'sh
private: true paket. Config'ga privatePackages.version: true qo'shing.
8.6 Tag yuborilmadi
GitHub'da reliz yo'q, CHANGELOG'dagi taqqoslash havolasi 404. Sabab: git push taglarni yubormaydi. Davosi: git push origin v4.0.1 yoki git push --follow-tags.
9. Mashqlar
Mashqlar kurs/mashqlar/32/02-reliz/ da. 2- va 3-mashq yechimlari Node 24.21.0 da tekshirilgan (biz ishga tushirdik).
1-mashq (oson): bo'shliqlarni to'ldiring
- Joriy
3.4.2, yagona commitfeat: eksport— keyingi versiya - Joriy
3.4.2, commitfix!: sana formati o'zgardi— keyingi versiya - Pre-release
2.0.0-rc.1va2.0.0dan qaysi biri katta? — - changesets'da hamma o'zgarish fayllarini yig'ib, versiya va CHANGELOG'ni yangilaydigan buyruq —
npx changeset - Keep a Changelog'da hali chiqmagan o'zgarishlar bo'limi —
Yechim
- 3.5.0 —
feat→ minor, patch nolga tushadi. - 4.0.0 —
!turidan qat'i nazar major qiladi. - 2.0.0 — pre-release asosiy versiyadan oldin turadi.
- version —
changeset statusfaqat ko'rsatadi,versiono'zgartiradi. - Unreleased — reliz paytida u yangi versiya sarlavhasiga aylanadi.
2-mashq (o'rta): pre-release'larni tartiblash
versiyaSolishtir(a, b) funksiyasini yozing: a < b bo'lsa manfiy, teng bo'lsa 0, katta bo'lsa musbat son qaytarsin. Qoidalar (semver.org, 11-band):
- Avval
MAJOR.MINOR.PATCHsonlar sifatida solishtiriladi. - Ular teng bo'lsa: pre-release'siz versiya katta.
- Ikkalasida pre-release bo'lsa — nuqta bilan bo'lingan qismlar chapdan: ikkalasi son bo'lsa — son sifatida; son har doim so'zdan kichik; so'zlar — alifbo bo'yicha; qismlari kam bo'lgani kichik.
Ishora: split("-") bilan asosiy qism va pre-release'ni ajrating (bu mashqda pre-release ichida chiziqcha yo'q deb hisoblang); /^\d+$/.test(q) — qism sonmi. Massivni sort(versiyaSolishtir) bilan tartiblang (sort va taqqoslash funksiyasi).
Yechim
function qismSolishtir(x, y) {
const xSon = /^\d+$/.test(x);
const ySon = /^\d+$/.test(y);
if (xSon && ySon) return Number(x) - Number(y);
if (xSon) return -1;
if (ySon) return 1;
return x < y ? -1 : x > y ? 1 : 0;
}
function versiyaSolishtir(a, b) {
const [aAsos, aOld] = a.split("-");
const [bAsos, bOld] = b.split("-");
const aS = aAsos.split(".").map(Number);
const bS = bAsos.split(".").map(Number);
for (let i = 0; i < 3; i++) {
if (aS[i] !== bS[i]) return aS[i] - bS[i];
}
if (!aOld && !bOld) return 0;
if (!aOld) return 1;
if (!bOld) return -1;
const aQ = aOld.split(".");
const bQ = bOld.split(".");
for (let i = 0; i < Math.min(aQ.length, bQ.length); i++) {
const f = qismSolishtir(aQ[i], bQ[i]);
if (f !== 0) return f;
}
return aQ.length - bQ.length;
}
const versiyalar = [
"1.0.0", "1.0.0-rc.1", "1.0.0-beta.11", "1.0.0-beta.2",
"1.0.0-beta", "1.0.0-alpha.1", "1.0.0-alpha", "0.9.9",
];
console.log(versiyalar.sort(versiyaSolishtir));Konsolda:
[
'0.9.9',
'1.0.0-alpha',
'1.0.0-alpha.1',
'1.0.0-beta',
'1.0.0-beta.2',
'1.0.0-beta.11',
'1.0.0-rc.1',
'1.0.0'
]Bu tartib semver.org'dagi namunaga mos. Ikki nozik joy: beta.2 < beta.11 (son sifatida, matn bo'lsa "11" < "2" bo'lardi) va alpha < alpha.1 (qismi kami kichik). Haqiqiy loyihada bu ishni semver npm paketi qiladi — u bilan Semver darsida tanishgansiz.
3-mashq (qiyin): o'z CHANGELOG generatoringiz
changelogYasa(versiya, sana, xabarlar) funksiyasini yozing. U conventional-changelog'ning valyuta repo'si uchun bergan natijasini («conventional-changelog — eng sodda» bo'limi) SHA'larsiz va havolalarsiz qaytarsin:
- sarlavha:
## 2.0.0 (2026-11-04); ### ⚠ BREAKING CHANGES— tanasidaBREAKING CHANGE:bo'lgan commitlar shu matn bilan;!bor, lekin tana yo'q bo'lsa — tavsifi bilan;### Features(feat) va### Bug Fixes(fix); boshqa turlar kirmaydi;- soha bo'lsa —
* **soha:** tavsif, bo'lmasa —* tavsif; - bo'lim ichida tartib: avval soha (yo'q bo'lsa tavsif), keyin tavsif bo'yicha;
- bo'sh bo'lim chiqmaydi, bo'limlar orasida bitta bo'sh qator.
Ishora: «Keyingi versiyani hisoblaymiz» bo'limidagi SARLAVHA regex'i; qatorlarni massivga yig'ib, oxirida join("\n").
Yechim
const SARLAVHA = /^(\w+)(?:\(([^)]*)\))?(!)?: (.+)$/;
const BOLIMLAR = [["feat", "Features"], ["fix", "Bug Fixes"]];
const qator = (c) =>
c.soha ? `* **${c.soha}:** ${c.tavsif}` : `* ${c.tavsif}`;
const kalit = (c) => [c.soha ?? c.tavsif, c.tavsif];
function tartibla(royxat) {
return royxat.sort((a, b) => {
const [a1, a2] = kalit(a);
const [b1, b2] = kalit(b);
if (a1 !== b1) return a1 < b1 ? -1 : 1;
return a2 < b2 ? -1 : a2 > b2 ? 1 : 0;
});
}
function changelogYasa(versiya, sana, xabarlar) {
const commitlar = [];
const buzuvchi = [];
for (const x of xabarlar) {
const [sarlavha, ...tana] = x.split("\n");
const m = sarlavha.match(SARLAVHA);
if (!m) continue;
const [, tur, soha, undov, tavsif] = m;
const izoh = tana.find((q) => q.startsWith("BREAKING CHANGE: "));
if (izoh) {
buzuvchi.push({ soha, tavsif: izoh.slice(17) });
} else if (undov) {
buzuvchi.push({ soha, tavsif });
}
commitlar.push({ tur, soha, tavsif });
}
const chiqish = [`## ${versiya} (${sana})`];
if (buzuvchi.length) {
chiqish.push("", "### ⚠ BREAKING CHANGES", "");
chiqish.push(...tartibla(buzuvchi).map(qator));
}
for (const [tur, nom] of BOLIMLAR) {
const ular = commitlar.filter((c) => c.tur === tur);
if (!ular.length) continue;
chiqish.push("", `### ${nom}`, "");
chiqish.push(...tartibla(ular).map(qator));
}
return chiqish.join("\n");
}
console.log(changelogYasa("2.0.0", "2026-11-04", [
"feat(cli)!: --json chiqish formati sukut bo'yicha\n\n" +
"BREAKING CHANGE: jadval endi --jadval bayrog'i bilan; " +
"skriptlar --jadval qo'shsin.",
"chore: kesh papkasi .gitignore ga",
"docs: README misollari",
"fix: yaxlitlash 2 xonagacha",
"feat(cli): --baza bayrog'i",
]));Konsolda:
## 2.0.0 (2026-11-04)
### ⚠ BREAKING CHANGES
* **cli:** jadval endi --jadval bayrog'i bilan; skriptlar --jadval qo'shsin.
### Features
* **cli:** --baza bayrog'i
* **cli:** --json chiqish formati sukut bo'yicha
### Bug Fixes
* yaxlitlash 2 xonagachaVosita chiqishi bilan solishtiring: SHA'lar va sarlavha havolasidan boshqa hamma narsa bir xil. Commitlar git log tartibida (yangisi tepada) berilgan, lekin bo'lim ichida tartib o'zgardi — biz ham vosita kabi soha va tavsif bo'yicha saraladik. Haqiqiy vosita bundan ko'p ish qiladi: tag'lar oralig'ini topadi, Refs #12 kabi footer'larni issue havolasiga aylantiradi, revert commitlarini hisobga oladi.
10. Real ishda
- Qayerda uchraydi: har npm paketi va ochiq loyihada — CHANGELOG.md va GitHub Releases. Ko'p katta kutubxonalar o'z relizlarini shu vositalar bilan chiqaradi; qaysi biri ishlatilganini repo'dagi config fayldan bilasiz:
.releaserc,release-please-config.json,.changeset/. - Ilova va kutubxona farqi: kutubxonada semver — foydalanuvchilar bilan shartnoma. API ilovada esa mijozlar
^bilan bog'lanmaydi, lekin CHANGELOG va versiya baribir kerak: xato haqida xabar "qaysi versiyada?" deb boshlanadi. - Intervyu savollari: "Semver nima, major qachon oshadi?", "CHANGELOG'ni qanday yuritasiz?", "semantic-release va changesets farqi?", "
^1.2.3qaysi versiyalarni oladi?"
Xulosa
- Versiya:
fix→ patch,feat→ minor,!yokiBREAKING CHANGE→ major;docs,chore— reliz yo'q. 0.x— barqaror emas; pre-release (-beta.1) asosiy versiyadan oldin turadi va^uni sukut bo'yicha olmaydi.- CHANGELOG — odamlar uchun: eng yangisi tepada, turlarga bo'lingan, ichki ishlarsiz.
- conventional-changelog — faqat CHANGELOG; semantic-release — CI'da hammasi; release-please — reliz PR'i; changesets — PR bilan o'zgarish fayli.
- Bir narsa ikki joyda yozilsa, biri eskiradi: versiyaning yagona manbai —
package.json. vazifalar-api4.0.1 — uchala vosita bir xil javob berdi; taggit push --follow-tagsbilan yuboriladi.
Keyingi dars: Jamoa workflow'lari: GitHub flow, trunk-based, git-flow — bitta o'zgarish uch xil branch strategiyasida qanday tarix qoldirishini solishtiramiz.
Manbalar
- Semantic Versioning 2.0.0: https://semver.org/
- Keep a Changelog 1.1.0: https://keepachangelog.com/en/1.1.0/ (sinalmagan, 2026-11)
- Conventional Commits 1.0.0: https://www.conventionalcommits.org/en/v1.0.0/
- conventional-changelog: https://github.com/conventional-changelog/conventional-changelog
- semantic-release hujjati: https://semantic-release.org/ (eski gitbook manzili yopilgan va shu yerga yo'naltiradi)
- changesets: https://github.com/changesets/changesets
- conventional-changelog-cli npm sahifasi (eskirgan paket belgisi): https://www.npmjs.com/package/conventional-changelog-cli
- release-please: https://github.com/googleapis/release-please (vosita sinalmagan, tavsif — README'dan, 2026-11-04)
- GitHub CLI — gh release create: https://cli.github.com/manual/gh_release_create (sinalmagan, 2026-11)
- Kanon tajribasi (IlmHamroh, 2026-11-04): conventional-changelog-cli 5.0.0, semantic-release 25.0.9, @changesets/cli 3.0.3, Node 24.21.0.
valyutanamuna repo'si, semantic-release va changesets tuzoqlari, conventional-changelog 8.1.3 bilan qayta sinov, mashq yechimlari — biz ishga tushirdik (2026-11-04).
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!