Aller au contenu

Husky : messages de commit avec commitlint

commitlint vérifie que chaque message de commit respecte une convention. Associé au hook commit-msg de Husky, il refuse un message mal formé avant la création du commit. La convention la plus courante est Conventional Commits :

type(portée): description à l'impératif
corps facultatif
pied facultatif (BREAKING CHANGE: …, Closes #12)
Fenêtre de terminal
npm install -D @commitlint/cli @commitlint/config-conventional

commitlint.config.js :

export default {
extends: ['@commitlint/config-conventional'],
};

(avec "type": "module" dans package.json ; sinon module.exports = { extends: [...] } ou le nom commitlint.config.cjs.)

Fenêtre de terminal
echo 'npx --no -- commitlint --edit "$1"' > .husky/commit-msg

Git passe en paramètre le fichier contenant le message ($1) ; --no empêche npx de télécharger un paquet absent (et lance l’exécutable local). Tester :

Fenêtre de terminal
git commit --allow-empty -m "n'importe quoi"
⧗ input: n'importe quoi
✖ subject may not be empty [subject-empty]
✖ type may not be empty [type-empty]
✖ found 2 problems, 0 warnings

Le commit est refusé ; un message conforme passe :

Fenêtre de terminal
git commit --allow-empty -m "chore: tester commitlint"
Type Usage
feat Nouvelle fonctionnalité
fix Correction de bogue
docs Documentation
style Mise en forme (sans effet sur le code)
refactor Refactorisation
perf Amélioration de performance
test Ajout ou modification de tests
build Système de construction, dépendances
ci Intégration continue
chore Tâches diverses
revert Annulation d’un commit

Exemples valides :

feat(projects): ajouter la grille de cartes
fix(theme): corriger le flash au chargement
docs: mettre à jour l'introduction
feat(api)!: supprimer l'ancien point d'entrée
BREAKING CHANGE: la route /v1/clients n'existe plus

Un ! après le type (ou une ligne BREAKING CHANGE: en pied) signale un changement cassant.

export default {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [
2,
'always',
[
'feat',
'fix',
'docs',
'style',
'refactor',
'perf',
'test',
'build',
'ci',
'chore',
'revert',
],
],
'scope-enum': [
2,
'always',
['theme', 'projects', 'docs', 'legal', 'deploy', 'config'],
],
'subject-case': [
2,
'never',
['sentence-case', 'start-case', 'pascal-case', 'upper-case'],
],
'subject-full-stop': [2, 'never', '.'],
'header-max-length': [2, 'always', 100],
'body-max-line-length': [1, 'always', 100],
},
};

Chaque règle est [niveau, applicabilité, valeur] :

Niveau Effet
0 Désactivée
1 Avertissement (le commit passe)
2 Erreur (le commit est refusé)

Applicabilité : 'always' (la règle doit être respectée) ou 'never' (le contraire). La documentation de commitlint liste toutes les règles (type-case, scope-empty, body-leading-blank, footer-max-line-length…).

Messages en français, description à l’impératif, en minuscules, sans point final :

export default {
extends: ['@commitlint/config-conventional'],
rules: {
'subject-case': [2, 'always', 'lower-case'],
'subject-full-stop': [2, 'never', '.'],
'scope-enum': [
2,
'always',
['theme', 'projects', 'docs', 'legal', 'deploy', 'config'],
],
'header-max-length': [2, 'always', 100],
},
};

La règle subject-case ne contrôle que la casse de la première lettre ; elle n’impose pas la langue.

Fenêtre de terminal
echo "feat(docs): ajouter la rubrique husky" | npx commitlint
echo "mauvais message" | npx commitlint
npx commitlint --from HEAD~5 --to HEAD # les 5 derniers commits
npx commitlint --last # le dernier commit

--from et --to servent à vérifier tous les commits d’une branche en intégration continue (voir Intégration continue et équipes).

commitlint ignore par défaut les messages de fusion (Merge branch …), d’annulation automatique (Revert "…") et de fixup!/squash! : ils ne déclenchent pas d’erreur. Pour modifier : l’option defaultIgnores et ignores de la configuration.

Avec des messages normalisés, des outils produisent automatiquement un CHANGELOG.md et calculent le numéro de version (conventional-changelog, release-please, semantic-release). C’est l’un des principaux bénéfices d’une convention de messages appliquée par un hook.

Une convention de messages va de pair avec des commits atomiques : un commit, un changement logique, qui compile et passe les tests. Utiliser git add -p pour séparer des modifications mêlées.

Symptôme Piste
commitlint: command not found Dépendances non installées ; utiliser npx (hook)
Aucune erreur alors que le message est mauvais Hook commit-msg absent ou non exécutable, --no-verify, core.hooksPath
Please add rules to your commitlint.config.js Fichier de configuration absent ou introuvable (extension, type: module)
Cannot find module '@commitlint/config-conventional' Paquet non installé
subject may not be empty / type may not be empty Format type: description non respecté
Une portée valide est refusée scope-enum ne la liste pas
header must not be longer than 100 characters Raccourcir la première ligne, détailler dans le corps
Le message de fusion est refusé Utiliser --no-verify pour cette fusion, ou ajouter un motif à ignores

Ubuntu 24.04 et 26.04 : différences à connaître

Section intitulée « Ubuntu 24.04 et 26.04 : différences à connaître »

Aucune.