Dai conventional commits a un changelog
6 min di lettura aggiornato il
I conventional commit regalano a un changelog tre cose: il tipo di ogni cambiamento, la parte del sistema che ha toccato, e se rompe qualcosa. Non gli regalano nient’altro. Formulazione, raggruppamento e selezione, che sono il changelog, restano completamente aperti, e una pipeline che finge il contrario spedisce un git log formattato.
feat(exports): add CSV column selection
fix(auth): reject expired refresh tokens
chore(deps): bump node-pg to 8.11
Tre commit nel formato Conventional Commits. Da questi, una macchina può dirvi che uno è una funzionalità, uno è una correzione, uno è manutenzione, e quale parte del sistema ha toccato ciascuno. Questo è genuinamente utile, ed è tutta la promessa della convenzione: una cronologia dei commit leggibile da qualcosa di diverso da una persona. L’errore è pensare che questo vi dia un changelog. Vi dà la materia prima.
Cosa specifica la convenzione?
Un tipo, uno scope opzionale, e una descrizione: type(scope): description. I tipi
convenzionalmente sono feat, fix, chore, docs, refactor, test, perf, build, ci.
Due cose segnano un cambiamento che rompe qualcosa: un ! prima dei due punti, o un footer
BREAKING CHANGE:. Gli strumenti si basano su feat e fix per i bump di versione minor e patch,
e sul marcatore di breaking per uno major.
| Il commit vi dà | Il changelog ha bisogno di | Chi colma il divario |
|---|---|---|
feat / fix / chore | Added / Fixed / interno | Una mappatura, automatica |
(scope) | Un raggruppamento che il lettore riconosce | Una persona, una volta per scope |
! o BREAKING CHANGE: | Chi si rompe, per quando, e cosa fare | Una persona, ogni volta |
| La descrizione, scritta per una revisora | Il risultato, scritto per una cliente | Una persona, ogni voce |
| Un commit | Un cambiamento, che può essere più commit | Regole di squash, o una persona |
Il marcatore lo dice allo strumento; non lo dice al chiamante, che è l’argomento di come deprecare un’API e cos’è un cambiamento che rompe qualcosa. È una specifica piccola e vale la pena seguirla anche se non generate mai nulla da essa, perché forza una decisione per commit: è un cambiamento che gli utenti vedono, o no.
Dove si fermano i conventional commit?
Si fermano alla frase. Tutto ciò che la convenzione cattura sono metadati su un cambiamento; il cambiamento stesso è ancora descritto nel vocabolario di una revisora.
I messaggi di commit sono scritti per revisore. fix(auth): reject expired refresh tokens è
corretto e non dice nulla a una cliente. La lettrice di un changelog vuole “verrai disconnesso
quando una sessione è davvero scaduta, invece di vedere 401 intermittenti”.
Gli scope sono interni. exports, auth, ingest sono nomi di moduli. Sono stabili, il che
li rende buoni per raggruppare, e privi di significato per chiunque sia fuori dalla codebase.
Un cambiamento è spesso più commit. Una funzionalità mergiata su undici commit produce undici voci, dieci delle quali rumore, e schiacciarle per nasconderlo perde la cronologia di revisione.
chore è un cassetto, non una categoria. Aggiornamenti di dipendenze, cambiamenti CI e
rinomine finiscono tutti lì, e alcuni contano per gli utenti mentre la maggior parte no.
Quindi: la convenzione vi dà tipo, scope e stato di breaking gratis, e lascia formulazione, raggruppamento e selezione completamente aperti. Quei tre sono il changelog. A chi appartiene davvero una voce di changelog copre chi dovrebbe occuparsi di quella formulazione, raggruppamento e selezione, dato che la convenzione stessa non ha un’opinione a riguardo.
Come si genera un changelog dai conventional commit?
In due strati, e il secondo deve essere obbligatorio.
Strato uno, automatico. Al merge, derivate una voce bozza dal commit: tipo mappato su un tipo
di changelog (feat su Added, fix su Fixed, un marcatore di breaking su Changed più un flag),
scope tenuto come metadato piuttosto che come testo, link alla PR. Fatela atterrare nella sezione
Unreleased che Keep a Changelog richiede.
Strato due, umano, e richiesto. Prima che esca un rilascio, ogni voce bozza o riceve una riscrittura di una riga nel vocabolario dell’utente, o viene marcata interna e scartata dalla vista pubblica. Questo è il passo che la gente cerca di saltare, e saltarlo è ciò che produce changelog che si leggono come un diff.
Il dettaglio importante di design è che lo strato due non è opzionale nella pipeline. Se un rilascio può essere tagliato con bozze non editate, lo sarà, nella settimana in cui tutti sono impegnati. Quali passi appartengono alla macchina e quali alla persona è tutto il tema di automazione del changelog.
Tagliare il rilascio è anche il momento in cui un tag git, una release e questa voce di changelog o combaciano o iniziano a disallinearsi; tag git, release e il tuo changelog copre come mantenere i tre sincronizzati.
Tre trappole
Gli squash merge mangiano i footer. Se la vostra piattaforma schiaccia con il titolo della PR
come messaggio, il footer BREAKING CHANGE: di un commit dentro quel branch scompare, e il vostro
strumento smette silenziosamente di vedere il cambiamento che rompe qualcosa. Controllate cosa
mantiene davvero il vostro template di squash.
I commit di revert producono voci fantasma. Un fix che viene revertito il giorno dopo genera
una voce per qualcosa che non è mai stato rilasciato, a meno che la derivazione non riconcili i
revert. La maggior parte degli strumenti non lo fa.
Il bump di versione e il changelog si disallineano. Se la versione è calcolata dai commit e il changelog è scritto a mano dopo, divergono in circa due rilasci. Calcolate entrambi nello stesso passaggio o accettate che uno dei due sia sbagliato.
Se volete la parte meccanica senza una pipeline
Il nostro generatore di changelog fa il passo di derivazione nel browser: incollate i commit, ottenete voci raggruppate e tipizzate. È deliberatamente deterministico ed interamente lato client, così i commit che incollate non lasciano mai la vostra macchina, il che conta quando i messaggi provengono da un repository privato. Fa onestamente la metà di raccolta e non tenta lo strato due, perché lo strato due è un giudizio e uno strumento che lo finge produce esattamente il changelog contro cui argomenta questo articolo.
Per la versione pipeline, strumenti per il changelog copre cosa esiste.
Il riassunto
I conventional commit rispondono “che tipo di cambiamento è questo” in modo affidabile ed economico. Non rispondono “cosa dovremmo dire alla gente”, e nessuna quantità di strumenti sopra il messaggio di commit lo farà, perché l’informazione non è mai stata nel messaggio di commit. Mettete in budget la riscrittura.
FAQ
I conventional commit generano automaticamente un changelog? Generano automaticamente una bozza: voci tipizzate, con scope, collegate. La formulazione per una cliente, il raggruppamento e la decisione su cosa lasciare fuori hanno ancora bisogno di una persona, e una pipeline che salta quel passo pubblica messaggi di commit.
Quali tipi di conventional commit appaiono in un changelog?
feat e fix sempre, come Added e Fixed. perf di solito, come Changed. chore, docs,
refactor, test, build e ci sono interni per default e appaiono solo se una persona ne
promuove uno.
Come segnano i conventional commit un cambiamento che rompe qualcosa?
Un ! dopo il tipo o lo scope (feat(api)!: ...), o un footer BREAKING CHANGE: nel corpo del
commit. Entrambi si perdono se uno squash merge conserva solo il titolo della PR.
Servono i conventional commit per automatizzare un changelog? No. Le etichette PR, i template PR e i link agli issue portano gli stessi metadati per i team che mergiano tramite pull request. I conventional commit sono l’opzione più economica quando l’unità di cambiamento è il commit.
Le affermazioni tecniche di questo articolo non sono state verificate in modo indipendente. Se qualcosa non è corretto, faccelo sapere e lo correggeremo.