repowarden 4.7.0 → 4.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -36
- package/bin/commit +10 -4
- package/hooks/commit-msg +33 -0
- package/hooks/lib/common.sh +17 -0
- package/hooks/lib/i18n/en.sh +10 -2
- package/hooks/lib/i18n/fr.sh +10 -2
- package/hooks/lib/tickets.sh +2 -1
- package/hooks/lib/ui.sh +21 -1
- package/hooks/prepare-commit-msg +4 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -27,29 +27,47 @@
|
|
|
27
27
|
|
|
28
28
|
**Plus de 25 technologies** : Java (Maven, Gradle), JavaScript / TypeScript, Python, Go, Rust, PHP, Ruby, .NET, Dart / Flutter, Swift, Elixir, C / C++, Shell, Terraform, Packer, Ansible, Helm, Kubernetes, Docker, GitHub Actions — [détail](https://simdevwarden.github.io/repowarden/technologies/). Linux, macOS, Windows.
|
|
29
29
|
|
|
30
|
-
##
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
30
|
+
## Le cycle d'une modification
|
|
31
|
+
|
|
32
|
+
De l'idée à la production, chaque changement suit le même chemin. Tu n'agis qu'aux étapes **en gras** ; le reste est automatique, et chaque étape est vérifiée par la CI.
|
|
33
|
+
|
|
34
|
+
```mermaid
|
|
35
|
+
flowchart LR
|
|
36
|
+
A[Ticket] -->|validé| B[Conception]
|
|
37
|
+
B --> C[Branche du ticket]
|
|
38
|
+
C -->|commits + push| D[PR brouillon]
|
|
39
|
+
D -->|Ready for review| E{CI verte ?}
|
|
40
|
+
E -->|oui| F[develop]
|
|
41
|
+
E -->|non| C
|
|
42
|
+
F -->|vendredi, ou à la main| G[Demande de livraison]
|
|
43
|
+
G -->|Approve and deploy| H[main : release]
|
|
44
|
+
```
|
|
42
45
|
|
|
43
|
-
|
|
46
|
+
| # | Étape | Qui | Ce qui se passe | Statut du ticket |
|
|
47
|
+
|---|---|---|---|---|
|
|
48
|
+
| 1 | Ouvrir un ticket (issue) | toi | rien ne se code sans ticket | à valider |
|
|
49
|
+
| 2 | **Valider le ticket** | toi | étiquette `validé` (posée d'office si un mainteneur ouvre le ticket) | backlog |
|
|
50
|
+
| 3 | **Écrire la conception** | toi | commentaire « Conception retenue » sur le ticket : ce qui change, fichiers touchés, hors périmètre. Sans elle, la vérification `ticket` de la PR échoue | backlog |
|
|
51
|
+
| 4 | **Prendre le ticket** | toi | `repowarden ticket 12` : assigné, branche `fix/12-sujet` créée depuis `develop` | en cours |
|
|
52
|
+
| 5 | Coder et committer | toi | `git cc` ; les hooks vérifient message, branche, secrets, formatage, puis les tests au push | en cours |
|
|
53
|
+
| 6 | Premier push | auto | PR **brouillon** vers `develop` ouverte, titre et description tirés du ticket | en cours |
|
|
54
|
+
| 7 | **Sortir du brouillon** | toi | bouton *Ready for review* (`gh pr ready`) | en relecture |
|
|
55
|
+
| 8 | Vérifier et intégrer | auto | CI complète ; verte → **merge automatique** (squash) dans `develop`. Rouge → corriger et pousser, retour en 5 | préprod |
|
|
56
|
+
| 9 | Préversion | auto | chaque soir si `develop` a changé : `vX.Y.Z-next.N` (paquet `repowarden@next`), pour tester avant la prod | préprod |
|
|
57
|
+
| 10 | Demande de livraison | auto | le vendredi matin, ou à la main (*Actions → release → Run workflow*, ou étiquette `urgent` sur une PR `fix/…`) : instantané `livraison/vX.Y.Z` et sa PR vers `main` | préprod |
|
|
58
|
+
| 11 | **Approuver la livraison** | toi | sur la page du run : **Review deployments → Approve and deploy** (pas « Approve » sur la PR, qui est une simple relecture) | préprod |
|
|
59
|
+
| 12 | Publier | auto | la GitHub App merge vers `main` : tag `vX.Y.Z`, release, paquet npm, documentation | done, ticket fermé |
|
|
60
|
+
|
|
61
|
+
Seul `develop` entre dans `main`, et jamais sans l'approbation de l'étape 11. Une PR `develop` → `main` ouverte à la main est fermée automatiquement, avec la marche à suivre. Pas à pas, commandes et pièges : [où cliquer](https://simdevwarden.github.io/repowarden/validation/#ou-cliquer).
|
|
44
62
|
|
|
45
63
|
## Démarrage
|
|
46
64
|
|
|
47
65
|
### 1. Sur ton poste, en une minute (tous tes dépôts)
|
|
48
66
|
|
|
49
67
|
```bash
|
|
50
|
-
npm install -g repowarden
|
|
51
|
-
repowarden install --global
|
|
52
|
-
repowarden
|
|
68
|
+
npm install -g repowarden # 1. le paquet (yarn global add, pnpm add -g : idem)
|
|
69
|
+
repowarden install --global # 2. active les hooks : demande la langue, installe git cc
|
|
70
|
+
repowarden # 3. vérifie : état du poste et étape suivante
|
|
53
71
|
```
|
|
54
72
|
|
|
55
73
|
L'étape 2 est indispensable : par sécurité, le paquet n'exécute rien à l'installation (aucun script `postinstall`, que npm 12 bloque d'ailleurs). Ensuite, dans **n'importe quel dépôt**, les hooks s'appliquent dès le prochain commit. Rien n'est ajouté aux projets ni à leur `package.json`.
|
|
@@ -59,7 +77,7 @@ cd mon-projet
|
|
|
59
77
|
git switch -c feat/panier # nom de branche vérifié
|
|
60
78
|
git add . && git cc # assistant : type, scope, description… puis commit
|
|
61
79
|
git push -u origin feat/panier # tests des projets touchés avant l'envoi
|
|
62
|
-
repowarden code-mort
|
|
80
|
+
repowarden code-mort # nouveau code mort de ta branche
|
|
63
81
|
```
|
|
64
82
|
|
|
65
83
|
| Action | Commande |
|
|
@@ -67,25 +85,17 @@ repowarden code-mort # nouveau code mort de ta branche
|
|
|
67
85
|
| État du poste, étape suivante | `repowarden` (ou `repowarden statut`) |
|
|
68
86
|
| Toutes les commandes | `repowarden --help` (`cc`, `code-mort`, `proteger`, `npm-publication`…) |
|
|
69
87
|
| Mettre à jour | `npm update -g repowarden` (les hooks suivent) |
|
|
88
|
+
| Tester la prochaine version | `npm install -g repowarden@next` (retour : `repowarden@latest`) ; en CI : `uses: simdevWarden/repowarden@develop` |
|
|
70
89
|
| Désinstaller | `repowarden uninstall --global`, **puis** `npm uninstall -g repowarden` (dans cet ordre : npm n'exécute rien à la désinstallation, les hooks resteraient branchés sur un dossier supprimé) |
|
|
71
90
|
|
|
72
91
|
Sans Node : `git clone https://github.com/simdevWarden/repowarden.git ~/repowarden && ~/repowarden/install.sh --global` (mise à jour : `git -C ~/repowarden pull`).
|
|
73
92
|
|
|
74
|
-
|
|
93
|
+
**Nouvelle machine** : ces trois commandes suffisent. Les règles du dépôt, l'environnement de livraison, la GitHub App, ses secrets et la publication npm vivent sur GitHub et npm : rien à reconfigurer. La clé privée de l'App ne doit jamais se trouver sur un poste.
|
|
75
94
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
repowarden app init
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
1. Ouvre la page locale → clique "Create GitHub App" sur GitHub
|
|
83
|
-
2. Clique "Install" sur ton repo/org
|
|
84
|
-
3. Les secrets `REPOWARDEN_APP_CLIENT_ID` / `REPOWARDEN_APP_KEY` sont configurés automatiquement
|
|
85
|
-
|
|
86
|
-
Sans cette étape, le `GITHUB_TOKEN` des Actions est utilisé : **ce qu'il fait ne déclenche pas les autres workflows** (merge auto, tickets, préversions).
|
|
87
|
-
|
|
88
|
-
**Tester la prochaine version** (avant sa sortie en production) : `npm install -g repowarden@next`, ou `uses: simdevWarden/repowarden@develop` en CI. Retour à la version stable : `npm install -g repowarden@latest`. Les problèmes se signalent en [issue](https://github.com/simdevWarden/repowarden/issues).
|
|
95
|
+
> [!NOTE]
|
|
96
|
+
> **GitHub CLI (`gh`) : facultatif.**
|
|
97
|
+
> Sans `gh` : tous les hooks (commits, branches, secrets, formatage, tests), `git cc`, `repowarden code-mort`, `repowarden statut`, et la CI (GitHub ou GitLab), qui n'utilise jamais le `gh` du poste.
|
|
98
|
+
> Avec `gh` connecté (`gh auth login`), en plus : les tickets (`repowarden ticket`, `tickets`, branches de tes tickets créées en local) et la gestion du dépôt (`proteger`, `app init`, `npm-publication`, `pr-*`, `run-*`). Utile au mainteneur du dépôt GitHub ; chaque commande le signale s'il manque.
|
|
89
99
|
|
|
90
100
|
### 2. Dans un projet d'équipe : les mêmes règles pour tous
|
|
91
101
|
|
|
@@ -107,22 +117,44 @@ L'essentiel des deux fichiers :
|
|
|
107
117
|
```ini
|
|
108
118
|
# .repowarden.conf : un poste en retard est prévenu, avec la commande de mise à jour
|
|
109
119
|
[repowarden]
|
|
110
|
-
version =
|
|
120
|
+
version = 4
|
|
111
121
|
```
|
|
112
122
|
|
|
113
|
-
Puis rendre la CI obligatoire pour merger
|
|
123
|
+
Puis rendre la CI obligatoire pour merger (`gh` connecté, admin du dépôt) :
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
repowarden proteger --checks "repowarden,tests" # toutes les vérifications exigées, séparées par des virgules
|
|
127
|
+
repowarden proteger --checks "repowarden,tests" --verifier # plus tard : règles en ligne à jour ? (lecture seule)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Toujours passer **toutes** les vérifications à `--checks` : sans lui, seule `repowarden` reste exigée. Avec un flux `develop` → `main`, `proteger` crée aussi l'étiquette `urgent` et exige l'approbation de chaque livraison : utiliser le [modèle de release du flux develop](https://simdevwarden.github.io/repowarden/releases/), sinon `main` attendrait un déploiement que rien ne crée (`proteger` le signale).
|
|
114
131
|
|
|
115
132
|
Exemple complet : [repowarden-demo](https://github.com/simdevWarden/repowarden-demo) · Releases automatiques : [documentation](https://simdevwarden.github.io/repowarden/releases/).
|
|
116
133
|
|
|
117
|
-
### 3.
|
|
134
|
+
### 3. GitHub App pour l'automatisation (merge auto, tickets, releases)
|
|
135
|
+
|
|
136
|
+
Pour que les workflows déclenchent les autres workflows (merge auto, tickets, releases), il faut une GitHub App au lieu du `GITHUB_TOKEN` :
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
repowarden app init
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
1. Ouvre la page locale → clique « Create GitHub App » sur GitHub
|
|
143
|
+
2. Clique « Install » sur ton dépôt ou ton organisation
|
|
144
|
+
3. Les secrets `REPOWARDEN_APP_CLIENT_ID` / `REPOWARDEN_APP_KEY` sont configurés automatiquement
|
|
145
|
+
|
|
146
|
+
Sans cette étape, le `GITHUB_TOKEN` des Actions est utilisé : **ce qu'il fait ne déclenche pas les autres workflows** (merge auto, tickets, préversions).
|
|
147
|
+
|
|
148
|
+
### 4. Contribuer à repowarden
|
|
118
149
|
|
|
119
150
|
```bash
|
|
120
151
|
git clone https://github.com/simdevWarden/repowarden.git && cd repowarden
|
|
121
152
|
./install.sh # repowarden se vérifie lui-même (hooks de ce dépôt)
|
|
122
|
-
|
|
153
|
+
brew install shellcheck bats-core actionlint gitleaks # outils des vérifications (ou équivalent Linux)
|
|
154
|
+
bats test/ # tests, aussi lancés au push
|
|
123
155
|
```
|
|
124
156
|
|
|
125
|
-
Les PR visent `develop` ; `main` ne reçoit que les livraisons, qui déclenchent les releases.
|
|
157
|
+
Les PR visent `develop` ; `main` ne reçoit que les livraisons, qui déclenchent les releases. Tout part d'un ticket : voir [AGENTS.md](AGENTS.md) et [CONTRIBUTING.md](CONTRIBUTING.md). Les problèmes se signalent en [issue](https://github.com/simdevWarden/repowarden/issues).
|
|
126
158
|
|
|
127
159
|
**Dans VS Code** : l'extension [repowarden-vscode](https://github.com/simdevWarden/repowarden-vscode) guide la rédaction des commits, signale une branche mal nommée et des hooks inactifs. En attendant sa publication sur le Marketplace : `.vsix` dans ses [releases](https://github.com/simdevWarden/repowarden-vscode/releases), puis `code --install-extension repowarden-X.Y.Z.vsix`.
|
|
128
160
|
|
package/bin/commit
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# sans cela, la ligne suivante serait lue
|
|
7
7
|
# comme une nouvelle réponse)
|
|
8
8
|
# git cc -m "description" [--type T] [--scope S] [--breaking NOTE]
|
|
9
|
-
# [--body TEXTE] [--refs "
|
|
9
|
+
# [--body TEXTE] [--refs "Ticket : #12"]
|
|
10
10
|
# sans question (scripts, agents) : mêmes
|
|
11
11
|
# contrôles, toute réponse refusée arrête
|
|
12
12
|
# tout ; type et scope déduits de la
|
|
@@ -173,14 +173,19 @@ while :; do
|
|
|
173
173
|
type="$answer"
|
|
174
174
|
break
|
|
175
175
|
fi
|
|
176
|
-
|
|
176
|
+
type_proche_r "$(printf '%s' "$answer" | tr '[:upper:]' '[:lower:]')"
|
|
177
|
+
if [ -n "$REPLY" ]; then
|
|
178
|
+
t cc.type_invalid_suggest "$answer" "$REPLY" "${#TYPES[@]}"
|
|
179
|
+
else
|
|
180
|
+
t cc.type_invalid "$answer" "${#TYPES[@]}"
|
|
181
|
+
fi
|
|
177
182
|
refuse "$REPLY"
|
|
178
183
|
done
|
|
179
184
|
|
|
180
185
|
# 2. Scope (optionnel)
|
|
181
186
|
t cc.step2
|
|
182
187
|
etape 2 "$REPLY"
|
|
183
|
-
t cc.scope_hint
|
|
188
|
+
if [ -n "$default_scope" ]; then t cc.scope_hint_default "$default_scope"; else t cc.scope_hint; fi
|
|
184
189
|
hint "$REPLY"
|
|
185
190
|
while :; do
|
|
186
191
|
if [ -n "$default_scope" ]; then
|
|
@@ -352,7 +357,8 @@ fi
|
|
|
352
357
|
if [ -n "$ticket" ]; then
|
|
353
358
|
t cc.refs_prompt_ticket "$ticket"
|
|
354
359
|
else
|
|
355
|
-
|
|
360
|
+
cfg_r integrationBranch ""
|
|
361
|
+
if [ -n "$REPLY" ]; then t cc.refs_prompt "Ticket : #12"; else t cc.refs_prompt "$FORGE_REFS"; fi
|
|
356
362
|
fi
|
|
357
363
|
ANSWER="$OPT_REFS"
|
|
358
364
|
ask "$REPLY"
|
package/hooks/commit-msg
CHANGED
|
@@ -39,6 +39,30 @@ if [[ "$SUBJECT" =~ ^(Merge|Revert|fixup!|squash!) ]]; then
|
|
|
39
39
|
exit 0
|
|
40
40
|
fi
|
|
41
41
|
|
|
42
|
+
# En-tête tenté mais refusé : type inconnu (ou en majuscules), description vide
|
|
43
|
+
if ! [[ "$SUBJECT" =~ $CC_PATTERN ]] &&
|
|
44
|
+
[[ "$SUBJECT" =~ ^([A-Za-z]+)(\([^\)]*\))?(!?):[[:space:]]*(.*)$ ]]; then
|
|
45
|
+
typ="${BASH_REMATCH[1]}" portee="${BASH_REMATCH[2]}" bang="${BASH_REMATCH[3]}" desc="${BASH_REMATCH[4]}"
|
|
46
|
+
typ_min="$(printf '%s' "$typ" | tr '[:upper:]' '[:lower:]')"
|
|
47
|
+
propose="$typ_min"
|
|
48
|
+
[[ "$typ_min" =~ ^($CC_TYPES)$ ]] || { type_proche_r "$typ_min"; propose="$REPLY"; }
|
|
49
|
+
if [ -z "$desc" ]; then
|
|
50
|
+
err_t hook.commit_msg.desc_empty "${propose:-$typ}$portee$bang:"
|
|
51
|
+
echo_t hook.commit_msg.kept >&2
|
|
52
|
+
exit 1
|
|
53
|
+
fi
|
|
54
|
+
if [ "$propose" != "$typ" ]; then
|
|
55
|
+
if [ -n "$propose" ]; then
|
|
56
|
+
err_t hook.commit_msg.type_unknown "$typ" "$propose$portee$bang: $desc"
|
|
57
|
+
else
|
|
58
|
+
err_t hook.commit_msg.type_none "$typ"
|
|
59
|
+
types_help
|
|
60
|
+
fi
|
|
61
|
+
echo_t hook.commit_msg.kept >&2
|
|
62
|
+
exit 1
|
|
63
|
+
fi
|
|
64
|
+
fi
|
|
65
|
+
|
|
42
66
|
if ! [[ "$SUBJECT" =~ $CC_PATTERN ]]; then
|
|
43
67
|
if [ "${REPOWARDEN_LANG:-}" = en ]; then
|
|
44
68
|
cat >&2 <<EOF
|
|
@@ -80,6 +104,15 @@ EOF
|
|
|
80
104
|
exit 1
|
|
81
105
|
fi
|
|
82
106
|
|
|
107
|
+
# Point final retiré, comme dans git cc (pas des points de suspension) ; seule
|
|
108
|
+
# la première ligne est réécrite, le corps reste intact
|
|
109
|
+
if [[ "$SUBJECT" == *. && "$SUBJECT" != *.. ]]; then
|
|
110
|
+
SUBJECT="${SUBJECT%.}"
|
|
111
|
+
contenu="$(awk -v s="$SUBJECT" '!fait && !/^#/ { print s; fait = 1; next } { print }' "$MSG_FILE")"
|
|
112
|
+
printf '%s\n' "$contenu" >"$MSG_FILE"
|
|
113
|
+
info_t hook.commit_msg.dot >&2
|
|
114
|
+
fi
|
|
115
|
+
|
|
83
116
|
authored_length "$SUBJECT"
|
|
84
117
|
if [ "$REPLY" -gt 72 ]; then
|
|
85
118
|
err_t hook.commit_msg.1 "$REPLY" >&2
|
package/hooks/lib/common.sh
CHANGED
|
@@ -84,6 +84,23 @@ cfg() {
|
|
|
84
84
|
CC_TYPES="feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert"
|
|
85
85
|
CC_PATTERN="^($CC_TYPES)(\([a-z0-9._-]+\))?!?: .+"
|
|
86
86
|
|
|
87
|
+
# Type le plus proche d'un type inconnu : alias courants, puis préfixe commun
|
|
88
|
+
# (doc → docs, feature → feat, Feat → feat) ; vide si aucun
|
|
89
|
+
type_proche_r() {
|
|
90
|
+
local t="$1" c
|
|
91
|
+
case "$t" in
|
|
92
|
+
feature | features) REPLY="feat"; return ;;
|
|
93
|
+
doc | documentation) REPLY="docs"; return ;;
|
|
94
|
+
fixe | fixed | fixes | bugfix | hotfix) REPLY="fix"; return ;;
|
|
95
|
+
tests) REPLY="test"; return ;;
|
|
96
|
+
refacto | refactoring) REPLY="refactor"; return ;;
|
|
97
|
+
esac
|
|
98
|
+
REPLY=""
|
|
99
|
+
for c in ${CC_TYPES//|/ }; do
|
|
100
|
+
if [[ "$c" == "$t"* || "$t" == "$c"* ]]; then REPLY="$c"; return; fi
|
|
101
|
+
done
|
|
102
|
+
}
|
|
103
|
+
|
|
87
104
|
# REPLY = longueur de la première ligne écrite par l'auteur : le suffixe
|
|
88
105
|
# « (#123) » ajouté par GitHub lors d'un merge squash n'est pas compté.
|
|
89
106
|
authored_length() {
|
package/hooks/lib/i18n/en.sh
CHANGED
|
@@ -25,8 +25,10 @@ _msg_en() {
|
|
|
25
25
|
cc.option_value) _M="Option %s expects a value." ;;
|
|
26
26
|
cc.batch_message_required) _M="Without questions, the description is required: git cc -m \"<description>\" [--type T] [--scope S] [--body …] [--refs …] [--breaking …]." ;;
|
|
27
27
|
cc.type_invalid) _M="\"%s\": pick a number (1 to %s) or a name from the list." ;;
|
|
28
|
+
cc.type_invalid_suggest) _M="\"%s\": unknown type. Did you mean \"%s\"? Number (1 to %s) or a name from the list." ;;
|
|
28
29
|
cc.step2) _M="Scope (optional)" ;;
|
|
29
30
|
cc.scope_hint) _M="Part of the project affected, e.g. api, auth, chart; Enter for none." ;;
|
|
31
|
+
cc.scope_hint_default) _M="Part of the project, e.g. api, auth, chart; Enter keeps \"%s\", \"-\" for none." ;;
|
|
30
32
|
cc.scope_prompt_default) _M="Scope (\"-\" for none) [%s]: " ;;
|
|
31
33
|
cc.scope_prompt) _M="Scope: " ;;
|
|
32
34
|
cc.scope_fixed) _M="Scope: lowercase letters, digits, . _ - only. Suggested: %s (Enter to accept)." ;;
|
|
@@ -40,7 +42,7 @@ _msg_en() {
|
|
|
40
42
|
cc.breaking_note_prompt) _M="What changes: " ;;
|
|
41
43
|
cc.breaking_note_invalid) _M="Describe the change (at least 10 characters); otherwise answer no to the previous question." ;;
|
|
42
44
|
cc.step4) _M="Description" ;;
|
|
43
|
-
cc.desc_hint) _M="Imperative mood, no
|
|
45
|
+
cc.desc_hint) _M="Imperative mood, no final period, lowercase start except acronyms or proper nouns; %s characters max." ;;
|
|
44
46
|
cc.desc_required) _M="The description is required." ;;
|
|
45
47
|
cc.header_too_long) _M="Header too long: %s characters (72 max). Shorten the description." ;;
|
|
46
48
|
cc.step5) _M="Details (optional)" ;;
|
|
@@ -48,7 +50,8 @@ _msg_en() {
|
|
|
48
50
|
cc.refs_prompt_ticket) _M="References (\"-\" for none) [%s]: " ;;
|
|
49
51
|
cc.refs_prompt) _M="References (e.g. %s; Enter for none): " ;;
|
|
50
52
|
tk.cli.no_ticket) _M="Branch %s has no ticket: this work will not be linked to any ticket (not blocking)." ;;
|
|
51
|
-
tk.cli.propose) _M="Start it from a ticket: repowarden ticket nouveau \"<title>\"
|
|
53
|
+
tk.cli.propose) _M="Start it from a ticket: repowarden ticket nouveau \"<title>\"." ;;
|
|
54
|
+
tk.cli.propose_cc) _M="Start it from a ticket: repowarden ticket nouveau \"<title>\" (or answer yes in git cc)." ;;
|
|
52
55
|
tk.cli.silence) _M="Project without ticket tracking? git config repowarden.skip tickets to stop seeing this." ;;
|
|
53
56
|
tk.cli.fetch) _M="Branch of ticket #%s…" ;;
|
|
54
57
|
tk.cli.switched) _M="On branch %s (ticket #%s)." ;;
|
|
@@ -111,6 +114,11 @@ _msg_en() {
|
|
|
111
114
|
hook.pre_commit.6) _M="gitleaks not installed, secret detection skipped (install: %s)." ;;
|
|
112
115
|
hook.pre_commit.7) _M="Pre-commit OK" ;;
|
|
113
116
|
hook.commit_msg.1) _M="First line too long (%s > 72 characters)." ;;
|
|
117
|
+
hook.commit_msg.type_unknown) _M="Unknown type \"%s\". Did you mean: %s" ;;
|
|
118
|
+
hook.commit_msg.type_none) _M="Unknown type \"%s\". Possible types:" ;;
|
|
119
|
+
hook.commit_msg.desc_empty) _M="Missing description after \"%s\": describe the change in the imperative mood." ;;
|
|
120
|
+
hook.commit_msg.kept) _M=" Your message is not lost: git commit -e -F .git/COMMIT_EDITMSG" ;;
|
|
121
|
+
hook.commit_msg.dot) _M="Final period removed from the description (same rule as git cc)." ;;
|
|
114
122
|
hook.pre_push.1) _M="Push refused: branch name does not follow the convention." ;;
|
|
115
123
|
hook.pre_push.2) _M="Direct push to '%s' refused: it only changes through pull requests." ;;
|
|
116
124
|
hook.pre_push.3) _M=" Create a branch: git switch -c feat/my-feature, then open a PR." ;;
|
package/hooks/lib/i18n/fr.sh
CHANGED
|
@@ -25,8 +25,10 @@ _msg_fr() {
|
|
|
25
25
|
cc.option_value) _M="L'option %s attend une valeur." ;;
|
|
26
26
|
cc.batch_message_required) _M="Sans question, la description est obligatoire : git cc -m \"<description>\" [--type T] [--scope S] [--body …] [--refs …] [--breaking …]." ;;
|
|
27
27
|
cc.type_invalid) _M="« %s » : choisis un numéro (1 à %s) ou un nom de la liste." ;;
|
|
28
|
+
cc.type_invalid_suggest) _M="« %s » : type inconnu. Voulais-tu « %s » ? Numéro (1 à %s) ou nom de la liste." ;;
|
|
28
29
|
cc.step2) _M="Scope (optionnel)" ;;
|
|
29
30
|
cc.scope_hint) _M="Partie du projet concernée, ex. api, auth, chart ; Entrée pour aucun." ;;
|
|
31
|
+
cc.scope_hint_default) _M="Partie du projet concernée, ex. api, auth, chart ; Entrée garde « %s », « - » pour aucun." ;;
|
|
30
32
|
cc.scope_prompt_default) _M="Scope (« - » pour aucun) [%s] : " ;;
|
|
31
33
|
cc.scope_prompt) _M="Scope : " ;;
|
|
32
34
|
cc.scope_fixed) _M="Scope : minuscules, chiffres, . _ - uniquement. Proposé : %s (Entrée pour l'accepter)." ;;
|
|
@@ -40,7 +42,7 @@ _msg_fr() {
|
|
|
40
42
|
cc.breaking_note_prompt) _M="Ce qui change : " ;;
|
|
41
43
|
cc.breaking_note_invalid) _M="Décris le changement (10 caractères au moins) ; sinon, réponds non à la question précédente." ;;
|
|
42
44
|
cc.step4) _M="Description" ;;
|
|
43
|
-
cc.desc_hint) _M="À l'impératif, sans
|
|
45
|
+
cc.desc_hint) _M="À l'impératif, sans point final, minuscule initiale sauf sigle ou nom propre ; %s caractères au plus." ;;
|
|
44
46
|
cc.desc_required) _M="La description est obligatoire." ;;
|
|
45
47
|
cc.header_too_long) _M="En-tête trop long : %s caractères (72 max). Raccourcis la description." ;;
|
|
46
48
|
cc.step5) _M="Détails (optionnels)" ;;
|
|
@@ -48,7 +50,8 @@ _msg_fr() {
|
|
|
48
50
|
cc.refs_prompt_ticket) _M="Références (« - » pour aucune) [%s] : " ;;
|
|
49
51
|
cc.refs_prompt) _M="Références (ex. %s ; Entrée pour aucune) : " ;;
|
|
50
52
|
tk.cli.no_ticket) _M="Branche %s sans ticket : ce travail ne sera relié à aucun ticket (non bloquant)." ;;
|
|
51
|
-
tk.cli.propose) _M="
|
|
53
|
+
tk.cli.propose) _M="Partir d'un ticket : repowarden ticket nouveau \"<titre>\"." ;;
|
|
54
|
+
tk.cli.propose_cc) _M="Partir d'un ticket : repowarden ticket nouveau \"<titre>\" (ou réponds oui à git cc)." ;;
|
|
52
55
|
tk.cli.silence) _M="Projet sans suivi de tickets ? git config repowarden.skip tickets pour ne plus le voir." ;;
|
|
53
56
|
tk.cli.fetch) _M="Branche du ticket #%s…" ;;
|
|
54
57
|
tk.cli.switched) _M="Sur la branche %s (ticket #%s)." ;;
|
|
@@ -109,6 +112,11 @@ _msg_fr() {
|
|
|
109
112
|
hook.pre_commit.6) _M="gitleaks absent, détection de secrets ignorée (installation : %s)." ;;
|
|
110
113
|
hook.pre_commit.7) _M="Pre-commit OK" ;;
|
|
111
114
|
hook.commit_msg.1) _M="Première ligne trop longue (%s > 72 caractères)." ;;
|
|
115
|
+
hook.commit_msg.type_unknown) _M="Type « %s » inconnu. Voulais-tu : %s" ;;
|
|
116
|
+
hook.commit_msg.type_none) _M="Type « %s » inconnu. Types possibles :" ;;
|
|
117
|
+
hook.commit_msg.desc_empty) _M="Description manquante après « %s » : décris le changement à l'impératif." ;;
|
|
118
|
+
hook.commit_msg.kept) _M=" Ton message n'est pas perdu : git commit -e -F .git/COMMIT_EDITMSG" ;;
|
|
119
|
+
hook.commit_msg.dot) _M="Point final retiré de la description (même règle que git cc)." ;;
|
|
112
120
|
hook.pre_push.1) _M="Push refusé : nom de branche non conforme." ;;
|
|
113
121
|
hook.pre_push.2) _M="Push direct refusé sur '%s' : elle n'évolue que par Pull Request." ;;
|
|
114
122
|
hook.pre_push.3) _M=" Crée une branche : git switch -c feat/ma-feature, puis ouvre une PR." ;;
|
package/hooks/lib/tickets.sh
CHANGED
|
@@ -168,7 +168,8 @@ ticket_hint() {
|
|
|
168
168
|
[ -z "$REPLY" ] || return 0
|
|
169
169
|
attention_t tk.cli.no_ticket "$branch"
|
|
170
170
|
if tickets_managed && has gh; then
|
|
171
|
-
|
|
171
|
+
# git cc ne propose de créer le ticket qu'avec ticketAutoCreate
|
|
172
|
+
if ticket_auto_create; then dim_t tk.cli.propose_cc; else dim_t tk.cli.propose; fi
|
|
172
173
|
else
|
|
173
174
|
dim_t tk.cli.silence
|
|
174
175
|
fi
|
package/hooks/lib/ui.sh
CHANGED
|
@@ -31,7 +31,27 @@ repowarden_version_r() {
|
|
|
31
31
|
local tag=""
|
|
32
32
|
REPLY="$(sed -n 's/^ "version": *"\([^"]*\)".*/\1/p' "$1/package.json" 2>/dev/null | sed -n 1p)"
|
|
33
33
|
if [ -e "$1/.git" ]; then
|
|
34
|
-
|
|
34
|
+
# Sous-shell sans les variables que git exporte aux hooks (worktree) :
|
|
35
|
+
# elles l'emportent sur -C, ce seraient les tags du projet. Tag le plus
|
|
36
|
+
# proche de HEAD (git describe), remplacé par un tag de release dont le
|
|
37
|
+
# commit mergé est au moins aussi proche : la release est taguée sur le
|
|
38
|
+
# merge de la livraison dans main, invisible depuis develop pour
|
|
39
|
+
# describe ; à égalité, la version stable l'emporte sur la préversion
|
|
40
|
+
tag="$(
|
|
41
|
+
unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE GIT_COMMON_DIR
|
|
42
|
+
best="$(git -C "$1" describe --tags --abbrev=0 --match 'v[0-9]*' 2>/dev/null || true)"
|
|
43
|
+
dist=""
|
|
44
|
+
[ -z "$best" ] || dist="$(git -C "$1" rev-list --count "$best..HEAD")"
|
|
45
|
+
while IFS= read -r t; do
|
|
46
|
+
git -C "$1" merge-base --is-ancestor "$t^2" HEAD 2>/dev/null || continue
|
|
47
|
+
d="$(git -C "$1" rev-list --count "$t^2..HEAD")"
|
|
48
|
+
if [ -z "$best" ] || [ "$d" -lt "$dist" ] ||
|
|
49
|
+
{ [ "$d" -eq "$dist" ] && [[ "$t" != *-* && "$best" == *-* ]]; }; then
|
|
50
|
+
best="$t" dist="$d"
|
|
51
|
+
fi
|
|
52
|
+
done < <(git -C "$1" tag --no-merged HEAD --list 'v[0-9]*' 2>/dev/null)
|
|
53
|
+
echo "$best"
|
|
54
|
+
)"
|
|
35
55
|
[ -z "$tag" ] || REPLY="${tag#v}"
|
|
36
56
|
fi
|
|
37
57
|
}
|
package/hooks/prepare-commit-msg
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# Hook prepare-commit-msg : déduit le préfixe Conventional Commits du nom de branche.
|
|
3
3
|
# branche feat/bean : git commit → éditeur prérempli avec "feat(bean): "
|
|
4
4
|
# git commit -m "ajoute X" → "feat(bean): ajoute X"
|
|
5
|
-
# Un message déjà conforme n'est pas modifié.
|
|
5
|
+
# Un message déjà conforme, ou qui a la forme d'un en-tête, n'est pas modifié.
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
|
|
8
8
|
source "$(dirname "$0")/lib/common.sh"
|
|
@@ -36,6 +36,9 @@ fi
|
|
|
36
36
|
|
|
37
37
|
SUBJECT="$(grep -v '^#' "$MSG_FILE" | sed -n 1p || true)"
|
|
38
38
|
[[ "$SUBJECT" =~ $CC_PATTERN ]] && exit 0
|
|
39
|
+
# En-tête déjà tenté (mot: ou mot(portée):), même raté : jamais enveloppé,
|
|
40
|
+
# commit-msg le juge (« doc: x » deviendrait « feat(y): doc: x », accepté)
|
|
41
|
+
[[ "$SUBJECT" =~ ^[A-Za-z]+(\([^\)]*\))?!?: ]] && exit 0
|
|
39
42
|
[[ "$SUBJECT" =~ ^(Merge|Revert|fixup!|squash!) ]] && exit 0
|
|
40
43
|
|
|
41
44
|
# Ajoute le préfixe en tête de la première ligne (vide ou non)
|
package/package.json
CHANGED