Aller au contenu principal
DevOps & Produit

SemVer (Semantic Versioning)

5 min de lecture
  • devops
  • méthodologie
  • versioning
SemVer : le contrat des versions

Quand vous voyez "lodash": "^4.17.21" dans votre package.json, le ^ signifie "mets à jour automatiquement les versions mineures et patch". Ça ne fonctionne que parce que lodash respecte un contrat : une mise à jour en 4.x ne cassera jamais votre code. Ce contrat, c'est le Semantic Versioning.

Le format : MAJOR.MINOR.PATCH

SemVer définit trois chiffres, chacun avec une signification précise :

2.4.1
│ │ │
│ │ └── PATCH : correction de bugs (rétrocompatible)
│ └──── MINOR : nouvelle fonctionnalité (rétrocompatible)
└────── MAJOR : breaking change (incompatible)

PATCH (2.4.1 → 2.4.2) : correction d'un bug. Le comportement existant ne change pas. Mise à jour sans risque.

MINOR (2.4.1 → 2.5.0) : ajout d'une fonctionnalité. Tout le code existant continue de fonctionner. Le PATCH revient à 0.

MAJOR (2.4.1 → 3.0.0) : changement incompatible. Du code qui fonctionnait avant peut casser. MINOR et PATCH reviennent à 0.

Pourquoi c'est crucial pour les dépendances

Les gestionnaires de paquets (npm, cargo, pip, bundler) s'appuient sur SemVer pour résoudre automatiquement les versions de vos dépendances :

{
  "dependencies": {
    "express": "^4.18.0",
    "lodash": "~4.17.0",
    "react": "18.2.0"
  }
}
NotationSignificationAutorise
^4.18.0Compatible avec 4.x4.18.1, 4.19.0, mais pas 5.0.0
~4.17.0Même mineur4.17.1, 4.17.21, mais pas 4.18.0
4.18.0Version exacteUniquement 4.18.0
>=4.0.0 <5.0.0Range expliciteTout entre 4.0.0 et 4.x.x

Sans SemVer, ces contraintes n'auraient aucun sens. Le ^ repose sur la promesse que MINOR et PATCH ne cassent rien. Si cette promesse n'est pas tenue, c'est toute la chaîne de dépendances qui devient imprévisible.

Les règles complètes

La spécification SemVer définit des règles précises :

  1. Une fois publiée, une version est immuable. Pas de modification d'une version existante — jamais.
  2. La version 0.x.x est spéciale : tout peut changer à tout moment. C'est la phase de développement initial. Pas de garantie de stabilité.
  3. La version 1.0.0 définit le premier contrat d'API publique stable.
  4. Les pre-release sont marquées par un suffixe : 2.0.0-alpha.1, 2.0.0-beta.3, 2.0.0-rc.1.
  5. Les metadata de build sont ajoutées après un + : 1.0.0+build.123.

Qu'est-ce qu'un breaking change ?

C'est la question la plus débattue. Un breaking change est toute modification qui peut casser du code existant qui utilisait l'API publique de manière documentée :

  • Supprimer une fonction publique
  • Changer la signature d'une fonction (paramètres obligatoires ajoutés)
  • Modifier la valeur de retour d'une fonction existante
  • Changer le comportement par défaut
  • Renommer un export public

Ce qui n'est pas un breaking change :

  • Ajouter une nouvelle fonction
  • Ajouter un paramètre optionnel avec une valeur par défaut
  • Corriger un bug (même si quelqu'un dépendait du bug)
  • Améliorer les performances sans changer l'API

Les pièges courants

Rester en 0.x indéfiniment. Certains projets restent en 0.x pendant des années pour éviter de passer en 1.0. Résultat : les utilisateurs ne savent jamais si une mise à jour est safe. Si votre API est utilisée en production, passez en 1.0.

Bumper MAJOR pour des changements mineurs. Passer de 3.0.0 à 4.0.0 parce que vous avez renommé une fonction interne crée de la fatigue de version. Réservez les bumps majeurs aux vrais breaking changes qui impactent les utilisateurs.

Ne pas respecter le contrat. Introduire un breaking change dans un bump PATCH ou MINOR, c'est casser la confiance. Un utilisateur qui met à jour en ^4.0.0 et dont le code casse ne reviendra peut-être pas.

Confondre MINOR et PATCH. Une nouvelle fonctionnalité est un bump MINOR, pas PATCH — même si elle est petite. Le PATCH est réservé aux corrections de bugs.

SemVer en pratique

Pour automatiser le versioning, des outils analysent vos commits et déterminent le type de bump :

# Conventional Commits
feat: add user profile page MINOR bump
fix: resolve login timeout PATCH bump
feat!: redesign auth API MAJOR bump (le ! indique un breaking change)
 
# Outils
# - semantic-release (JS)
# - python-semantic-release (Python)
# - cargo-release (Rust)

La convention Conventional Commits (feat:, fix:, chore:) combinée avec un outil de release automatisé élimine le débat humain : le type de commit détermine le bump.


SemVer est un contrat de confiance entre le mainteneur d'un paquet et ses utilisateurs. Il permet aux outils de dépendances de faire des choix de mise à jour automatiques et sûrs. Respecter ce contrat, c'est permettre à l'écosystème de fonctionner. Le casser, c'est transformer chaque npm update en loterie.