facebook

Blog

Resta aggiornato

Proseguiamo il viaggio nel versionamento del codice aggiungendo i tool GitFlow e SemVer
Versionare i pacchetti Nuget con GitFlow e SemVer
martedì 04 Giugno 2019

Nel precedente articolo abbiamo visto come poter versionare i nostri pacchetti Nuget tramite l’uso di alcune classi come AssemblyInfo.cs. Seguendo questa tipologia di versionamento nella nostra azienda non abbiamo avuto grosse difficoltà, anche se con l’adozione di Git ci siamo chiesti se ci fosse un modo migliore per strutturare il nostro lavoro e di conseguenza il processo di versionamento. Per tale motivo abbiamo esaminato le diverse branching strategies che si usano con git, e l’approccio che abbiamo trovato più adatto alle nostre esigenze è stato quello di GitFlow.

L’approccio GitFlow

In sostanza GitFlow consente di dare un significato semantico ai branch di git in relazione a ciò su cui si sta lavorando. Ad esempio, se stiamo sviluppando su un branch feature, sappiamo di lavorare su una nuova feature da includere nella prossima release del nostro software. Di seguito una overview di GitFlow:

Overview di GitFlow

In GitFlow abbiamo due branch che vengono definiti come principali o storici e che esisteranno per tutta la vita del nostro repository. Questi branch sono:

  • master: contiene l’insieme delle release che abbiamo creato per il nostro software. I commit hanno origine dai branch di release o di hotfix prima di essere uniti a questo (merge);
  • develop: contiene le integrazioni necessarie per il prossimo rilascio, e da cui partono i nuovi branch di release. I commit di questo repository hanno origine dai branch di feature.

Insieme a questi branch, troviamo poi branch che hanno mediamente vita breve:

  • feature: racchiudono l’insieme delle nuove funzionalità da integrare nella prossima release. Nascono e vengono uniti al termine dello sviluppo della funzionalità con il branch develop;
  • release: racchiudono l’insieme delle feature che faranno parte della prossima release. I branch nascono da develop, e saranno uniti sia a master che a develop (a seguito delle fix sul branch stesso). I branch di release saranno inoltre taggati un attimo prima del merge con master e develop;
  • hotfix: racchiudono l’insieme delle fix che sono effettuate sul codice di produzione. I branch nascono da master e saranno uniti sia a master che a develop.

Da queste informazioni emerge un aspetto importante di GitFlow: l’esistenza di strette correlazioni fra i diversi branch. Possiamo considerare ciò un punto di forza di questo approccio, anche se in alcuni casi lo possono far sembrare un po’ troppo laborioso.

Un aspetto che invece ne favorisce l’adozione è l’ottima integrazione con i tool di sviluppo che usiamo. Possiamo infatti utilizzare GitFlow sia in Visual Studio (anche Code) oppure usare la comodissima CLI. Inoltre, alcuni client Git come SourceTree o Fork lo includono già tra le proprie funzionalità.

Vediamo un breve esempio di utilizzo di GitFlow tramite la CLI, partendo dall’implementazione di una feature e terminando con il suo rilascio.

Il primo passo è quello di inizializzare il repository con il comando git flow init: questo comando, tramite la richiesta di alcune informazioni, configura il repository e i nomi dei branch.

Ora siamo pronti per creare la nostra prima feature: il comando git flow feature start <nomeFeature> crea un nuovo branch di feature in cui andremo a sviluppare le nuove funzionalità da integrare nel nostro progetto. Terminata questa fase, possiamo unire le nuove modifiche con il branch develop usando il comando git flow feature finish <nomeFeature>. Questa operazione, oltre ad aggiornare develop, elimina anche il nostro branch di feature perché non è più necessario.

Nel momento in cui siamo pronti per rilasciare una nuova versione del nostro software: git flow release start <numero_release>. Questo comando crea un nuovo branch di release che sarà destinato principalmente al testing e conterrà bugfix in caso di problemi.

L’ultimo passo è quello di rilasciare il prodotto e unire tutte le modifiche al branch master. Il comando da utilizzare è git flow release finish <numero_release>, che effettua molteplici operazioni:

  • merge verso master;
  • tag della release con il proprio nome;
  • back-merge verso develop;
  • rimozione del branch di release.
Release Flow con GitFlow

Con questi semplici passi, e grazie all’ottima integrazione con la CLI, siamo in grado di creare un processo di sviluppo ben definito in maniera molto intuitiva.

A tal punto potrebbe però sorgere una domanda: in questo processo come stabiliamo il numero di versione associato al nome della branch di release? E più in generale, possiamo usare lo stesso numero per definire anche i branch “intermedi” che useremo per integrare le nuove release? La risposta a queste domande è SemVer.

GitFlow è accostato spesso al concetto di versionamento semantico. Offre cioè un insieme di regole che rendono semplice il versionamento di branch che hanno già un proprio significato all’interno del processo di lavoro.

L’adozione di SemVer e GitVersion

SemVer aiuta a definire il versionamento del software grazie ad una serie di regole basate su 3 numeri: major, minor e patch.

I principali numeri di SemVer

Come si evince dall’immagine, ogni numero viene incrementato a seconda di quale modifica stiamo effettuando all’interno del nostro software. L’aspetto interessante è che, oltre a questi numeri, possiamo prevedere anche la presenza di release intermedie per differenziare quelle che provengono da branch diversi dal master:

Pre-release e metadati in SemVer

Questi numeri, e in particolare le sezioni di pre-release e metadati, possono essere generati in base al branch che prendiamo in considerazione e favoriscono i processi di automazione e il testing.

Seguendo le regole relative ai branch che abbiamo visto in GitFlow e compreso il funzionamento di SemVer per avere nuovi numeri di versione, possiamo standardizzare il processo di assegnazione di un nuovo numero di release. A venirci in aiuto è un tool che si chiama GitVersion. Si tratta di uno strumento da riga di comando che ci consente, in base alla storia del nostro repository e al branch in cui ci troviamo, di generare il prossimo numero di versione.

Su Windows l’installazione è semplice grazie all’uso di Chocolatey.

Il comando gitversion init avvia un wizard di inizializzazione che ci guida con una serie di domande sulla scelta del versionamento che ci occorre. Scelto l’approccio GitFlow, salviamo al termine del wizard la configurazione gitversion.yml che sarà presente all’interno del repository e aiuterà la gestione delle versioni. A tal punto, per generare il successivo numero di versione basterà eseguire gitversion nella console e comparirà un payload JSON che racchiude una serie di informazioni e il prossimo numero di versione in diversi formati:

Un esempio di output di GitVersion

Nell’ottica di versionare i nostri pacchetti Nuget, la proprietà da dover prendere in considerazione per il prossimo valore da inserire nell’AssemblyInfo.cs è NugetVersionV2.

Nasce però un problema: nel precedente articolo, abbiamo utilizzato AssemblyVersion e AssemblyFileVersion per versionare i nostri pacchetti. Se il nostro numero di versione contiene dei metadati come ad esempio alpha, questi attributi non vanno più bene! Il problema nasce dal fatto che questi due attributi non accettano caratteri ma solo numeri. Per tal motivo occorre usare un attributo compatibile SemVer chiamato AssemblyInformationalVersion. In questo modo, dopo aver creato il pacchetto Nuget con i numeri generati da GitVersion, troviamo anche la parte di pre-release o di metadati compatibile con SemVer.

L’attributo AssemblyInformationVersion

Qual è il prossimo passo?

Dopo aver stabilito un processo ben consolidato e adottato GitFlow, SemVer e GitVersion, il passo successivo è quello di automatizzare l’intera procedura tramite l’uso di una pipeline di Continuous Deployment. Nel prossimo articolo, vedremo come possiamo farlo con Azure DevOps.

La nascita di GitFlow: https://nvie.com/posts/a-successful-git-branching-model/

Uso di GitFlow step-by-step: https://danielkummer.github.io/git-flow-cheatsheet/

Uso e configurazione di GitVersion: https://gitversion.readthedocs.io/en/latest/configuration/#configuration

Diversi workflow per git: https://www.atlassian.com/git/tutorials/comparing-workflows