Dato un numero di versione MAJOR.MINOR.PATCH, incrementate la:
Sono disponibili etichette aggiuntive per il pre-release e i metadati di build comeestensioni al formato MAJOR.MINOR.PATCH.
Nel mondo della gestione del software esiste un luogo terrificante chiamato“inferno della dipendenza”. Quanto più cresce il vostro sistema e quanti più pacchetti integrate nel vostro software, tanto più facilmente vi ritroverete, un giorno, in questa valle di lacrime.
Nei sistemi con molte dipendenze, rilasciare nuove versioni di pacchetti può diventare rapidamente un incubo. Se le specifiche di dipendenza sono troppo stringenti, siete a rischio di blocco di versione (l’impossibilità di aggiornareun pacchetto senza dover rilasciare nuove versioni di ogni pacchetto dipendente). Se le dipendenze sono specificate in modo troppo permissivo, sareteinevitabilmente afflitti da promiscuità di versione (l’ipotizzare compatibilità con versioni future più di quanto sia ragionevole). L’inferno della dipendenza è dove siete quando blocco di versione e/o promiscuità di versione vi impediscono di far avanzare il vostro progetto in modo facile e sicuro.
Come soluzione a questo problema, propongo un semplice insieme di regole e requisiti che stabiliscono come i numeri di versione siano assegnati ed incrementati.Queste regole sono basate su, ma non necessariamente limitate a, diffusepratiche comuni adottate sia in software proprietario che open source.Affinché questo sistema funzioni, avete prima bisogno di dichiarare un’API pubblica. Quest’ultima può consistere di documentazione o essere imposta tramiteil codice stesso. In ogni caso, è importante che tale API sia chiara e precisa. Una volta identificata la vostra API pubblica, comunicatene le modifiche con incrementi specifici del numero di versione. Considerate un formato di versione X.Y.Z (Major.Minor.Patch). La correzione di bug, non influenzandol’API, incrementa la versione Patch, aggiunte/modifiche retrocompatibili all’APIincrementano la versione Minor, e modifiche non retrocompatibili all’APIincrementano la versione Major.
Chiamo questo sistema “Versionamento Semantico”. Con queste convenzioni i numeri di versione, ed il modo in cui essi cambiano, comunicano significato relativamenteal codice sottostante e a cosa è stato modificato da una versione all’altra.
Le parole chiave “DEVE” (“MUST”), “NON DEVE” (“MUST NOT”), “REQUIRED”, “SHALL”, “SHALL NOT”, “DOVREBBE” (“SHOULD”), “SHOULD NOT”, “RECOMMENDED”, “PUO’” (“MAY”), e “OPTIONAL” in questo documento sono da interpretarsi come descritto nellaRFC 2119.
Software che usa Versionamento Semantico DEVE dichiarare un’API pubblica. Questa API potrebbe essere dichiarata nel codice stesso oppure essere definita rigorosamente nella documentazione. Indipendentemente da come è dichiarata, dovrebbeessere precisa a completa.
Un numero di versione normale DEVE essere nella forma X.Y.Z, dove X, Y, e Z sono interi non negativi, e NON DEVONO contenere zeri iniziali. X è la versionemajor, Y è la versione minor, e Z è la versione patch.Ogni elemento DEVE incrementare come numero a sé. Per esempio: 1.9.0 -> 1.10.0 -> 1.11.0.
Una volta che un pacchetto versionato è stato rilasciato, i contenuti diquella versione NON DEVONO essere modificati. Qualsiasi modifica DEVE essererilasciata come una nuova versione.
La versione Major zero (0.y.z) è per lo sviluppo iniziale. Qualunque cosapuò cambiare in qualsiasi istante. L’API pubblica non dovrebbe essere considerata stabile.
La versione 1.0.0 definisce l’API pubblica. Il modo in cui il numero di versione è incrementato dopo questo rilascio dipende da questa API pubblicae da come quest’ultima cambia.
La versione Patch Z (x.y.Z | x > 0) DEVE essere incrementata solo se sonointrodotte correzioni retrocompatibili di bug. Una correzione di un bug èdefinita come una modifica interna che corregge un comportamento errato.
La versione Minor Y (x.Y.z | x > 0) DEVE essere incrementata se nell’API pubblica è introdotta una nuova funzionalità retrocompatibile. Essa DEVE essereincrementata se qualsiasi funzionalità dell’API pubblica è marcata come deprecata. Essa PUO’ essere incrementata se sono introdotti all’interno del codice privato nuove funzionalità o miglioramenti sostanziali. Essa PUO’ includere modifiche di livello patch. La versione Patch DEVE esserereimpostata a 0 quando la versione Minor è incrementata.
La versione Major X (X.y.z | X > 0) DEVE essere incrementata se nell’API pubblica è introdotta qualsiasi modifica non retrocompatibile. Essa PUO’ includere modifiche di livello minor e patch. Le versioni patch e minor DEVONOessere reimpostate a 0 quando la versione major è incrementata.
Una versione di pre-rilascio PUO’ essere indicata aggiungendo immediatamente dopo la versione patch un trattino e una serie di identificatori separati dal punto. Gli identificatori DEVONO essere composti solo da alfanumerici ASCII e trattini [0-9A-Za-z-]. Gli identificatori NON DEVONO essere vuoti. Gliidentificatori numerici NON DEVONO includere zeri iniziali. Le versioni dipre-rilascio hanno una precedenza inferiore rispetto alla versione normaleassociata. Una versione di pre-rilascio indica che la versione è instabilee potrebbe non soddisfare i requisiti di compatibilità intesi come indicato dalla versione normale ad essa associata. Esempi: 1.0.0-alpha, 1.0.0-alpha.1, 1.0.0-0.3.7, 1.0.0-x.7.z.92.
Metadati di build POSSONO essere indicati aggiungendo immediatamente dopo laversione patch o pre-rilascio un segno di addizione e una serie di identificatori separati dal punto. Gli identificatori DEVONO essere composti solo da alfanumerici ASCII e trattini [0-9A-Za-z-]. Gli identificatori NON DEVONO essere vuoti. I metadati di build dovrebbero essere ignorati nella determinazione della precedenza delle versione. Perciò due versioni che differiscono solo per i metadati di build, hanno la stessa precedenza. Esempi: 1.0.0-alpha+001, 1.0.0+20130313144700, 1.0.0-beta+exp.sha.5114f85.
La precedenza si riferisce a come le versioni sono confrontate l’una conl’altra quando poste in relazione d’ordine. La precedenza DEVE essere calcolata separando gli identificatori nell’ordine seguente: major, minor, patch e pre-release (i metadati di build non compaiono nella precedenza). La precedenza è determinata dalla prima discrepanza quando si confrontano ognuno di tali identificatori da sinistra a destra come segue: le versioni major, minor e patch sono sempre confrontate numericamente. Esempio: 1.0.0 < 2.0.0 < 2.1.0 < 2.1.1. Quando major, minor, e patch sono uguali, una versione di pre-rilascio ha una precedenza inferiore rispetto alla versione normale. Esempio: 1.0.0-alpha < 1.0.0. La precedenza per due versioni di pre-rilascio con la stessa versione major, minor, e patch DEVE essere determinata confrontando ognuno degli identificatoriseparati dal punto da sinistra a destra finché si trova una discrepanza come segue: gli identificatori costituiti da sole cifre sono confrontati numericamente e gli identificatori con lettere o trattini sono confrontatilessicalmente secondo l’ordinamento ASCII. Gli identificatori numerici hannosempre una precedenza più bassa rispetto agli identificatori non numerici. Un insieme più grande di identificatori ha una precedenza superiore rispettoad un insieme più piccolo, se tutti quanti i precedenti identificatori sono uguali. Esempio: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta <1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0.
Questa non è un’idea rivoluzionaria. Infatti, probabilmente fate già qualcosa disimile a questo. Il problema è che quel “simile” non è abbastanza buono.Senza la conformità a qualche tipo di specifica formale, i numeri di versionesono essenzialmente inutili per una gestione delle dipendenze. Dando un nomeed una chiara definizione alle idee sopra, diventa semplice comunicare le vostreintenzioni agli utenti del vostro software. Quando queste intenzioni sono chiare,flessibili (ma non troppo flessibili) le specifiche di dipendenza possonofinalmente essere realizzate.
Un semplice esempio dimostrerà come Versionamento Semantico può rendere l’inferno della dipendenza una cosa del passato. Considerate una libreriachiamata “CamionDeiPompieri”. Essa richiede un pacchetto semanticamente versionato di nome “Scala”. All’istante in cui è creato, Scala è alla versione 3.1.0. Poiché CamionDeiPompieri utilizza alcune funzionalità che furono inizialmente introdotte in 3.1.0, potete specificare con sicurezza la dipendenza da Scala come maggiore o uguale a 3.1.0 ma minore di 4.0.0. Ora, quando Scala versione 3.1.1 e 3.2.0 diventano disponibili, potete rilasciarle al vostro sistema di gestione dei pacchetti e sapere che esse saranno compatibili con software dipendente esistente.
In qualità di sviluppatori responsabili vorrete, naturalmente, verificare chequalsiasi aggiornamento di pacchetto funzioni come descritto. Il mondo reale èun luogo caotico; non possiamo farci nulla se non essere vigili. Ciò che potetefare è consentire a Versionamento Semantico di fornirvi un modo sano di rilasciare ed aggiornare i pacchetti senza dover propagare le nuove versioniai pacchetti dipendenti, facendovi risparmiare tempo e fastidio.
Se tutto questo vi suona desiderabile, tutto ciò che vi serve fare per iniziare ad usare Versionamento Semantico è dichiarare che state facendo così e poi seguire le regole. Rimandate a questo sito web dal vostro LEGGIMI (README) così altriconosceranno le regole e potranno beneficiarne.
La cosa più semplice da fare è cominciare da 0.1.0 con il rilascio di sviluppo iniziale e poi incrementare la versione minor per ogni successivo rilascio.
Se il vostro software è usato in produzione, dovrebbe probabilmente già esserealla 1.0.0. Se avete un’API stabile dalla quale gli utenti sono diventati dipendenti, dovreste essere alla 1.0.0. Se vi state preoccupando molto relativamente alla retrocompatibilità, dovreste probabilmente già essere alla 1.0.0.
La versione Major zero riguarda completamente lo sviluppo rapido. Se state modificando l’API ogni giorno dovreste o essere già nella versione 0.y.z oppure essere su un ramo di sviluppo separato lavorando alla prossimaversione major.
Questa è una questione di sviluppo responsabile e lungimiranza. Modificheincompatibili non dovrebbero essere introdotte con leggerezza a software cheha molto codice dipendente. Il costo in cui si potrebbe incorrere per aggiornarepotrebbe essere significativo. Dover dar colpi alla versione major per rilasciare modifiche incompatibili significa che penserete all’impatto delle vostre modifiche, e valuterete il rapporto costi/benefici coinvolto.
E’ vostra responsabilità come sviluppatori professionisti documentare appropriatamente software il cui uso è destinato ad altri. Gestire lacomplessità del software è una parte enormemente importante per mantenereun progetto efficiente, e ciò è difficile da fare se nessuno sa come usare ilvostro software, o nessuno sa con sicurezza quali metodi sono invocabili. Nel lungo periodo Versionamento Semantico, ed il perseverare su un’API pubblica ben documentata, è in grado di far andare tutto liscio.
Non appena realizzate di aver infranto le specifiche di Versionamento Semantico,correggete il problema e rilasciate una nuova versione minor che corregga il problema e ripristini la retrocompatibilità. Perfino in tali circostanze,non è accettabile modificare una versione rilasciata. Se è appropriato,documentate la versione illecita ed informate i vostri utenti del problema cosicchésiano consapevoli della versione illecita.
Ciò sarebbe considerato compatibile poiché non interessa l’API pubblica.Software che dipendono esplicitamente dalle stesse dipendenze del vostro pacchetto dovrebbero avere le loro proprie specifiche di dipendenza e l’autore noterà qualsiasi conflitto. Determinare se la modifica sia di livello patch ominor dipende se avete aggiornato le vostre dipendenze per correggere un bug oper introdurre una nuova funzionalità. In quest’ultimo caso solitamente mi aspetto del codice aggiuntivo, ed ovviamente un incremento della versioneminor.
Utilizzate il buon senso. Se avete una platea immensa che sarebbe drasticamenteimpattata dal ripristinio del comportamento atteso dell’API pubblica, allorapotrebbe essere meglio eseguire un rilascio di una versione major, perfino sela correzione potrebbe strettamente essere considerata il rilascio di una patch.Ricordate, Versionamento Semantico, è finalizzato alla comunicazione di significato attraverso il cambiamento del numero di versione. Se tali modifiche sono importanti per i vostri utenti, usate il numero di versioneper informarli.
Deprecare funzionalità esistenti fa parte del normale sviluppo di software ed èspesso necessario per fare progressi in avanti. Quando deprecate parte dellavostra API pubblica, dovreste fare due cose: (1) aggiornare la vostra documentazioneper consentire agli utenti di essere consapevoli della modifica, (2) distribuireun nuovo rilascio minor con la deprecazione all’interno. Prima di rimuoverecompletamente la funzionalità nel rilascio di una nuova major dovrebbe esserci al minimo un rilascio minor che contenga la deprecazione cosicché gli utenti siano in grado di migrare tranquillamente alla nuova API.
No, ma usate il buon senso. Per esempio, una stringa di versione di 255 caratteri è eccessiva. Inoltre, sistemi specifici possono imporre i loro limiti sulla dimensione.
No, “v1.2.3” non è una versione semantica. Tuttavia, prefissare una versione semanticacon una “v” è un modo comune (in inglese) di indicare che si tratta di un numero di versione.L’abbreviazione “v” per “version” si incontra spesso nel controllo di versione. Esempio:git tag v1.2.3 -m "Release version 1.2.3"
, ove “v1.2.3” è un nome di tage la versione semantica è “1.2.3”.
Ne esistono due. Una con i gruppi nominati per quei sistemi che li supportano(PCRE [Perl Compatible Regular Expressions, i.e. Perl, PHP ed R], Pythone Go).
Vedi:https://regex101.com/r/Ly7O1x/3/
^(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$
…ed una con invece i gruppi di cattura numerati (quindi cg1 = major, cg2 = minor,cg3 = patch, cg4 = prerelease and cg5 = buildmetadata) che è compatibilecon ECMA Script (JavaScript), PCRE (Perl Compatible Regular Expressions,i.e. Perl, PHP ed R), Python e Go.
Vedi:https://regex101.com/r/vkijKf/1/
^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$
La specifica di Versionamento Semantico è scritta daTomPreston-Werner, inventore di Gravatars ecofondatore di GitHub.
Traduzione a cura delJava User Group Padova:
…e diLorenzo L. Ancora (autore)
Per lasciare il vostro feedback per favoreaprite una segnalazione su GitHub.