erplibre/script/git/commit_msg_lib.py
Mathieu Benoit f9edaa4e59 [ADD] git : un garde-fou commit-msg pour le sujet
Rien ne tenait la convention sur le sujet : le tag est respecté partout,
c'est la longueur qui glisse. Le hook refuse le mécanique et rien de plus
— tag absent, plus de 72 caractères, sujet ouvrant sur une citation ; dire
sur quoi porte le code reste un jugement qu'aucun hook ne rendra. Il compte
des caractères et non des octets, sans quoi un sujet français de 72
caractères tomberait sur ses accents. Le refus enseigne le repli vers des
mots-clés plutôt que la troncature, et nomme `--no-verify` : un garde-fou
qui refuse trop est désinstallé. Les tests pèsent donc autant les
acceptations, « Merge branch » ou fixup de rebase. Le lanceur balaie le
préfixe test_git_ : 32 tests jamais exécutés, le total va de 1021 à 1071.

--- EN ---

Nothing held the subject convention: the tag is respected everywhere, it
is the length that slips. The hook refuses the mechanical and nothing more
— no tag, over 72 characters, a subject opening on a quotation; whether it
says what the code is about stays a judgement no hook will make. It counts
characters, not bytes, or a 72-character French subject would fall on its
accents. The refusal teaches the fallback to keywords rather than
truncation, and names `--no-verify`: a guard rail that refuses too much
gets uninstalled. So the tests weigh the acceptances as much, a "Merge
branch" or a rebase fixup. The runner sweeps the test_git_ prefix: 32
tests never ran, and the total goes from 1021 to 1071.

Assisted-by: Claude Opus 5
(cherry picked from commit c9abf4d1b723ae8ff3762d39bfe1d6982400d12d)
2026-08-29 02:11:04 -04:00

71 lines
2.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# © 2026 TechnoLibre (http://www.technolibre.ca)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
"""Le sujet d'un commit tient-il la convention ?
La convention est dans `.claude/rules/04-code-conventions.md`, son mode
d'emploi dans `conf/template_claude_commands_commit.md`. Ce module en vérifie
la part MÉCANIQUE : le tag, la longueur, et le sujet qui s'ouvre sur une
citation. Le reste — « ce sujet dit-il sur quoi porte le code » — est un
jugement, et aucun hook ne le rendra.
Compté en CARACTÈRES et non en octets : « préchauffer » pèse 12 caractères et
14 octets, et une limite en octets refuserait des sujets français conformes.
"""
MAX = 72
TAGS = ("ADD", "FIX", "UPD", "IMP", "REF", "REM", "MOV", "I18N")
# Ce que git écrit lui-même, ou ce qu'un rebase consomme : hors convention.
GENERATED = ("Merge ", "Revert ", "fixup!", "squash!", "amend!")
# Un sujet qui s'ouvre sur une citation cite un écran. C'est une PREUVE, et une
# preuve va dans le corps — le sujet doit nommer la cause.
QUOTES = ("«", '"', "'", "`", "“", "‘")
def subject_of(message: str) -> str:
"""La première ligne utile : ni commentaire, ni ligne vide."""
for line in message.split("\n"):
stripped = line.strip()
if not stripped or stripped.startswith("#"):
continue
return stripped
return ""
def check(message: str) -> list:
"""Rend la liste des problèmes. Vide si le sujet passe."""
subject = subject_of(message)
if not subject or subject.startswith(GENERATED):
return []
problems = []
tag = None
for candidate in TAGS:
if subject.startswith(f"[{candidate}]"):
tag = candidate
break
if tag is None:
problems.append(
f"le sujet doit commencer par un tag : {', '.join('[%s]' % t for t in TAGS)}"
)
if len(subject) > MAX:
problems.append(
f"le sujet fait {len(subject)} caractères, {MAX} au plus.\n"
" Ne le tronquez pas : à cette longueur, écrivez des MOTS-CLÉS\n"
" qui résument plutôt qu'une phrase amputée. « proxmox : pmxcfs,\n"
" stockage, diagnostic » vaut mieux qu'une phrase coupée net."
)
rest = subject.split(":", 1)[1].strip() if ":" in subject else ""
if rest.startswith(QUOTES):
problems.append(
"le sujet s'ouvre sur une citation. Un message d'écran est une\n"
" preuve : elle va dans le corps. Le sujet nomme la cause."
)
return problems