repowarden 4.10.2 → 4.11.0-next.21
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/bin/bot +18 -1
- package/bin/bots +4 -3
- package/bin/garde +20 -3
- package/bin/migrer +4 -18
- package/bin/pr-checks +36 -4
- package/bin/run-list +9 -8
- package/bin/statut +48 -0
- package/bin/ticket +18 -3
- package/bin/tickets +2 -1
- package/ci/tickets/adopter.sh +3 -2
- package/ci/tickets/commun.sh +27 -2
- package/ci/tickets/issue.sh +16 -7
- package/ci/tickets/pr.sh +1 -1
- package/ci/tickets/push.sh +117 -4
- package/ci/tickets/registre.sh +12 -20
- package/ci/tickets/release.sh +19 -8
- package/ci/tickets.sh +6 -5
- package/hooks/commit-msg +15 -9
- package/hooks/lib/commentaires.sh +123 -0
- package/hooks/lib/common.sh +25 -3
- package/hooks/lib/i18n/en.sh +37 -4
- package/hooks/lib/i18n/fr.sh +37 -4
- package/hooks/lib/lang.sh +26 -2
- package/hooks/lib/secrets.sh +52 -0
- package/hooks/lib/tickets.sh +55 -0
- package/hooks/lib/ui.sh +12 -0
- package/hooks/pre-commit +17 -8
- package/hooks/pre-push +45 -3
- package/package.json +1 -1
package/ci/tickets/registre.sh
CHANGED
|
@@ -4,20 +4,8 @@
|
|
|
4
4
|
# Chargé par ci/tickets.sh (après hooks/lib/common.sh et hooks/lib/tickets.sh).
|
|
5
5
|
# shellcheck disable=SC2154 # statuts, réglages et compteurs définis dans les autres modules
|
|
6
6
|
|
|
7
|
-
# Registre
|
|
8
|
-
#
|
|
9
|
-
# liée supprimée y perd son nom : le registre garde le nom de chaque branche.
|
|
10
|
-
REPERE="repowarden:branche"
|
|
11
|
-
|
|
12
|
-
repere() { printf '<!-- %s %s -->' "$REPERE" "$1"; }
|
|
13
|
-
|
|
14
|
-
# REPLY = branches inscrites sur le ticket $1 (séparées par des espaces)
|
|
15
|
-
branches_inscrites_r() {
|
|
16
|
-
local corps
|
|
17
|
-
corps="$(gh issue view "$1" --json comments -q '.comments[].body' 2>/dev/null || true)"
|
|
18
|
-
REPLY="$(grep -oE "<!-- $REPERE [^ ]+ -->" <<<"$corps" | awk '{ printf "%s ", $3 }' || true)"
|
|
19
|
-
REPLY="${REPLY% }"
|
|
20
|
-
}
|
|
7
|
+
# Registre (REPERE, repere, branches_inscrites_r) : hooks/lib/tickets.sh,
|
|
8
|
+
# partagé avec repowarden ticket.
|
|
21
9
|
|
|
22
10
|
# Inscrit la branche $2 sur le ticket $1, une seule fois ($3 : origine, ex. PR #7).
|
|
23
11
|
# Une seconde branche pour le même ticket est inscrite et signalée.
|
|
@@ -34,7 +22,7 @@ inscrire_branche() {
|
|
|
34
22
|
_tr tk.branch_registered "$b"
|
|
35
23
|
fi
|
|
36
24
|
[ -z "$origine" ] || _T="$_T ($origine)"
|
|
37
|
-
|
|
25
|
+
commenter "$n" "$_T"$'\n\n'"$(repere "$b")"
|
|
38
26
|
INSCRITES=$((INSCRITES + 1))
|
|
39
27
|
}
|
|
40
28
|
|
|
@@ -65,19 +53,23 @@ nettoyer_branche() {
|
|
|
65
53
|
notice_t tk.branch_deleted "$branche" "$n"
|
|
66
54
|
else
|
|
67
55
|
_tr tk.branch_kept "$branche" "${avance:-?}" "${prs:--}"
|
|
68
|
-
|
|
56
|
+
commenter "$n" "$_T"
|
|
69
57
|
fi
|
|
70
58
|
}
|
|
71
59
|
|
|
72
60
|
# Ticket $1 validé : sa branche naît de la branche d'intégration, liée au
|
|
73
|
-
# ticket (panneau « Development »). Rien si
|
|
74
|
-
#
|
|
61
|
+
# ticket (panneau « Development »). Rien si une PR ouverte cite déjà le ticket
|
|
62
|
+
# (travail commencé hors de sa branche) ; si elle existe déjà, jamais recréée :
|
|
63
|
+
# faite avant la validation, elle n'est pas liée et son lien est inscrit.
|
|
75
64
|
creer_branche() {
|
|
76
65
|
local n="$1" titre labels branche pr head body
|
|
77
66
|
# Travail déjà mergé ou en production : plus de branche à (re)créer
|
|
78
67
|
travail_termine "$(etiquettes "$n")" && return 0
|
|
79
68
|
branche_du_ticket_r "$n"
|
|
80
|
-
[ -
|
|
69
|
+
if [ -n "$REPLY" ]; then
|
|
70
|
+
ticket_note_unlinked_branch "$n" "$REPLY" || true
|
|
71
|
+
return 0
|
|
72
|
+
fi
|
|
81
73
|
while IFS=$'\t' read -r pr head; do
|
|
82
74
|
[ -n "$pr" ] || continue
|
|
83
75
|
body="$(gh pr view "$pr" --json body -q .body)"
|
|
@@ -97,6 +89,6 @@ creer_branche() {
|
|
|
97
89
|
-f oid="$(gh api "repos/$GH_REPO/git/ref/heads/$INTEGRATION" -q .object.sha)" \
|
|
98
90
|
-f name="$branche" >/dev/null
|
|
99
91
|
_tr tk.branch_created "$branche" "$INTEGRATION" "$n" "$branche"
|
|
100
|
-
|
|
92
|
+
commenter "$n" "$_T"$'\n\n'"$(repere "$branche")"
|
|
101
93
|
notice_t tk.branch_notice "$branche" "$n"
|
|
102
94
|
}
|
package/ci/tickets/release.sh
CHANGED
|
@@ -1,20 +1,31 @@
|
|
|
1
1
|
# shellcheck shell=bash
|
|
2
|
-
# Suivi des tickets, préversion
|
|
3
|
-
# prévenus, ou passés en done et fermés.
|
|
2
|
+
# Suivi des tickets, préversion, release ou livraison sans nouvelle version
|
|
3
|
+
# (ci/tickets.sh release) : tickets prévenus, ou passés en done et fermés.
|
|
4
4
|
# Chargé par ci/tickets.sh (après hooks/lib/common.sh et hooks/lib/tickets.sh).
|
|
5
5
|
# shellcheck disable=SC2154 # statuts, réglages et compteurs définis dans les autres modules
|
|
6
6
|
|
|
7
|
+
# TAG : release (vX.Y.Z) ou préversion (vX.Y.Z-next.N) ; sans TAG,
|
|
8
|
+
# DELIVERED_SHA : commit livré sur la branche principale sans nouvelle version
|
|
9
|
+
# (livraison sans fix ni feat), les tickets livrés sont fermés tout de même
|
|
7
10
|
cmd_release() {
|
|
8
|
-
local n
|
|
11
|
+
local n tag="${TAG:-}" sha="${DELIVERED_SHA:-}"
|
|
12
|
+
if [ -n "$tag" ]; then
|
|
13
|
+
if [[ "$tag" == *-* ]]; then _tr tk.prerelease "$tag"; else _tr tk.released "$tag"; fi
|
|
14
|
+
elif [ -n "$sha" ]; then
|
|
15
|
+
_tr tk.delivered "${MAIN:-main}" "${sha:0:7}"
|
|
16
|
+
else
|
|
17
|
+
echo "ci/tickets.sh release : TAG ou DELIVERED_SHA requis" >&2
|
|
18
|
+
return 2
|
|
19
|
+
fi
|
|
20
|
+
local msg="$_T"
|
|
9
21
|
while IFS= read -r n; do
|
|
10
22
|
[ -n "$n" ] || continue
|
|
11
|
-
if [[ "$
|
|
12
|
-
|
|
13
|
-
gh issue comment "$n" --body "$_T" >/dev/null
|
|
23
|
+
if [[ "$tag" == *-* ]]; then
|
|
24
|
+
commenter "$n" "$msg"
|
|
14
25
|
else
|
|
15
|
-
_tr tk.released "$TAG"
|
|
16
26
|
statut "$n" "$S_DONE"
|
|
17
|
-
|
|
27
|
+
pied_r "$msg"
|
|
28
|
+
gh issue close "$n" --comment "$REPLY" >/dev/null
|
|
18
29
|
nettoyer_branche "$n"
|
|
19
30
|
fi
|
|
20
31
|
done < <(gh issue list --state open --label "$S_PREPROD" --limit 500 --json number -q '.[].number')
|
package/ci/tickets.sh
CHANGED
|
@@ -12,8 +12,9 @@
|
|
|
12
12
|
# ci/tickets.sh push premier push sur la branche d'un ticket : PR
|
|
13
13
|
# brouillon ouverte, ticket en cours
|
|
14
14
|
# ci/tickets.sh revue corrections demandées en revue → en cours
|
|
15
|
-
# ci/tickets.sh release release publiée
|
|
16
|
-
#
|
|
15
|
+
# ci/tickets.sh release release publiée, ou livraison sur la branche
|
|
16
|
+
# principale sans nouvelle version : tickets en
|
|
17
|
+
# préprod → done (fermés) ; ou prévenus de la préversion
|
|
17
18
|
# ci/tickets.sh adopter mise en route (tickets init) : tickets existants
|
|
18
19
|
# rangés, branches des PR inscrites sur leurs tickets
|
|
19
20
|
#
|
|
@@ -24,10 +25,10 @@
|
|
|
24
25
|
# feat/12-sujet. « Closes #12 » fermerait le ticket dès le merge dans develop :
|
|
25
26
|
# c'est la release qui le ferme.
|
|
26
27
|
#
|
|
27
|
-
# Variables : GH_TOKEN, GH_REPO, INTEGRATION
|
|
28
|
-
# HEAD, BASE, HEAD_SHA, AUTHOR ; issue : ISSUE, ACTION, LABEL, STATE_REASON ;
|
|
28
|
+
# Variables : GH_TOKEN, GH_REPO, INTEGRATION, APP_SLUG (pied des commentaires) ;
|
|
29
|
+
# pr : PR, ACTION, MERGED, DRAFT, HEAD, BASE, HEAD_SHA, AUTHOR ; issue : ISSUE, ACTION, LABEL, STATE_REASON ;
|
|
29
30
|
# push : PUSH_BRANCH, DELETED, PUSHER, SHA ; revue : PR, HEAD, REVIEW_STATE ;
|
|
30
|
-
# release : TAG
|
|
31
|
+
# release : TAG, ou DELIVERED_SHA et MAIN (livraison sans nouvelle version)
|
|
31
32
|
set -euo pipefail
|
|
32
33
|
|
|
33
34
|
REPOWARDEN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
|
package/hooks/commit-msg
CHANGED
|
@@ -74,13 +74,6 @@ Expected format: <type>(<optional scope>): <description>
|
|
|
74
74
|
refactor!: change the public API (! = breaking change)
|
|
75
75
|
|
|
76
76
|
Types:
|
|
77
|
-
EOF
|
|
78
|
-
types_help
|
|
79
|
-
cat >&2 <<EOF
|
|
80
|
-
|
|
81
|
-
👉 Tip: name your branch <type>/<topic> (e.g. feat/user) and the prefix
|
|
82
|
-
is added automatically: git commit -m "add sign-up" (or use git cc)
|
|
83
|
-
Your message is not lost: git commit -e -F .git/COMMIT_EDITMSG
|
|
84
77
|
EOF
|
|
85
78
|
else
|
|
86
79
|
cat >&2 <<EOF
|
|
@@ -93,9 +86,22 @@ Format attendu : <type>(<scope optionnel>): <description>
|
|
|
93
86
|
|
|
94
87
|
Types :
|
|
95
88
|
EOF
|
|
96
|
-
|
|
89
|
+
fi
|
|
90
|
+
types_help
|
|
91
|
+
echo >&2
|
|
92
|
+
# HEAD détachée (bisect, essai, rebase) : pas de branche dont tirer le
|
|
93
|
+
# préfixe, le conseil de nommage ne s'applique pas
|
|
94
|
+
if ! git symbolic-ref -q HEAD >/dev/null; then
|
|
95
|
+
echo_t hook.commit_msg.detached >&2
|
|
96
|
+
echo_t hook.commit_msg.kept >&2
|
|
97
|
+
elif [ "${REPOWARDEN_LANG:-}" = en ]; then
|
|
98
|
+
cat >&2 <<EOF
|
|
99
|
+
👉 Tip: name your branch <type>/<topic> (e.g. feat/user) and the prefix
|
|
100
|
+
is added automatically: git commit -m "add sign-up" (or use git cc)
|
|
101
|
+
Your message is not lost: git commit -e -F .git/COMMIT_EDITMSG
|
|
102
|
+
EOF
|
|
103
|
+
else
|
|
97
104
|
cat >&2 <<EOF
|
|
98
|
-
|
|
99
105
|
👉 Astuce : nomme ta branche <type>/<sujet> (ex. feat/user) et le préfixe
|
|
100
106
|
sera ajouté automatiquement : git commit -m "ajoute l'inscription" (ou git cc)
|
|
101
107
|
Ton message n'est pas perdu : git commit -e -F .git/COMMIT_EDITMSG
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Fonctions ajoutées sans commentaire : chaque nouvelle fonction doit dire,
|
|
3
|
+
# juste au-dessus, ce qu'elle fait et pourquoi (docstring acceptée en Python).
|
|
4
|
+
# Comme pour le code mort, seul le code ajouté compte : une fonction dont le
|
|
5
|
+
# nom existait déjà dans le fichier n'est jamais signalée, même retouchée.
|
|
6
|
+
# Avertissement seulement (pre-commit et CI), désactivable par skip = comments.
|
|
7
|
+
# Langages : Shell (.sh, .bash, ou shebang sh/bash), Python, JavaScript/TypeScript.
|
|
8
|
+
|
|
9
|
+
# Une ligne « fichier:ligne<TAB>nom » par fonction ajoutée sans commentaire
|
|
10
|
+
# entre $1 (commit de base) et $2 (commit, ou vide pour le contenu stagé).
|
|
11
|
+
comments_missing() {
|
|
12
|
+
local base="$1" new="$2" st a b f old lang added tmp
|
|
13
|
+
tmp="$(mktemp -d)"
|
|
14
|
+
while IFS=$'\t' read -r st a b; do
|
|
15
|
+
[ -n "$a" ] || continue
|
|
16
|
+
# Renommage ou copie : l'ancien chemin donne les fonctions existantes
|
|
17
|
+
if [ -n "$b" ]; then old="$a" f="$b"; else old="$a" f="$a"; fi
|
|
18
|
+
is_excluded "$f" && continue
|
|
19
|
+
case "${f##*/}" in
|
|
20
|
+
*.sh | *.bash) lang=shell ;;
|
|
21
|
+
*.py) lang=py ;;
|
|
22
|
+
*.js | *.jsx | *.mjs | *.cjs | *.ts | *.tsx) lang=js ;;
|
|
23
|
+
*.*) continue ;;
|
|
24
|
+
*) lang=shebang ;;
|
|
25
|
+
esac
|
|
26
|
+
git show "$new:$f" >"$tmp/new" 2>/dev/null || continue
|
|
27
|
+
if [ "$lang" = shebang ]; then
|
|
28
|
+
# Script sans extension (bin/…) : seul un shebang sh ou bash compte
|
|
29
|
+
IFS= read -r st <"$tmp/new" || true
|
|
30
|
+
[[ "$st" =~ ^#!.*[/\ ](ba)?sh([[:space:]]|$) ]] || continue
|
|
31
|
+
lang=shell
|
|
32
|
+
fi
|
|
33
|
+
git show "$base:$old" >"$tmp/base" 2>/dev/null || : >"$tmp/base"
|
|
34
|
+
if [ -n "$new" ]; then
|
|
35
|
+
git diff -U0 --no-color --no-ext-diff "$base" "$new" -- "$f"
|
|
36
|
+
else
|
|
37
|
+
git diff --cached -U0 --no-color --no-ext-diff "$base" -- "$f"
|
|
38
|
+
fi 2>/dev/null >"$tmp/diff"
|
|
39
|
+
# Numéros des lignes ajoutées ou modifiées, d'après les en-têtes @@
|
|
40
|
+
added="$(awk '/^@@/ {
|
|
41
|
+
split($3, a, ","); s = substr(a[1], 2); n = (a[2] == "" ? 1 : a[2])
|
|
42
|
+
for (i = 0; i < n; i++) printf " %d", s + i
|
|
43
|
+
}' "$tmp/diff") "
|
|
44
|
+
[ "$added" != " " ] || continue
|
|
45
|
+
awk -v lang="$lang" -v added="$added" -v f="$f" -v q="'" "$COMMENTS_AWK" "$tmp/base" "$tmp/new"
|
|
46
|
+
done < <(
|
|
47
|
+
if [ -n "$new" ]; then
|
|
48
|
+
git diff --name-status -M --diff-filter=ACMR "$base" "$new"
|
|
49
|
+
else
|
|
50
|
+
git diff --cached --name-status -M --diff-filter=ACMR "$base"
|
|
51
|
+
fi 2>/dev/null
|
|
52
|
+
)
|
|
53
|
+
rm -rf "$tmp"
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
# Avertit des fonctions ajoutées sans commentaire, sans jamais bloquer : le
|
|
57
|
+
# commentaire aide la relecture, son absence n'est pas une faute. REPLY = nombre.
|
|
58
|
+
comments_check() {
|
|
59
|
+
local loc name n=0
|
|
60
|
+
while IFS=$'\t' read -r loc name; do
|
|
61
|
+
[ -n "$loc" ] || continue
|
|
62
|
+
n=$((n + 1))
|
|
63
|
+
attention_t cm.missing "$loc" "$name"
|
|
64
|
+
done < <(comments_missing "$1" "$2")
|
|
65
|
+
[ "$n" = 0 ] || info_t cm.summary "$n"
|
|
66
|
+
REPLY="$n"
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
# Programme awk de comments_missing : lit le fichier de base (noms des
|
|
70
|
+
# fonctions existantes) puis le nouveau, et signale les fonctions nouvelles
|
|
71
|
+
# dont aucune ligne de commentaire ne précède la déclaration
|
|
72
|
+
# shellcheck disable=SC2016 # programme awk, rien à développer
|
|
73
|
+
COMMENTS_AWK='
|
|
74
|
+
# Nom de la fonction déclarée par la ligne l (vide sinon), selon le langage
|
|
75
|
+
function nom(l) {
|
|
76
|
+
if (lang == "shell") {
|
|
77
|
+
if (l ~ /^[ \t]*function[ \t]+[A-Za-z_]/) {
|
|
78
|
+
sub(/^[ \t]*function[ \t]+/, "", l); sub(/[ \t(){}].*$/, "", l); return l
|
|
79
|
+
}
|
|
80
|
+
if (l ~ /^[ \t]*[A-Za-z_][A-Za-z0-9_:.@-]*[ \t]*\(\)/) {
|
|
81
|
+
sub(/^[ \t]*/, "", l); sub(/[ \t]*\(\).*$/, "", l); return l
|
|
82
|
+
}
|
|
83
|
+
} else if (lang == "py") {
|
|
84
|
+
if (l ~ /^[ \t]*(async[ \t]+)?def[ \t]+[A-Za-z_]/) {
|
|
85
|
+
sub(/^[ \t]*(async[ \t]+)?def[ \t]+/, "", l); sub(/[^A-Za-z0-9_].*$/, "", l); return l
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
if (l ~ /^[ \t]*(export[ \t]+(default[ \t]+)?)?(async[ \t]+)?function[ \t]*\*?[ \t]*[A-Za-z_$]/) {
|
|
89
|
+
sub(/^[ \t]*(export[ \t]+(default[ \t]+)?)?(async[ \t]+)?function[ \t]*\*?[ \t]*/, "", l)
|
|
90
|
+
sub(/[^A-Za-z0-9_$].*$/, "", l); return l
|
|
91
|
+
}
|
|
92
|
+
if (l ~ /^[ \t]*(export[ \t]+)?(const|let|var)[ \t]+[A-Za-z_$][A-Za-z0-9_$]*[ \t]*(:[^=]*)?=[ \t]*(async[ \t]+)?(function[^A-Za-z0-9_$]|function$|\([^)]*\)[^=]*=>|[A-Za-z_$][A-Za-z0-9_$]*[ \t]*=>)/) {
|
|
93
|
+
sub(/^[ \t]*(export[ \t]+)?(const|let|var)[ \t]+/, "", l); sub(/[^A-Za-z0-9_$].*$/, "", l); return l
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return ""
|
|
97
|
+
}
|
|
98
|
+
# Directive d outil (shellcheck, eslint, noqa…) : n explique rien, on regarde au-dessus
|
|
99
|
+
function directive(l) {
|
|
100
|
+
return l ~ /^[ \t]*(#|\/\/)[ \t]*(shellcheck|noqa|type:|pylint:|eslint|@ts-|prettier-)/
|
|
101
|
+
}
|
|
102
|
+
# Commentaire juste au-dessus de la ligne i (décorateurs et directives sautés),
|
|
103
|
+
# ou docstring en tête du corps pour Python
|
|
104
|
+
function commentee(i, j, s) {
|
|
105
|
+
for (j = i - 1; j > 0 && (L[j] ~ /^[ \t]*@/ || directive(L[j])); j--) ;
|
|
106
|
+
if (j > 0 && L[j] !~ /^#!/ && L[j] ~ /^[ \t]*(#|\/\/|\/\*|\*)/) return 1
|
|
107
|
+
if (lang != "py") return 0
|
|
108
|
+
# Fin de la signature (deux-points en fin de ligne), puis première ligne non vide
|
|
109
|
+
for (j = i; j <= N && j < i + 20 && L[j] !~ /:[ \t]*(#.*)?$/; j++) ;
|
|
110
|
+
for (j++; j <= N && L[j] ~ /^[ \t]*$/; j++) ;
|
|
111
|
+
s = "^[ \t]*[rRuUbBfF]*[\"" q "]"
|
|
112
|
+
return j <= N && L[j] ~ s
|
|
113
|
+
}
|
|
114
|
+
FILENAME == ARGV[1] { n = nom($0); if (n != "") ancien[n] = 1; next }
|
|
115
|
+
{ L[FNR] = $0; N = FNR }
|
|
116
|
+
END {
|
|
117
|
+
for (i = 1; i <= N; i++) {
|
|
118
|
+
if (index(added, " " i " ") == 0) continue
|
|
119
|
+
n = nom(L[i])
|
|
120
|
+
if (n == "" || (n in ancien) || commentee(i)) continue
|
|
121
|
+
print f ":" i "\t" n
|
|
122
|
+
}
|
|
123
|
+
}'
|
package/hooks/lib/common.sh
CHANGED
|
@@ -218,6 +218,30 @@ header_valid() {
|
|
|
218
218
|
[ "$REPLY" -le 72 ]
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
+
# Bots de mise à jour des dépendances : leurs titres (« bump <paquet> from X
|
|
222
|
+
# to Y ») dépassent souvent 72 caractères ; seul leur format est exigé.
|
|
223
|
+
BOTS='^[0-9]*\+?(dependabot|renovate)\[bot\]@'
|
|
224
|
+
|
|
225
|
+
# Règle des en-têtes de commit, commune au pre-push et à la CI : même verdict,
|
|
226
|
+
# même message, que le commit soit vu avant le push ou après.
|
|
227
|
+
# REPLY = clé du message de refus de l'en-tête $1 (e-mail de l'auteur $2),
|
|
228
|
+
# vide si l'en-tête est admis
|
|
229
|
+
commit_subject_problem_r() {
|
|
230
|
+
if [[ "$1" =~ ^(fixup|squash|amend)! ]]; then
|
|
231
|
+
REPLY=ci.check.3
|
|
232
|
+
elif [[ "$1" =~ ^(Merge|Revert) ]]; then
|
|
233
|
+
REPLY=""
|
|
234
|
+
elif ! [[ "$1" =~ $CC_PATTERN ]]; then
|
|
235
|
+
REPLY=ci.check.4
|
|
236
|
+
elif [[ "$2" =~ $BOTS ]]; then
|
|
237
|
+
REPLY=""
|
|
238
|
+
elif authored_length "$1" && [ "$REPLY" -gt 72 ]; then
|
|
239
|
+
REPLY=ci.check.5
|
|
240
|
+
else
|
|
241
|
+
REPLY=""
|
|
242
|
+
fi
|
|
243
|
+
}
|
|
244
|
+
|
|
221
245
|
# REPLY = titre de PR conforme déduit de la branche $1 :
|
|
222
246
|
# feat/ajout-panier → « feat: ajout panier », hotfix/crash → « fix: crash »,
|
|
223
247
|
# release/1.2.0 → « chore(release): 1.2.0 », develop → livraison sur main
|
|
@@ -310,7 +334,6 @@ EOF
|
|
|
310
334
|
|
|
311
335
|
Allowed exceptions: $allowed
|
|
312
336
|
(change: git config repowarden.allowedBranches "main develop release/*")
|
|
313
|
-
Disable for this repository: git config repowarden.skip branch-name
|
|
314
337
|
EOF
|
|
315
338
|
else
|
|
316
339
|
cat >&2 <<EOF
|
|
@@ -333,7 +356,6 @@ EOF
|
|
|
333
356
|
|
|
334
357
|
Exceptions autorisées : $allowed
|
|
335
358
|
(modifier : git config repowarden.allowedBranches "main develop release/*")
|
|
336
|
-
Désactiver pour ce dépôt : git config repowarden.skip branch-name
|
|
337
359
|
EOF
|
|
338
360
|
fi
|
|
339
361
|
}
|
|
@@ -341,7 +363,7 @@ EOF
|
|
|
341
363
|
# Vrai si l'élément est désactivé (repowarden.skip, git config ou .repowarden.conf).
|
|
342
364
|
# Valeurs : true|all, ou liste séparée par espaces/virgules parmi
|
|
343
365
|
# pre-commit prepare-commit-msg commit-msg pre-push post-checkout
|
|
344
|
-
# branch-name protect-branch secrets format tests, ou un langage (node, python…)
|
|
366
|
+
# branch-name protect-branch secrets sensitive-files format tests, ou un langage (node, python…)
|
|
345
367
|
skipped() {
|
|
346
368
|
local v
|
|
347
369
|
cfg_r skip
|
package/hooks/lib/i18n/en.sh
CHANGED
|
@@ -50,11 +50,13 @@ _msg_en() {
|
|
|
50
50
|
cc.refs_prompt_ticket) _M="References (\"-\" for none) [%s]: " ;;
|
|
51
51
|
cc.refs_prompt) _M="References (e.g. %s; Enter for none): " ;;
|
|
52
52
|
tk.cli.no_ticket) _M="Branch %s has no ticket: this work will not be linked to any ticket (not blocking)." ;;
|
|
53
|
+
tk.cli.explain) _M="Ticket: the GitHub issue each change starts from (branch type/<n>-topic, PR citing it); its lifecycle: https://simdevwarden.github.io/repowarden/en/tickets/" ;;
|
|
53
54
|
tk.cli.propose) _M="Start it from a ticket: repowarden ticket nouveau \"<title>\"." ;;
|
|
54
55
|
tk.cli.propose_cc) _M="Start it from a ticket: repowarden ticket nouveau \"<title>\" (or answer yes in git cc)." ;;
|
|
55
56
|
tk.cli.silence) _M="Project without ticket tracking? git config repowarden.skip tickets to stop seeing this." ;;
|
|
56
57
|
tk.cli.fetch) _M="Branch of ticket #%s…" ;;
|
|
57
58
|
tk.cli.switched) _M="On branch %s (ticket #%s)." ;;
|
|
59
|
+
tk.cli.unlinked) _M="Branch %s was created before validation: GitHub cannot link it to ticket #%s afterwards, its link is written on the ticket." ;;
|
|
58
60
|
tk.cli.created_branch) _M="Branch %s created from %s, linked to ticket #%s." ;;
|
|
59
61
|
tk.cli.not_validated) _M="Ticket #%s not validated yet: its branch will be created automatically on validation (\"%s\" label)." ;;
|
|
60
62
|
tk.cli.closed) _M="Ticket #%s is closed: no branch to create." ;;
|
|
@@ -62,6 +64,7 @@ _msg_en() {
|
|
|
62
64
|
tk.cli.issue_created) _M="Ticket #%s created, awaiting validation. Its branch will be created on validation; then: repowarden ticket %s" ;;
|
|
63
65
|
tk.cli.issue_created_branch) _M="Ticket #%s created." ;;
|
|
64
66
|
tk.cli.title_required) _M="Ticket title required: repowarden ticket nouveau \"<title>\"" ;;
|
|
67
|
+
tk.cli.bad_type) _M="Unknown ticket type: %s (types: %s)" ;;
|
|
65
68
|
tk.cli.current) _M="Branch %s: ticket #%s." ;;
|
|
66
69
|
tk.cli.no_ticket_here) _M="No ticket for this branch." ;;
|
|
67
70
|
cc.ticket_offer) _M="No ticket for this branch. Create one now (title: the description)? [y/N]: " ;;
|
|
@@ -119,7 +122,7 @@ _msg_en() {
|
|
|
119
122
|
help.code-mort) _M="Usage: repowarden code-mort [base]\n\nDead code introduced by your branch (like CI): only added/changed lines\nsince base (commits, staged/uncommitted, new files). Default: merge-base\nwith origin/main. See docs/code-mort.md (proven vs candidates)." ;;
|
|
120
123
|
help.ticket) _M="Usage: repowarden ticket <n> branch for ticket (created, linked if needed)\n repowarden ticket ticket of current branch\n repowarden ticket nouveau \"<title>\" [--type fix] [--description \"…\"]\n repowarden ticket comment <n> \"<text>\" add comment\n repowarden ticket label <n> <label> [--remove] manage labels\n\nTicket first: taking <n> assigns to you and switches to its branch\n(created from develop if needed). \"nouveau\" creates a ticket (\"à valider\"\nif tracking is managed). Needs gh connected (https://cli.github.com)." ;;
|
|
121
124
|
help.tickets) _M="Usage: repowarden tickets init [--repo owner/name] [--sans-validation-auto]\n repowarden tickets sync\n\nSets up ticket tracking: labels, issue template, workflow; classifies\nexisting tickets; records PR branches. sync checks out local branches for\ntickets assigned to you (auto with ticketSync=auto, manual by default)." ;;
|
|
122
|
-
help.pr) _M="Usage: repowarden pr label <n> <label> [--remove]\n repowarden pr checks <n>\n\nlabel adds or removes a label from PR #<n>; checks
|
|
125
|
+
help.pr) _M="Usage: repowarden pr label <n> <label> [--remove]\n repowarden pr checks <n>\n\nlabel adds or removes a label from PR #<n>; checks lists its failed\njobs (with their link) and pending ones, then the verdict; exit 1 if a job fails.\nExamples:\n repowarden pr label 123 \"ready-for-review\"\n repowarden pr label 123 \"needs-changes\" --remove\n repowarden pr checks 123" ;;
|
|
123
126
|
help.run) _M="Usage: repowarden run rerun <run-id|--failed|--workflow <name>>\n repowarden run list [--workflow <name>] [--limit N]\n\nrerun restarts a GitHub Actions workflow. list shows recent runs\n(default limit 20).\nExamples:\n repowarden run rerun --failed\n repowarden run list --workflow \"CI\" --limit 10" ;;
|
|
124
127
|
help.proteger) _M="Usage: repowarden proteger [--repo owner/name] [--checks \"repowarden,tests (ubuntu-latest)\"]\n [--relecteurs N] [--codeowners] [--environnement NAME] [--approbateurs \"login …\"]\n [--sans-tags] [--dry-run] [--verifier]\n\nProtects GitHub repo per .repowarden.conf: required PR, required checks,\nno force push/deletion, ruleset, squash merges, v* tags reserved to\nworkflows, optional human approvals. --verifier checks online rules\nwithout changes. Needs gh and admin rights." ;;
|
|
125
128
|
help.migrer) _M="Usage: repowarden migrer [--pr] [--hooks]\n\nMigrates from repogarde to repowarden (docs/migration-v4.md): configs,\nworkflows, renames, lists manual steps left. Safe to rerun.\n --pr on chore/migration-repowarden-vN: commit, push and PR\n --hooks also move leftover lefthook hooks to .git/hooks-lefthook/" ;;
|
|
@@ -130,7 +133,6 @@ _msg_en() {
|
|
|
130
133
|
# Hooks and language plugins
|
|
131
134
|
hook.pre_commit.1) _M="Commit refused: branch name does not follow the convention." ;;
|
|
132
135
|
hook.pre_commit.2) _M="Direct commit on '%s' forbidden. Create a branch: git switch -c feat/my-feature" ;;
|
|
133
|
-
hook.pre_commit.3) _M=" (disable for this repository: git config repowarden.skip protect-branch)" ;;
|
|
134
136
|
hook.pre_commit.4) _M="Secret detection (gitleaks)" ;;
|
|
135
137
|
hook.pre_commit.5) _M="Secret detected: commit refused." ;;
|
|
136
138
|
hook.secrets.where) _M=" %s:%s (%s)" ;;
|
|
@@ -141,7 +143,9 @@ _msg_en() {
|
|
|
141
143
|
hook.secrets.todo_3) _M=" 3. Key that may have leaked elsewhere (already pushed, shared): revoke it at its provider." ;;
|
|
142
144
|
hook.secrets.todo_4) _M=" False positive: add its fingerprint to .gitleaksignore:" ;;
|
|
143
145
|
hook.secrets.failed) _M="gitleaks failed (code %s): commit refused, secret detection not done." ;;
|
|
144
|
-
hook.pre_commit.6) _M="gitleaks not installed,
|
|
146
|
+
hook.pre_commit.6) _M="gitleaks not installed: secrets not checked before the commit, the CI (secrets check) will do it. Install: %s" ;;
|
|
147
|
+
hook.sensitive.found) _M="Sensitive file neither tracked nor ignored: git add . would publish it. Lines to add to .gitignore:" ;;
|
|
148
|
+
hook.sensitive.hint) _M=" (names compared, content never read; patterns: repowarden.sensitiveFiles; disable: git config repowarden.skip sensitive-files)" ;;
|
|
145
149
|
hook.pre_commit.7) _M="Pre-commit OK" ;;
|
|
146
150
|
hook.commit_msg.1) _M="First line too long (%s > 72 characters)." ;;
|
|
147
151
|
hook.commit_msg.type_unknown) _M="Unknown type \"%s\". Did you mean: %s" ;;
|
|
@@ -149,13 +153,16 @@ _msg_en() {
|
|
|
149
153
|
hook.commit_msg.desc_empty) _M="Missing description after \"%s\": describe the change in the imperative mood." ;;
|
|
150
154
|
hook.commit_msg.kept) _M=" Your message is not lost: git commit -e -F .git/COMMIT_EDITMSG" ;;
|
|
151
155
|
hook.commit_msg.dot) _M="Final period removed from the description (same rule as git cc)." ;;
|
|
156
|
+
hook.commit_msg.detached) _M="👉 Detached HEAD (bisect, trial): no prefix comes from a branch, write the full header (e.g. fix: correct the total)." ;;
|
|
152
157
|
hook.pre_push.1) _M="Push refused: branch name does not follow the convention." ;;
|
|
153
158
|
hook.pre_push.2) _M="Direct push to '%s' refused: it only changes through pull requests." ;;
|
|
154
159
|
hook.pre_push.3) _M=" Create a branch: git switch -c feat/my-feature, then open a PR." ;;
|
|
155
|
-
hook.pre_push.4) _M=" (disable for this repository: git config repowarden.skip protect-branch)" ;;
|
|
156
160
|
hook.pre_push.5) _M="%s: no changed file, nothing to test." ;;
|
|
157
161
|
hook.pre_push.6) _M="Nothing to test (branch deletion only)." ;;
|
|
158
162
|
hook.pre_push.7) _M="Pre-push OK" ;;
|
|
163
|
+
hook.pre_push.msg) _M="Push refused: commit message does not follow the convention (same rule as CI)." ;;
|
|
164
|
+
hook.pre_push.msg_fix) _M=" Fix: git rebase -i %s (reword), then push again." ;;
|
|
165
|
+
hook.pre_push.nothing) _M="Nothing to push." ;;
|
|
159
166
|
hook.pre_push.workflow_scope) _M="gh token without the 'workflow' scope: GitHub will refuse a push touching .github/workflows/. Allow it (then sign in again): gh auth refresh -h github.com -s workflow" ;;
|
|
160
167
|
hook.pre_push.lint.missing) _M="%s not installed, %s not checked (install: %s)." ;;
|
|
161
168
|
hook.pre_push.lint.run) _M="%s: %s" ;;
|
|
@@ -287,6 +294,11 @@ _msg_en() {
|
|
|
287
294
|
ci.fix_pr.2) _M="PR #%s retargeted: %s → %s (%s flow)" ;;
|
|
288
295
|
ci.fix_pr.3) _M="Title follows the convention: %s" ;;
|
|
289
296
|
ci.fix_pr.4) _M="Title \"%s\" replaced with \"%s\"" ;;
|
|
297
|
+
ci.verrous_pip.compile) _M="Lock file %s: re-running the command from its header" ;;
|
|
298
|
+
ci.verrous_pip.refused) _M="Lock file %s skipped: the output of its header command is not this file" ;;
|
|
299
|
+
ci.verrous_pip.compliant) _M="pip lock files match their header: no commit" ;;
|
|
300
|
+
ci.verrous_pip.committed) _M="Lock files regenerated and committed: %s" ;;
|
|
301
|
+
ci.verrous_pip.pushed) _M="Commit pushed to %s" ;;
|
|
290
302
|
ci.version.1) _M="version announced by the delivery PR" ;;
|
|
291
303
|
ci.version.2) _M="No feat, fix, perf or breaking change since %s: no version." ;;
|
|
292
304
|
ci.version.3) _M="first version" ;;
|
|
@@ -420,6 +432,12 @@ _msg_en() {
|
|
|
420
432
|
dc.knip_file) _M="file never imported" ;;
|
|
421
433
|
dc.knip_export) _M="export never imported:" ;;
|
|
422
434
|
dc.knip_dep) _M="dependency never imported:" ;;
|
|
435
|
+
# Functions added without a comment
|
|
436
|
+
cm.section) _M="Functions without a comment (new code only)" ;;
|
|
437
|
+
cm.no_base) _M="No base: comment check skipped." ;;
|
|
438
|
+
cm.missing) _M="%s: function %s has no comment right above it" ;;
|
|
439
|
+
cm.summary) _M="%s function(s) added without a comment: one or two lines right above, saying what it does and why (warning, not blocking)." ;;
|
|
440
|
+
cm.none) _M="Every added function has a comment." ;;
|
|
423
441
|
ci.section.commits) _M="Commit messages (Conventional Commits)" ;;
|
|
424
442
|
ci.section.branch) _M="Branch name" ;;
|
|
425
443
|
ci.section.secrets) _M="Secrets (gitleaks)" ;;
|
|
@@ -486,6 +504,10 @@ _msg_en() {
|
|
|
486
504
|
st.repo_version_ok) _M="Version required by the project (%s): met" ;;
|
|
487
505
|
st.repo_forge) _M="Platform: %s" ;;
|
|
488
506
|
st.repo_rules) _M="GitHub rules up to date? repowarden proteger --verifier (read-only)" ;;
|
|
507
|
+
st.wf_owner) _M="%s:%s: repowarden called from another repository than the official one (%s); expected: %s" ;;
|
|
508
|
+
st.wf_branch) _M="%s:%s: repowarden called on a branch (@%s), broken as soon as it is deleted; expected: %s" ;;
|
|
509
|
+
st.wf_old) _M="%s:%s: repowarden called in an outdated major version (@%s); expected: %s" ;;
|
|
510
|
+
st.wf_fix) _M="fix the uses: lines reported above" ;;
|
|
489
511
|
st.tools) _M="Tools present: %s · missing: %s (depending on the projects' languages)" ;;
|
|
490
512
|
st.next) _M="Next step:" ;;
|
|
491
513
|
st.ready) _M="All set: git cc to commit, repowarden code-mort on a branch." ;;
|
|
@@ -541,6 +563,7 @@ _msg_en() {
|
|
|
541
563
|
bot.ignored) _M="ignored (bot = off)" ;;
|
|
542
564
|
bot.mode_invalid) _M="bot = %s: auto, pr or off expected" ;;
|
|
543
565
|
bot.clone_failed) _M="clone failed: %s" ;;
|
|
566
|
+
bot.email_fallback) _M="Bot user %s not found: commits signed %s, linked to no account (set REPOWARDEN_BOT_EMAIL to fix the address)." ;;
|
|
544
567
|
bot.prot_ok) _M="up to date" ;;
|
|
545
568
|
bot.prot_stale) _M="⚠ outdated: repowarden proteger" ;;
|
|
546
569
|
bot.prot_applied) _M="✔ applied" ;;
|
|
@@ -633,6 +656,7 @@ _msg_en() {
|
|
|
633
656
|
tk.pr_backmerge_empty) _M="PR closed automatically: \`%s\` brings no content to \`%s\`. The back-merge is done automatically after a release, only when there is something to bring back." ;;
|
|
634
657
|
tk.pr_delivery_manual) _M="PR closed automatically: the \`%s\` → \`%s\` delivery is opened by the release workflow; a PR opened by hand would never get a deployment approval. Run *Actions → release → Run workflow* on \`%s\` (or \`gh workflow run release.yml --ref %s\`), then **Approve and deploy** on the run." ;;
|
|
635
658
|
tk.branch_registered) _M="Ticket branch: \`%s\`." ;;
|
|
659
|
+
tk.branch_unlinked) _M="Ticket branch: [\`%s\`](%s). Created before the ticket was validated: GitHub does not link an existing branch, so it does not show under *Development*; this comment keeps its link." ;;
|
|
636
660
|
tk.branch_second) _M="Second branch for this ticket: \`%s\` (already: %s). One ticket, one branch: group the work, or open a separate ticket." ;;
|
|
637
661
|
tk.adopted) _M="Existing tickets: %s sorted, %s branch(es) registered." ;;
|
|
638
662
|
tk.init_adopt) _M="Existing tickets and branches" ;;
|
|
@@ -641,6 +665,8 @@ _msg_en() {
|
|
|
641
665
|
tk.branch_kept) _M="Branch \`%s\` kept: %s commit(s) missing from the integration branch, open PR(s): %s. Delete it by hand if the work lives elsewhere." ;;
|
|
642
666
|
tk.draft_opened) _M="Draft PR #%s opened for ticket #%s" ;;
|
|
643
667
|
tk.draft_updated) _M="PR #%s (ticket #%s): title and description taken from the ticket" ;;
|
|
668
|
+
tk.pr_additions) _M="Ticket additions" ;;
|
|
669
|
+
tk.pr_design) _M="Design (summary)" ;;
|
|
644
670
|
tk.created_body) _M="Ticket created automatically for PR #%s, which cited none. To be validated by a maintainer (\"validé\" label)." ;;
|
|
645
671
|
tk.created) _M="Ticket #%s created for PR #%s and linked in its description: to be validated by a maintainer." ;;
|
|
646
672
|
tk.init_labels) _M="Labels (statuses and validation)" ;;
|
|
@@ -654,6 +680,8 @@ _msg_en() {
|
|
|
654
680
|
tk.init_next_wired) _M="Next: commit these files; require the \"ticket\" check (repowarden proteger --checks \"…,ticket\"). The tickets job of release.yml is already wired." ;;
|
|
655
681
|
tk.prerelease) _M="Available in pre-release **%s**: to be tested before production." ;;
|
|
656
682
|
tk.released) _M="Released in **%s**." ;;
|
|
683
|
+
tk.footer) _M="Posted by this repository's GitHub App ([repowarden docs](https://simdevwarden.github.io/repowarden/en/industrialisation/#github-app-for-workflows)): [%s](https://github.com/apps/%s)" ;;
|
|
684
|
+
tk.delivered) _M="Delivered to **%s**, without a new version (commit %s)." ;;
|
|
657
685
|
# Ticket comment
|
|
658
686
|
tk.comment.adding) _M="Adding comment to ticket #%s..." ;;
|
|
659
687
|
tk.comment.added) _M="Comment added to ticket #%s." ;;
|
|
@@ -679,6 +707,11 @@ _msg_en() {
|
|
|
679
707
|
run.listing.workflow) _M="Listing runs for workflow \"%s\"..." ;;
|
|
680
708
|
# PR checks
|
|
681
709
|
pr.checks.checking) _M="Checking checks for PR #%s..." ;;
|
|
710
|
+
pr.checks.failed) _M="Failed: %s %s" ;;
|
|
711
|
+
pr.checks.pending) _M="Pending: %s" ;;
|
|
712
|
+
pr.checks.verdict) _M="PR #%s: %s passed, %s failed, %s pending." ;;
|
|
713
|
+
pr.checks.green) _M="All checks of PR #%s are green." ;;
|
|
714
|
+
pr.checks.none) _M="No check on PR #%s." ;;
|
|
682
715
|
# AI agent guard (repowarden garde, repowarden agents)
|
|
683
716
|
garde.format) _M="Unknown format \"%s\": claude or opencode." ;;
|
|
684
717
|
garde.no_jq) _M="repowarden garde: jq missing, action not checked (install jq: https://jqlang.org)." ;;
|