Engineering

Van conventional commits naar een changelog

5 min lezen bijgewerkt op

Conventional commits geven een changelog drie dingen gratis: het type van elke verandering, het deel van het systeem dat het raakte, en of het iets breekt. Meer geven ze niet. Formulering, groepering en selectie, wat de changelog is, blijven volledig open, en een pipeline die anders doet alsof levert een geformatteerde git log.

feat(exports): add CSV column selection
fix(auth): reject expired refresh tokens
chore(deps): bump node-pg to 8.11

Drie commits in het formaat Conventional Commits. Hieruit kan een machine je vertellen dat de een een feature is, de een een fix, de een huishouding, en welk deel van het systeem elk raakte. Dat is echt nuttig, en het is de hele belofte van de conventie: een commit-geschiedenis die door iets anders dan een persoon kan worden gelezen. De fout is denken dat dat je een changelog oplevert. Het levert je de grondstof.

Wat specificeert de conventie?

Een type, een optioneel scope, en een beschrijving: type(scope): description. Types zijn conventioneel feat, fix, chore, docs, refactor, test, perf, build, ci. Twee dingen markeren een breaking change: een ! voor de dubbele punt, of een BREAKING CHANGE:-footer. Tooling stuurt op feat en fix voor minor- en patch-versiesprongen, en op de breaking-marker voor een major.

De commit geeft jeDe changelog heeft nodigWie de kloof opvult
feat / fix / choreAdded / Fixed / internEen mapping, automatisch
(scope)Een groepering die de lezer herkentEen persoon, eenmaal per scope
! of BREAKING CHANGE:Wie breekt, tegen wanneer, en wat te doenEen persoon, elke keer
De beschrijving, geschreven voor een reviewerHet resultaat, geschreven voor een klantEen persoon, elke entry
Eén commitEén verandering, die meerdere commits kan zijnSquash-regels, of een persoon

De marker vertelt het aan de tooling; het vertelt het niet aan de aanroeper, wat het onderwerp is van hoe deprecieer je een API en wat is een breaking change. Het is een kleine spec en het is de moeite waard om te volgen, zelfs als je er nooit iets uit genereert, omdat het één beslissing per commit afdwingt: is dit een verandering die gebruikers zien, of niet.

Waar stoppen conventional commits?

Ze stoppen bij de zin. Alles wat de conventie vastlegt is metadata over een verandering; de verandering zelf wordt nog steeds beschreven in het vocabulaire van een reviewer.

Commitberichten zijn geschreven voor reviewers. fix(auth): reject expired refresh tokens is correct en vertelt een klant niets. De lezer van een changelog wil “je wordt uitgelogd wanneer een sessie echt is verlopen, in plaats van intermitterende 401’s te zien”.

Scopes zijn intern. exports, auth, ingest zijn modulenamen. Ze zijn stabiel, wat ze goed maakt om te groeperen, en betekenisloos voor iedereen buiten de codebase.

Eén verandering is vaak meerdere commits. Een feature die over elf commits is gemerged produceert elf entries, tien daarvan ruis, en die weg-squashen om dat te verbergen verliest de reviewgeschiedenis.

chore is een prullenbak, geen categorie. Dependency-updates, CI-wijzigingen en hernoemingen belanden allemaal daar, en sommige tellen voor gebruikers terwijl de meeste niet.

Dus: de conventie geeft je type, scope en breaking-status gratis, en laat formulering, groepering en selectie volledig open. Die drie zijn de changelog. Wie is eigenlijk eigenaar van een changelog-item behandelt wie zich met die formulering, groepering en selectie zou moeten bezighouden, aangezien de conventie zelf daar geen mening over heeft.

Hoe genereer je een changelog uit conventional commits?

In twee lagen, en de tweede moet verplicht zijn.

Laag één, automatisch. Leid bij het mergen een conceptentry af uit de commit: type gemapt naar een changelog-type (feat naar Added, fix naar Fixed, een breaking-marker naar Changed plus een vlag), scope bewaard als metadata in plaats van als tekst, link naar de PR. Zet het in de Unreleased-sectie die Keep a Changelog vraagt.

Laag twee, menselijk, en vereist. Voordat een release uitgaat, krijgt elke conceptentry ofwel een herschrijving van één regel in het vocabulaire van de gebruiker, ofwel wordt hij intern gemarkeerd en uit de publieke weergave gehaald. Dit is de stap die mensen proberen over te slaan, en overslaan is wat changelogs oplevert die als een diff lezen.

Het belangrijke ontwerpdetail is dat laag twee niet optioneel is in de pipeline. Als een release kan worden gesneden met ongewijzigde concepten, zal dat gebeuren, in de week dat iedereen het druk heeft. Welke stappen bij de machine horen en welke bij de persoon is het hele onderwerp van changelog-automatisering.

De release snijden is ook het moment waarop een git-tag, een release en deze changelog-regel of samenkomen of uit sync beginnen te raken; git-tags, releases en je changelog behandelt hoe je de drie synchroon houdt.

Drie valkuilen

Squash-merges eten de footers op. Als jullie platform squasht met de PR-titel als bericht, verdwijnt de BREAKING CHANGE:-footer van een commit binnen die branch, en jullie tooling stopt stilletjes met het zien van de breaking change. Controleer wat jullie squash-template werkelijk bewaart.

Revert-commits produceren spookentries. Een fix die de volgende dag wordt gerevert genereert een entry voor iets dat nooit is uitgebracht, tenzij de afleiding reverts verrekent. De meeste tools doen dat niet.

Versiesprong en changelog raken uit de pas. Als de versie wordt berekend uit commits en de changelog daarna met de hand wordt geschreven, drijven ze binnen ongeveer twee releases uiteen. Bereken beide in dezelfde stap of accepteer dat een van de twee fout is.

Als je het mechanische deel wilt zonder pipeline

Onze changelog-generator doet de afleidingsstap in de browser: plak commits, krijg gegroepeerde, getypeerde entries. Het is bewust deterministisch en volledig clientside, dus de commits die je plakt verlaten nooit je machine, wat telt wanneer de berichten uit een privérepository komen. Het doet de verzamelingshelft eerlijk en waagt geen poging tot laag twee, omdat laag twee een oordeel is en een tool die dat veinst precies de changelog oplevert waartegen dit artikel argumenteert.

Voor de pipelineversie dekt changelog-tools wat er bestaat.

De samenvatting

Conventional commits beantwoorden “wat voor soort verandering is dit” betrouwbaar en goedkoop. Ze beantwoorden niet “wat moeten we mensen vertellen”, en geen hoeveelheid tooling boven op het commitbericht zal dat doen, omdat de informatie nooit in het commitbericht zat. Begroot de herschrijving.

FAQ

Genereren conventional commits automatisch een changelog? Ze genereren automatisch een concept: getypeerde, gescopte, gelinkte entries. De formulering voor een klant, de groepering en de beslissing wat weg te laten hebben nog steeds een persoon nodig, en een pipeline die die stap overslaat publiceert commitberichten.

Welke conventional-commit-types verschijnen in een changelog? feat en fix altijd, als Added en Fixed. perf meestal, als Changed. chore, docs, refactor, test, build en ci zijn standaard intern en verschijnen alleen als een persoon er een promoot.

Hoe markeren conventional commits een breaking change? Een ! na het type of scope (feat(api)!: ...), of een BREAKING CHANGE:-footer in de body van de commit. Beide gaan verloren als een squash-merge alleen de PR-titel behoudt.

Heb je conventional commits nodig om een changelog te automatiseren? Nee. PR-labels, PR-templates en issue-links dragen dezelfde metadata voor teams die via pull request mergen. Conventional commits zijn de goedkoopste optie wanneer de eenheid van verandering de commit is.


De technische beweringen in dit artikel zijn niet onafhankelijk gecontroleerd. Klopt er iets niet, laat het ons weten, dan corrigeren we het.

Meer op changeloop: Changelog-generator, Changelog-tools vergeleken

changeloop
Het team achter een changelog die de cirkel rondmaakt. Je gebruikers vragen iets, je team levert het, degene die het vroeg hoort ervan.