Regex Conventional Commits message
A Conventional Commits message isn't just "type: description": the official spec itself publishes no regex, only a prose description - and introduces the "!" notation to flag a breaking change ("feat!: ..."), absent from the original Angular convention. The regex used by default by commitlint and semantic-release (inherited from Angular) doesn't handle that "!": a commit that's perfectly valid under spec v1.0.0 fails it. Here's a pattern covering that notation, compared against this widely-used default regex and two other attempts.
/^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\([\w-]+\))?!?: .+$/passes 21/21 cases
Comparison of existing patterns
| Source | pattern | Score on the corpus | ReDoS |
|---|---|---|---|
| conventional-changelog-angular, le parseur utilisé par défaut par commitlint ET semantic-release — aucune restriction de type, et surtout ne gère pas la notation « ! » de breaking change de la spec v1.0.0 | ^(\w*)(?:\((.*)\))?: (.*)$ | 15 / 21 | vulnerable ((): ): ): ): ): ): ): ): ): ): ): ): ): ): ): ): ): ): ): ):…) |
| Gist « Conventional Commit Regex » (49 étoiles, très utilisé) — liste de types figée aux 10 types Angular, rejette tout type personnalisé pourtant autorisé par la spec officielle | ^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test){1}(\([\w\-\.]+\))?(!)?: ([\w ])+([\s\S]*) | 21 / 21 | safe |
| regex101.com (-2 votes, explicitement rejetée par la communauté) — liste de types tronquée et impose un format d'identifiant de ticket façon JIRA absent de la spec officielle | ^(feat|chore|fix|security|wip):[ ]?[A-Z0-9]+-[0-9]+.{3,}$ | 13 / 21 | undetermined |
Implementation
const re = new RegExp("^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\\([\\w-]+\\))?!?: .+$", "");
re.test(input);Limits
- Valide seulement la première LIGNE (le « header ») du message, conformément à la spec : le corps et le pied de page (BREAKING CHANGE, références de tickets) suivent des règles de mise en forme séparées (ligne vide obligatoire avant le corps) qu'une regex sur une seule ligne ne peut pas vérifier.
- La liste de types utilisée ici (build/chore/ci/docs/feat/fix/perf/refactor/revert/style/test) vient de la convention Angular, largement adoptée mais non imposée par la spec officielle elle-même : une équipe peut légitimement définir ses propres types, que ce motif rejetterait à tort.
- N'impose aucune limite de longueur sur la description : une bonne pratique courante (50-72 caractères pour la première ligne) reste une convention d'équipe, pas une règle de la spec Conventional Commits.
- Le scope entre parenthèses doit être non vide dans ce motif (« docs(): » est rejeté) — un choix délibéré plus strict que plusieurs implémentations réelles comparées ici, qui l'acceptent sans le signaler comme cas limite.