Ingegneria

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 diChi colma il divario
feat / fix / choreAdded / Fixed / internoUna mappatura, automatica
(scope)Un raggruppamento che il lettore riconosceUna persona, una volta per scope
! o BREAKING CHANGE:Chi si rompe, per quando, e cosa fareUna persona, ogni volta
La descrizione, scritta per una revisoraIl risultato, scritto per una clienteUna persona, ogni voce
Un commitUn cambiamento, che può essere più commitRegole 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.

Correlati su changeloop: Generatore di changelog, Strumenti di changelog a confronto

changeloop
Il team che costruisce un changelog che chiude il cerchio. I tuoi utenti chiedono, il tuo team rilascia, chi ha chiesto lo viene a sapere.