
Gli standard coinvolti
L’automazione della release in un workflow GIT è resa possibile dall’adozione di alcuni standard:
Il versionamento semantico
Il Semantic Versioning (SemVer) stabilisce che ogni versione di un software deve essere nel formato:
MAJOR.MINOR.PATCH
Ciascuna voce è rappresentata da un numero con un significato preciso:
- MAJOR → cambia quando introduci modifiche incompatibili con le versioni precedenti.
- MINOR → cambia quando aggiungi funzionalità nuove ma compatibili.
- PATCH → cambia quando correggi bug senza aggiungere funzionalità e senza rompere nulla.
I commit convenzionali
Il sistema Conventional Commits definisce un formato standard per i messaggi di commit:
<type>([optional scope]): <description>
[optional body]
[optional footer(s)]
Elementi principali
- type (obbligatorio): Indica la natura del cambiamento. I più comuni:
- scope (opzionale, compreso tra parentesi rotonde); specifica l’area del progetto interessata (es.
api,ui,auth). - description (o subject): breve frase che spiega il cambiamento. Dovrebbe rispettare le seguenti regole (convenzione Angular):
- all’incirca 50 caratteri, descrive cosa è stato fatto.
- usare l’imperativo presente
- non scrivere in maiuscolo la prima lettera
- nessun punto (.) alla fine
- body (opzionale, separato da una riga): dettagli aggiuntivi, motivazioni, contesto. Spiega il “perché” e i dettagli tecnici, utile per chi legge la storia dei commit.
- footer (opzionale, separato da una riga): per note importanti, come:
- BREAKING CHANGE: (in maiuscolo, seguito da uno spazio) per modifiche incompatibili (quando la modifica causa una incompatibilità, alcuni utilizzano il type
feat!) - riferimenti a issue o ticket, con il seguente formato (convenzione Angular):
Un bug risolto con la release dovrebbe essere indicato in una riga separata e il prefisso “Closes“, in questo modo:Closes #234
Nel caso di risoluzione di più bug, questi possono essere elencati, separati da un virgola, in questo modo:Closes #123, #245, #992
- BREAKING CHANGE: (in maiuscolo, seguito da uno spazio) per modifiche incompatibili (quando la modifica causa una incompatibilità, alcuni utilizzano il type
Esempio di commit con titolo, corpo e due righe di footer
git commit -m "feat: aggiunge validazione lato client al form di login" \
-m "Implementata la validazione dei campi email e password. \
Questo riduce gli errori di input e migliora l'esperienza utente." \
-m "BREAKING CHANGE: modificata la struttura del payload di login" \
-m "Closes #123"
Il commit contiene i seguenti elementi strutturali, allo scopo di comunicare l’intento al consumatore della libreria:
fonte: https://www.conventionalcommits.org/it/v1.0.0/
fix: un commit di tipofixrisolve un errore nel codice (correlato alPATCHin un versionamento Semver).
feat: un commit di tipofeatintroduce una nuova funzionalità al codice (correlato alMINORin un versionamento Semver).
BREAKING CHANGE: un commit che contiene in un piè di paginaBREAKING CHANGE:, o aggiunge un!subito dopo il tipo/contesto, all’inizio delle sezioni opzionali corpo o piè di pagina, introduce una breaking API change (correlato alMAJORin un versionamento Semver). Una BREAKING CHANGE può essere parte di un commit di qualsiasi tipo.
Sono ammessi ulteriori tipi oltrefix:efeat:, per esempio commitlint-config-conventional (che si basa sulla convenzione Angular) raccomandabuild:,chore:,ci:,docs:,style:,refactor:,perf:,test:, ed altri.
Altri piè di pagina oltreBREAKING CHANGE: <description>possono essere utilizzati e seguono ua specifica simile a git trailer format.
Risorse online
Strumenti per il controllo della correttezza del messaggio di commit
E’ possibile controllare se il messaggio di commit rispetta gli standard prima che il commit venga eseguito. I tool coinvolti in questo meccanissmo sono Husky e Commitlint.
Husky
Husky è un tool per gestire Git hooks in modo semplice e configurabile. Ad esempio, permette di:
- Eseguire script prima di un commit (
pre-commit), come lanciare linting, formattazione, test veloci. - Eseguire script prima di un push (
pre-push), come far girare test completi o build. - Bloccare commit/push se gli script falliscono.
- Garantire che tutti nel team rispettino le stesse regole.
- Integrarsi con strumenti come ESLint, Prettier, Lint-staged, Commitlint.
Installazione di Husky
Per installare Husky:
npm install --save-dev husky
Attivare Husky nel progetto con il comando:
npx husky init
Questo comando inizializza Husky e crea automaticamente:
- la cartella
.husky/nella root del progetto - uno script
pre-commitdi esempio - lo script
prepare: "husky"nel filepackage.json - inserisce
hooksPath = .huskynel file.git/config, in questo modo istruisce GIT di non ricercre gli hook nella directory.git/hooks, bensì nella directory.husky.
Creare l’ hook di Husky per Commitlint:
echo 'npx --no -- commitlint --edit "$1"' > .husky/commit-msg
chmod +x .husky/commit-msg
Commitlint
Commitlint è un tool di validazione dei messaggi di commit. Controlla che ogni commit rispetti un formato predefinito (di solito quello dei Conventional Commits).
Installazione di Commitlint
Per installare Commitlint e le regole standard di validazione, posizionati nella root del tuo progetto Laravel e invia il comando:
npm install --save-dev @commitlint/{config-conventional,cli}
E’ possibile configurare Commitlint affinché usi valori personalizzati per Type e Scope. Di seguito i miei personali elenchi di Type e Scope e la loro implementazione nel file di configurazione di Commitlint.
Possibili Type
| Type | previsto da convenzione Angular? | previsto da config-conventional? | Previsto da me? | Prefisso branch | Descrizione |
|---|---|---|---|---|---|
| build(scope) | NO | aggiornamenti a Vite o a dipendenze che influenzano la build | |||
| chore(scope) | NO | chore/scope/ | attività di manutenzione, cleanup | ||
| ci(scope) | NO | file yaml | |||
| docs(scope) | NO | documentazione | |||
| feat(scope) | feat/scope/ | nuova funzionalità/adeguamento normativo | |||
| fix(scope) | fix/scope/ | correzione di errori non bloccanti | |||
| perf(scope) | perf/scope/ | quando la modifica rende il codice più veloce o più efficiente, senza cambiare cosa fa | |||
| refactor(scope) | ì | refactor/scope/ | si usa quando si modifica il codice senza cambiarne il comportamento esterno. | ||
| revert (*) | NO | n.a. | formato usato da git quando un commit annulla esplicitamente un commit precedente; il subject deve coincidere con l’header del reverted commit | ||
| style(scope) | NO | applicazione di regole estetiche del linter | |||
| test(scope) | NO | aggiunta o modifica di test |
git reset --soft HEAD~1 sposta HEAD indietro di un commit, non va tracciato con type=revertI Type omessi nel mio elenco (build, ci, docs, style, test) diventano possibili Scope di “chore”.
i commit di release di Shipmark, se abilitati, utilizzano il type chore(release).
Possibili Scope per ciascun Type
| Type | Scope | Descrizione |
|---|---|---|
| chore | config | configurazioni, environment, setup |
| build | (alias: deps, ovvero dependencies) descrivere nel corpo del messaggio la libreria composer/NPM modificata | |
| ci | file yaml di CI | |
| deploy | file yaml di deploy, scripts | |
| docs | documentazione | |
| style | (alias: lint) modifiche estetiche del codice, senza variazione di comportamento | |
| test | infrastruttura di test | |
| release | nei commit di release di shipmark, se abilitati | |
| feat, feat!, fix | ajax | gestione chiamate AJAX, API interne |
| auth | autenticazione e autorizzazione, gestione utenti | |
| bkp | logica di backup, restore | |
| dwh | analytics, elaborazione dati, metriche, datawarehousing, ETL, aggregazioni | |
| gdpr | cookie banner, gestione dei consensi, gestione dati personali, anonimizzazione, informativa privacy, retention | |
| i18n | Internazionalizzazione | |
| pages | pagine del sito | |
| rep | reporting: dashboard, esportazioni, grafici | |
| sec | Security | |
| trk | tracking: raccolta eventi, pixel, script | |
| ui | componenti grafici, layout, css, js, messaggi utente, assets | |
| perf | db | ottimizzazione query, creazione indici |
| asset | minifying, CDN | |
| image | .avif; .webp; sprite sheet | |
| html | uso di async, defer, lazy load | |
| http | compressione response http | |
| cache | cache di pagina; cache Redir (persist object cache) | |
| refactor | componente Laravel tra i seguenti: | |
| controllers | controller MVC | |
| models | Eloquent models | |
| views | Blade templates | |
| routes | web.php, api.php, routing in generale | |
| migrations | creazione e modifica di tabelle MySQL | |
| seeders | inserimento dati in DB | |
| middleware | filtri, autenticazione | |
| services | classi di servizio, logica applicativa | |
| jobs | queue jobs, processi asincroni | |
| commands | comandi Artisan personalizzati | |
| providers | service providers |
Configurazione di Commitlint
Crea un file chiamato commitlint.config.js nella root del progetto e inserisci il testo:
/* istruzioni per scope nullo: non dovrebbe mai essere empty, ma se lo è
* viene segnalato come errore di gravità 1 ovvero warning */
export default {
extends: ['@commitlint/config-conventional'],
rules: {
// Tipi consentiti
'type-enum': [
2,
'always',
['chore', 'feat', 'fix', 'perf', 'refactor', 'revert']
],
// Scope consentiti
'scope-enum': [
2,
'always',
['config', 'ci', 'deploy', 'deps', 'lint', 'test', 'release', 'ajax', 'auth', 'bkp', 'dwh', 'gdpr', 'i18n', 'page', 'rep', 'sec', 'trk', 'ui']
],
// Lo scope non può essere vuoto
'scope-empty': [1, 'never'],
// Lunghezza massima del titolo
'header-max-length': [2, 'always', 72],
// Obbligo di avere un messaggio nel body se il tipo è "feat" o "fix"
'body-empty': [1, 'never'],
// Il body deve iniziare con una riga vuota dopo il titolo
'body-leading-blank': [2, 'always'],
// Il footer deve iniziare con una riga vuota
'footer-leading-blank': [2, 'always'],
// Il tipo deve essere in minuscolo
'type-case': [2, 'always', 'lower-case'],
// Lo scope deve essere in minuscolo
'scope-case': [2, 'always', 'lower-case'],
// Il titolo non deve terminare con un punto
'header-full-stop': [2, 'never', '.'],
// Il messaggio deve iniziare con un tipo valido
'subject-case': [
2,
'never',
['sentence-case', 'start-case', 'pascal-case', 'upper-case']
],
// Il subject non deve essere vuoto
'subject-empty': [2, 'never']
}
};
Per controllare il comportamento di commitlint, posizionati sulla root del progetto e invia il comando:
echo "messaggio-da-verificare" | npx commitlint
Strumenti l’automazione della release
L’automazione della release in Git serve a eliminare attività manuali (tagging, version bump, changelog, build, pubblicazione) e garantire rilasci coerenti, ripetibili e senza errori. I tool più diffusi oggi sono Semantic‑release, Release‑it e GoReleaser, insieme ai workflow nativi di GitHub/GitLab che orchestrano il processo. Altri tool che rientrano pienamente nelal categoeia sono Release-please, Shipmark e Ship.js.
Ecco una tabella compatrativa degli strumenti:
| Esigenza | Tool ideale | Stile di automazione | Punti di forza |
|---|---|---|---|
| Automazione totale, zero interventi manuali, versioning basato sui commit | semantic‑release | Full‑auto (CI‑only) | Determina versione automaticamente, genera changelog, crea tag, pubblica pacchetti. Standard de facto nel mondo JS. |
| Controllo manuale + possibilità di automazione | release‑it | Manuale + CI | Molto flessibile, configurabile, ottimo per progetti che vogliono supervisione umana. |
| Workflow basato su PR, auditabile, ideale per monorepo | release‑please | PR‑based automation | Crea Release PR, aggiorna versioni e changelog, ottimo per GitHub e monorepo. |
| Rilasciare binari multipiattaforma (Go, CLI, DevOps) | GoReleaser | Full‑auto (CI) | Build multi‑OS, checksum, archivi, Homebrew/Scoop, GitHub Releases. Standard nel mondo Go. |
| Tool moderno, leggero, UX curata, zero dipendenze | Shipmark | CLI interattiva + CI | Semplice, elegante, veloce, ottimo per team che vogliono un flusso chiaro e pulito. |
| Automazione JS con PR di release, molto personalizzabile | Ship.js | PR‑based + npm | Ideale per progetti JS che vogliono un flusso guidato e configurabile. |
Personalmente ho scelto Shipmark, che, diversamente dagli altri strumenti, esegue il commit sul main in locale e poi esegue il push su origin, unitamente ad un tag che dà origine al processo di deploy del software.
Shipmark
Shipmark è uno strumento CLI (Command Line Interface) pensato per automatizzare il workflow di rilascio nelle applicazioni che usano Git.
Flusso da creazione del branch a fine CI con il merge su origin master
- Situazione iniziale: main branch stabile
- Si riceve una richiesta di nuova feature (ad esempio aggiungere la pagina di login)
- Creazione del feature branch (es feat/add-login)
- feature commit nel branch
- Push del feature branch (git push origin feat/add-login); posso sincronizzare GitHub actions su push (facoltativo)
- Apertura di una Pull Request (PR); posso sincronizzare GitHub actions su PR
- CI: Code review + test + approvazione
- merge su origin master (su GitHub, origin master ora contiene la nuova feature ed è un “release candidate”).
Flusso normale
Su GitHub:
- Creazione del branch di release (es. release/1.4.0)
- commit di release (automatico; bump versione, changelog, file aggiornati)
- PR di release automatica
- Merge della PR di release su origin master
- Creazione TAG (v1.4.0)
- CD pubblica la release (build + deploy)
In sviluppo:
- git pull origin main per allinearsi all’ultimo merge (PR di release)
Flusso con shipmark
- Lo sviluppatore esegue
shipmark release- git checkout main
- fetch del repo origin (git fetch origin)
- merge del branch origin main nel branch main locale (git pull origin/main)
- analisi commit (git describe –tags –abbrev=0)
- determina versione (git log <ultimo-tag>..HEAD)
- genera changelog
- aggiorna package.json
- crea commit di release (sul branch attuale) (git add . + git commit -m “chore(release): vX.Y.Z”)
- crea tag (git tag -a vX.Y.Z -m “Release vX.Y.Z”)
- mostra anteprima
- chiede conferma prima del push
- push automatico del branch main e del tag (git push origin main –follow-tag)
- CD rileva il TAG e pubblica la release (build + deploy)
Cosa distingue Shipmark dagli altri strumenti
Shipmark:
- non crea branch di release;
- non apre PR (pull request) di release;
- prepara tutto localmente;
- chiede conferma prima di pushare;
- fa un unico push contenente commit di release e tag di release
Installazione di shipmark
Se si vuole installare shipmark come dipendenza del progetto, posizionarsi sulla root del progetto ed inviare il comando:
npm install @grazulex/shipmark --save-dev
Oppure, se si vuole installare shipmark globalmente, aggiungere il paramentro -g il comando:
npm install -g @grazulex/shipmark --save-dev
Installando shipmark come dipendenza del progetto, per eseguirlo si dovrà sempre premettere npx. Ad esempio per controllare l’esito della installazione si doovrà usare il comando:
npx shipmark --version
Configurazione di shipmark
Avviare la configurazione interattiva tramite il comando:
npx shipmark init
Bisognerà rispondere alle seguenti domande:
? ShipMark Setup
──────────────────────────────────────────────────
✔ Changelog file: CHANGELOG.md
✔ Tag prefix: v
✔ Commit message template: chore(release): {version}
✔ Auto push after release? No
✔ Sign tags with GPG? No
✔ Use conventional commits? Yes
✔ Configuration saved to .shipmarkrc.yml
Al termine, verrà generato il file .shipmarkrc.yml, che io ho personalizzato così:
changelog:
file: CHANGELOG.md
types:
feat: Nuova funzionalità
fix: Correzione bug
chore: Manutenzione
perf: Performance Improvements
refactor: Miglioramento prestazioni
revert: Annullamento commit
includeHash: true
includeDate: true
includeAuthor: false
version:
files:
- package.json
tagPrefix: v
tagMessage: Release {version}
commitMessage: "chore(release): {version}"
commits:
conventional: true
allowCustomTypes: true
# incremento il numero di patch anche in caso
# di commit type = chore, perf o refactor
types:
feat:
release: minor
fix:
release: patch
chore:
release: patch
perf:
release: patch
refactor:
release: patch
git:
push: false
pushTags: false
signTags: false
signCommits: false
In particolare, notare che i Type chore, perf e refactor generano anch’essi una nuova versione (con incremento del valore patch).
Risorse online
- Laravel news: Automate Your Release Workflow with Shipmark

0 commenti