repowarden 4.8.3 → 4.9.0-next.10
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/LICENSE +674 -21
- package/README.md +2 -2
- package/bin/app +61 -9
- package/bin/bots +236 -26
- package/bin/npm-publication +37 -67
- package/bin/proteger +34 -3
- package/bin/tickets +9 -3
- package/ci/tickets/issue.sh +38 -9
- package/ci/tickets/push.sh +26 -4
- package/hooks/lib/i18n/en.sh +37 -14
- package/hooks/lib/i18n/fr.sh +37 -14
- package/hooks/lib/tickets.sh +9 -5
- package/package.json +2 -2
package/bin/proteger
CHANGED
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
# - tags v* : créés, déplacés ou supprimés uniquement par les workflows ;
|
|
8
8
|
# - GitHub Actions autorisé à créer des PR (releases automatiques) ;
|
|
9
9
|
# - validation humaine (optionnelle) : approbations obligatoires, revue des
|
|
10
|
-
# CODEOWNERS, environnement de déploiement approuvé par des personnes
|
|
10
|
+
# CODEOWNERS, environnement de déploiement approuvé par des personnes ;
|
|
11
|
+
# livraison approuvée (deliveryApproval deployment ou review, défaut) ou
|
|
12
|
+
# automatique (auto : vérifications exigées gardées).
|
|
11
13
|
#
|
|
12
14
|
# bin/proteger [--repo propriétaire/nom] [--checks "repowarden,tests (ubuntu-latest)"] [--relecteurs N]
|
|
13
15
|
# [--codeowners] [--environnement NOM] [--approbateurs "login …"]
|
|
@@ -54,7 +56,7 @@ while [ $# -gt 0 ]; do
|
|
|
54
56
|
--sans-tags) NO_TAGS=1 ;;
|
|
55
57
|
--dry-run) DRY_RUN=1 ;;
|
|
56
58
|
--verifier) VERIFY=1 ;;
|
|
57
|
-
-h | --help) sed -n '2,
|
|
59
|
+
-h | --help) sed -n '2,19p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
|
|
58
60
|
*) err_t install.unknown_arg "$1"; exit 1 ;;
|
|
59
61
|
esac
|
|
60
62
|
shift
|
|
@@ -84,6 +86,16 @@ for b in $protected; do
|
|
|
84
86
|
[ "$(gh api "repos/$REPO/branches/$b" --jq .name 2>/dev/null)" = "$b" ] && existing="$existing $b"
|
|
85
87
|
done
|
|
86
88
|
[ -n "$existing" ] || { err_t ci.proteger.no_branch "$protected" "$REPO"; exit 1; }
|
|
89
|
+
# Branche d'intégration absente : arrêt avant toute modification (GitHub
|
|
90
|
+
# refuserait une branche par défaut inexistante, réglages posés à moitié)
|
|
91
|
+
if [ -n "$integration" ] &&
|
|
92
|
+
[ "$(gh api "repos/$REPO/branches/$integration" --jq .name 2>/dev/null)" != "$integration" ]; then
|
|
93
|
+
principale=main
|
|
94
|
+
for b in $existing; do [ "$b" = "$integration" ] || { principale="$b"; break; }; done
|
|
95
|
+
err_t ci.proteger.no_integration "$integration" "$REPO"
|
|
96
|
+
dim_t ci.proteger.no_integration_hint "$principale" "$integration"
|
|
97
|
+
exit 1
|
|
98
|
+
fi
|
|
87
99
|
|
|
88
100
|
# Vérifications séparées par des virgules : un nom de job peut contenir des
|
|
89
101
|
# espaces (« tests (ubuntu-latest) »)
|
|
@@ -179,14 +191,21 @@ if [ -n "$integration" ]; then
|
|
|
179
191
|
# l'approbation de l'environnement de livraison (« Approve and deploy »),
|
|
180
192
|
# exigée par une règle de main (déploiement réussi) ; la revue de PR n'est
|
|
181
193
|
# plus nécessaire (relectures configurées : gardées). review : revue de PR.
|
|
194
|
+
# auto : choix du projet, la validation humaine est le merge de chaque
|
|
195
|
+
# ticket ; la GitHub App arme le merge de la livraison (release-auto,
|
|
196
|
+
# delivery-auto), qui part quand les vérifications exigées sont vertes.
|
|
197
|
+
# Ni règle de déploiement ni environnement créé d'office ; vérifications
|
|
198
|
+
# et relectures configurées gardées.
|
|
182
199
|
cfg_r deliveryApproval deployment
|
|
183
200
|
DELIVERY="$REPLY"
|
|
184
|
-
[[ "$DELIVERY" =~ ^(deployment|review)$ ]] || { err_t ci.proteger.delivery_invalid; exit 1; }
|
|
201
|
+
[[ "$DELIVERY" =~ ^(deployment|review|auto)$ ]] || { err_t ci.proteger.delivery_invalid; exit 1; }
|
|
185
202
|
deploiement=""
|
|
186
203
|
if [ "$DELIVERY" = deployment ]; then
|
|
187
204
|
ENVIRONMENT="${ENVIRONMENT:-production}"
|
|
188
205
|
livraison="$REVIEWS"
|
|
189
206
|
deploiement="{\"type\": \"required_deployments\", \"parameters\": {\"required_deployment_environments\": [\"$ENVIRONMENT\"]}}"
|
|
207
|
+
elif [ "$DELIVERY" = auto ]; then
|
|
208
|
+
livraison="$REVIEWS"
|
|
190
209
|
fi
|
|
191
210
|
# PR à jour non exigée non plus : le merge commit d'une livraison n'existe
|
|
192
211
|
# que sur main ; strict, la livraison suivante serait bloquée tant que
|
|
@@ -218,6 +237,11 @@ if [ -n "$integration" ]; then
|
|
|
218
237
|
cfg_r autoMergeWork true
|
|
219
238
|
auto_merge="$REPLY"
|
|
220
239
|
[[ "$auto_merge" =~ ^(true|false)$ ]] || { err_t ci.proteger.automerge_invalid; exit 1; }
|
|
240
|
+
# Livraison automatique : merge automatique du dépôt indispensable
|
|
241
|
+
if [ "$DELIVERY" = auto ] && [ "$auto_merge" = false ]; then
|
|
242
|
+
err_t ci.proteger.auto_needs_automerge
|
|
243
|
+
exit 1
|
|
244
|
+
fi
|
|
221
245
|
# Sans ce workflow, les branches mergées ne seraient plus supprimées
|
|
222
246
|
if ! grep -qs "nettoyage-branches.yml" "$GIT_TOPLEVEL"/.github/workflows/*.y*ml; then
|
|
223
247
|
attention_t ci.proteger.no_cleanup
|
|
@@ -228,6 +252,11 @@ if [ -n "$integration" ]; then
|
|
|
228
252
|
! grep -qs "delivery-environment:" "$GIT_TOPLEVEL"/.github/workflows/*.y*ml; then
|
|
229
253
|
attention_t ci.proteger.no_delivery_env "$ENVIRONMENT"
|
|
230
254
|
fi
|
|
255
|
+
# Livraison automatique que rien n'arme : la PR se mergera à la main
|
|
256
|
+
if [ "$DELIVERY" = auto ] &&
|
|
257
|
+
! grep -qsE "^[[:space:]]*delivery-auto:[[:space:]]*true" "$GIT_TOPLEVEL"/.github/workflows/*.y*ml; then
|
|
258
|
+
attention_t ci.proteger.no_delivery_auto
|
|
259
|
+
fi
|
|
231
260
|
# Demande de livraison (manuelle, planifiée) qui ne remplace pas celle en
|
|
232
261
|
# attente : une demande oubliée bloquerait en silence les suivantes
|
|
233
262
|
for wf in "$GIT_TOPLEVEL"/.github/workflows/*.y*ml; do
|
|
@@ -266,6 +295,8 @@ echo_t ci.proteger.3 "$CHECKS"
|
|
|
266
295
|
echo_t ci.proteger.4 "$methods" "$delete_on_merge"
|
|
267
296
|
if [ -n "$integration" ] && [ "$DELIVERY" = deployment ]; then
|
|
268
297
|
echo_t ci.proteger.delivery_deploy "$ENVIRONMENT" "$auto_merge"
|
|
298
|
+
elif [ -n "$integration" ] && [ "$DELIVERY" = auto ]; then
|
|
299
|
+
echo_t ci.proteger.delivery_auto "$livraison"
|
|
269
300
|
elif [ -n "$integration" ]; then
|
|
270
301
|
echo_t ci.proteger.delivery "$livraison" "$auto_merge"
|
|
271
302
|
fi
|
package/bin/tickets
CHANGED
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
# mainteneur → backlog, sinon à valider ; --sans-validation-auto : tous à
|
|
13
13
|
# valider) ; branches des PR ouvertes et mergées inscrites sur leurs tickets.
|
|
14
14
|
# Ensuite : committer ces fichiers, exiger la vérification « ticket »
|
|
15
|
-
# (repowarden proteger --checks "…,ticket") et
|
|
15
|
+
# (repowarden proteger --checks "…,ticket") et, s'il n'y est pas, brancher le
|
|
16
|
+
# job tickets de release.yml (repowarden bots l'y écrit).
|
|
16
17
|
set -euo pipefail
|
|
17
18
|
|
|
18
19
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
|
|
@@ -41,7 +42,7 @@ if [ "$commande" = sync ]; then
|
|
|
41
42
|
exit 0
|
|
42
43
|
fi
|
|
43
44
|
if [ "$commande" != init ]; then
|
|
44
|
-
sed -n '2,
|
|
45
|
+
sed -n '2,16p' "$0" | sed 's/^# \{0,1\}//'
|
|
45
46
|
[ "$commande" = "" ] || [ "$commande" = -h ] || [ "$commande" = --help ]
|
|
46
47
|
exit
|
|
47
48
|
fi
|
|
@@ -149,4 +150,9 @@ esac
|
|
|
149
150
|
|
|
150
151
|
echo
|
|
151
152
|
ok_t tk.init_done
|
|
152
|
-
|
|
153
|
+
# Job tickets de release.yml déjà branché (modèle de repowarden bots) : rien à ajouter
|
|
154
|
+
if grep -qs 'workflows/tickets\.yml@' .github/workflows/release.yml; then
|
|
155
|
+
dim_t tk.init_next_wired
|
|
156
|
+
else
|
|
157
|
+
dim_t tk.init_next
|
|
158
|
+
fi
|
package/ci/tickets/issue.sh
CHANGED
|
@@ -31,27 +31,56 @@ accepter() {
|
|
|
31
31
|
-q '.[] | [.number, .headRefName, .headRefOid, .baseRefName, .isDraft] | @tsv')
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
# Ticket ouvert par un mainteneur (droits d'écriture) : c'est déjà sa
|
|
35
|
+
# décision, validé d'office. Vérifié par tout événement du ticket (idempotent) :
|
|
36
|
+
# GitHub ne garde qu'un run en attente par groupe de concurrence, le run
|
|
37
|
+
# « opened » peut être annulé par ceux des étiquettes posées à la création.
|
|
38
|
+
# Non si déjà validé, ou (hors ouverture) rangé au-delà de « à valider »
|
|
39
|
+
# (« validé » retiré à la main : décision respectée). Test seul : appelé dans un « if », où set -e
|
|
40
|
+
# ne s'applique pas.
|
|
41
|
+
a_valider_d_office() {
|
|
42
|
+
local labels l
|
|
43
|
+
[ "${AUTO_VALIDATE:-maintainers}" = maintainers ] || return 1
|
|
44
|
+
est_mainteneur "${ISSUE_ASSOCIATION:-}" || return 1
|
|
45
|
+
[ "${ISSUE_STATE:-open}" = open ] || return 1
|
|
46
|
+
labels="$(etiquettes "$ISSUE")"
|
|
47
|
+
! grep -qxF "$VALIDE" <<<"$labels" || return 1
|
|
48
|
+
[ "$ACTION" != opened ] || return 0
|
|
49
|
+
while IFS= read -r l; do
|
|
50
|
+
[[ "$l" == "statut: "* && "$l" != "$S_AVALIDER" ]] && return 1
|
|
51
|
+
done <<<"$labels"
|
|
52
|
+
return 0
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
valider_d_office() {
|
|
56
|
+
gh issue edit "$ISSUE" --add-label "$VALIDE" >/dev/null
|
|
57
|
+
statut "$ISSUE" "$S_AVALIDER"
|
|
58
|
+
accepter "$ISSUE"
|
|
59
|
+
}
|
|
60
|
+
|
|
34
61
|
cmd_issue() {
|
|
35
62
|
local pr sha head body
|
|
36
63
|
case "$ACTION" in
|
|
37
64
|
opened)
|
|
38
65
|
est_valide "$ISSUE" && return 0
|
|
39
|
-
#
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
est_mainteneur "${ISSUE_ASSOCIATION:-}"; then
|
|
43
|
-
gh issue edit "$ISSUE" --add-label "$VALIDE" >/dev/null
|
|
44
|
-
statut "$ISSUE" "$S_AVALIDER"
|
|
45
|
-
accepter "$ISSUE"
|
|
66
|
+
# Validé d'office, sinon un mainteneur pose « validé »
|
|
67
|
+
if a_valider_d_office; then
|
|
68
|
+
valider_d_office
|
|
46
69
|
else
|
|
47
70
|
statut "$ISSUE" "$S_AVALIDER"
|
|
48
71
|
fi
|
|
49
72
|
;;
|
|
50
73
|
labeled)
|
|
51
|
-
[ "${LABEL:-}" = "$VALIDE" ]
|
|
52
|
-
|
|
74
|
+
if [ "${LABEL:-}" = "$VALIDE" ]; then
|
|
75
|
+
accepter "$ISSUE"
|
|
76
|
+
elif a_valider_d_office; then
|
|
77
|
+
valider_d_office
|
|
78
|
+
fi
|
|
53
79
|
;;
|
|
54
80
|
assigned)
|
|
81
|
+
if a_valider_d_office; then
|
|
82
|
+
valider_d_office
|
|
83
|
+
fi
|
|
55
84
|
# Pris en charge : sa branche (s'il est validé), en cours s'il est
|
|
56
85
|
# validé ET assigné (quelle que soit la présence du label backlog,
|
|
57
86
|
# pour gérer la race validation+assignation quasi simultanée).
|
package/ci/tickets/push.sh
CHANGED
|
@@ -34,11 +34,32 @@ commit_impact_r() {
|
|
|
34
34
|
REPLY="$meilleur"
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
# REPLY =
|
|
38
|
-
#
|
|
39
|
-
#
|
|
37
|
+
# REPLY = en-tête du premier commit de la branche $1 par rapport à la branche
|
|
38
|
+
# d'intégration, sans « (#N) » final ; vide s'il n'est pas utilisable (aucun
|
|
39
|
+
# commit, non conforme, plus de 72 caractères). Lu par l'API : le checkout du
|
|
40
|
+
# workflow est celui de repowarden, pas l'historique du projet.
|
|
41
|
+
premier_commit_r() {
|
|
42
|
+
local s
|
|
43
|
+
s="$(gh api "repos/$GH_REPO/compare/$INTEGRATION...$1" \
|
|
44
|
+
-q '.commits[0].commit.message // "" | split("\n")[0] // ""' 2>/dev/null || true)"
|
|
45
|
+
s="${s%%$'\n'*}"
|
|
46
|
+
s="${s%$'\r'}"
|
|
47
|
+
[[ "$s" =~ ^(.*[^[:space:]])[[:space:]]+\(#[0-9]+\)$ ]] && s="${BASH_REMATCH[1]}"
|
|
48
|
+
REPLY=""
|
|
49
|
+
[[ "$s" =~ $CC_PATTERN ]] || return 0
|
|
50
|
+
authored_length "$s"
|
|
51
|
+
[ "$REPLY" -le 72 ] || { REPLY=""; return 0; }
|
|
52
|
+
REPLY="$s"
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# REPLY = titre de la PR brouillon du ticket $1 (branche $2) : en-tête du
|
|
56
|
+
# premier commit de la branche (déjà validé par les hooks, il devient le commit
|
|
57
|
+
# de squash), sinon « type(portée): sujet » depuis le ticket, sinon le commit
|
|
58
|
+
# conforme de plus fort impact, sinon le titre déduit de la branche
|
|
40
59
|
titre_pr_brouillon_r() {
|
|
41
60
|
local n="$1" branche="$2" type
|
|
61
|
+
premier_commit_r "$branche"
|
|
62
|
+
[ -z "$REPLY" ] || return 0
|
|
42
63
|
ticket_type_r "$(etiquettes "$n")"
|
|
43
64
|
type="$REPLY"
|
|
44
65
|
ticket_pr_title_r "$type" "$(gh issue view "$n" --json title -q .title)"
|
|
@@ -82,7 +103,8 @@ description_pr_brouillon_r() {
|
|
|
82
103
|
}
|
|
83
104
|
|
|
84
105
|
# Premier push sur la branche d'un ticket : PR brouillon vers la branche
|
|
85
|
-
# d'intégration,
|
|
106
|
+
# d'intégration, titrée par le premier commit (repli : le ticket), à la
|
|
107
|
+
# description reprise du ticket, citant le
|
|
86
108
|
# ticket, assignée à l'auteur du push ; ticket en cours. Ouverte par le jeton
|
|
87
109
|
# des Actions, elle ne lance pas la CI : elle tourne au push suivant, ou au
|
|
88
110
|
# passage « prête pour revue ». Tant qu'elle est en brouillon, chaque push met
|
package/hooks/lib/i18n/en.sh
CHANGED
|
@@ -284,10 +284,15 @@ _msg_en() {
|
|
|
284
284
|
ci.proteger.reviews_invalid) _M="--relecteurs: a number from 0 to 9 is expected." ;;
|
|
285
285
|
ci.proteger.codeowners_invalid) _M="codeOwnerReview: true or false." ;;
|
|
286
286
|
ci.proteger.delivery_deploy) _M=" delivery into main: approval of the \"%s\" deployment (Approve and deploy), then merged by the GitHub App; auto-merge of work PRs into develop: %s" ;;
|
|
287
|
-
ci.proteger.delivery_invalid) _M="deliveryApproval: deployment or
|
|
287
|
+
ci.proteger.delivery_invalid) _M="deliveryApproval: deployment, review or auto." ;;
|
|
288
|
+
ci.proteger.auto_needs_automerge) _M="deliveryApproval = auto needs the repository's auto-merge: remove autoMergeWork = false from .repowarden.conf, or choose deliveryApproval = deployment or review." ;;
|
|
289
|
+
ci.proteger.no_delivery_auto) _M="deliveryApproval = auto, but no workflow calls release-auto.yml with delivery-auto: true: nothing will arm the delivery merge, which will be done by hand (see docs/releases.md, automatic delivery)." ;;
|
|
290
|
+
ci.proteger.delivery_auto) _M=" delivery into main: automatic (the GitHub App merges it as soon as the required checks are green; %s approval(s) required)" ;;
|
|
288
291
|
ci.proteger.automerge_invalid) _M="autoMergeWork: true or false." ;;
|
|
289
292
|
ci.proteger.unattributed_invalid) _M="unattributedApproval: true or false." ;;
|
|
290
293
|
ci.proteger.no_branch) _M="None of the branches \"%s\" exists on %s." ;;
|
|
294
|
+
ci.proteger.no_integration) _M="Integration branch \"%s\" missing on %s: nothing was changed." ;;
|
|
295
|
+
ci.proteger.no_integration_hint) _M=" Create it from the main branch: git push origin %s:refs/heads/%s (or repowarden bots), then run again." ;;
|
|
291
296
|
ci.proteger.no_cleanup) _M="Automatic branch deletion disabled (it would delete develop): add a workflow calling nettoyage-branches.yml, otherwise merged branches remain (see In an organisation)." ;;
|
|
292
297
|
ci.proteger.no_delivery_env) _M="main will require a successful \"%s\" deployment, but no workflow creates that deployment: a deployment nothing creates would block main forever. Call release-auto.yml with delivery-environment (see docs/releases.md, develop flow), or set deliveryApproval = review in .repowarden.conf." ;;
|
|
293
298
|
ci.proteger.stale_concurrency) _M="%s: a pending delivery request (manual or scheduled) would silently block the next ones. Set cancel-in-progress: \${{ github.event_name != 'push' }} (a new request replaces the pending one) and one group per trigger: release-\${{ github.ref_name }}-\${{ github.event.schedule || github.event_name }}." ;;
|
|
@@ -391,19 +396,14 @@ _msg_en() {
|
|
|
391
396
|
npm.old_npm) _M="npm %s is too old: 11.15 or later required (npm install -g npm@11)." ;;
|
|
392
397
|
npm.step_login) _M="1/3 npm account" ;;
|
|
393
398
|
npm.logged) _M="Logged in to npm: %s" ;;
|
|
394
|
-
npm.no_2fa) _M="Two-factor authentication (2FA) is not enabled on the npm account: npm requires it to
|
|
399
|
+
npm.no_2fa) _M="Two-factor authentication (2FA) is not enabled on the npm account: npm requires it to configure tokenless publishing." ;;
|
|
395
400
|
npm.hint_2fa) _M="Enable it: npm profile enable-2fa auth-and-writes (QR code for an authenticator app), or https://www.npmjs.com/settings/%s/tfa; then run this command again." ;;
|
|
396
|
-
npm.
|
|
397
|
-
npm.
|
|
398
|
-
npm.
|
|
399
|
-
npm.
|
|
400
|
-
npm.
|
|
401
|
-
npm.
|
|
402
|
-
npm.dispatched) _M="Pipeline started (%s): it publishes the latest release to npm. Waiting… (Ctrl+C: run the command again later, it resumes)" ;;
|
|
403
|
-
npm.waiting) _M="The next release publishes %s: merge a PR (or let the bot merge the release PR). Waiting… (Ctrl+C: run the command again later, it resumes)" ;;
|
|
404
|
-
npm.still_waiting) _M="still waiting (%s min)…" ;;
|
|
405
|
-
npm.not_yet) _M="Not published yet: run this command again after the next release." ;;
|
|
406
|
-
npm.first_published) _M="%s@%s published by the pipeline." ;;
|
|
401
|
+
npm.step_first) _M="2/3 First publication, from this machine (latest release)" ;;
|
|
402
|
+
npm.no_release) _M="No release yet: nothing is published. Run this command again after the first release of %s." ;;
|
|
403
|
+
npm.would_publish) _M="[dry-run] %s@%s would be published from release %s (npm publish, in this terminal)" ;;
|
|
404
|
+
npm.publishing) _M="Publishing %s@%s (release %s): npm may ask for a validation (browser or code)." ;;
|
|
405
|
+
npm.publish_failed) _M="Publication of %s refused (see above): nothing else was configured. Run this command again." ;;
|
|
406
|
+
npm.first_published) _M="%s@%s published." ;;
|
|
407
407
|
npm.step_trust) _M="3/3 Tokenless publishing (trusted publishing)" ;;
|
|
408
408
|
npm.trust_exists) _M="Trusted publishing already configured." ;;
|
|
409
409
|
npm.trust_mismatch) _M="Existing trust relationship does not match expected parameters:" ;;
|
|
@@ -461,11 +461,18 @@ _msg_en() {
|
|
|
461
461
|
app.server_failed) _M="Local page did not start." ;;
|
|
462
462
|
app.open) _M="Open %s then click GitHub's green button." ;;
|
|
463
463
|
app.no_code) _M="No answer from GitHub (creation cancelled, or 15 min timeout)." ;;
|
|
464
|
+
app.container) _M="Container detected: the local creation page (127.0.0.1) would not be reachable from the host's browser. Nothing was created." ;;
|
|
465
|
+
app.howto) _M="Run the command on the host: %s (or here with REPOWARDEN_CONTENEUR=0 if your browser reaches this container's 127.0.0.1: host network, forwarded port)." ;;
|
|
466
|
+
app.page_timeout) _M="Local page not visited within %s s: stopped, nothing was created." ;;
|
|
467
|
+
app.orphan) _M="If you clicked \"Create\", the App exists without retrieved credentials: delete it (GitHub settings → Developer settings → GitHub Apps) before running again." ;;
|
|
464
468
|
app.created) _M="App %s created; credentials stored (variable %s, secret %s)." ;;
|
|
465
469
|
app.step_install) _M="Installing on the repository" ;;
|
|
466
470
|
app.installed) _M="App %s installed on %s." ;;
|
|
467
471
|
app.not_installed) _M="App %s not installed on %s yet: run repowarden app init again once installed." ;;
|
|
468
|
-
app.
|
|
472
|
+
app.not_verified) _M="Installation of App %s on %s not verified: the private key is not on this machine (only the App can list its installations). If it is not installed, workflows will fail at the \"Jeton de l'App\" step. To install it: %s" ;;
|
|
473
|
+
app.name_taken) _M="A GitHub App named %s already exists (often an orphan App from an interrupted attempt: created on GitHub, credentials never stored)." ;;
|
|
474
|
+
app.name_taken_fix) _M="Either run again with --nom <other name>, or delete the orphan App (Settings → Developer settings → GitHub Apps → the App → Advanced → Delete): %s" ;;
|
|
475
|
+
app.name_hint) _M="If GitHub refuses the name %s (already taken): Ctrl+C, then run again with --nom <other name>, or delete the orphan App: %s" ;;
|
|
469
476
|
app.done) _M="repowarden workflows now use the App: what they do triggers the other workflows." ;;
|
|
470
477
|
app.next) _M="Without the App (variable and secret missing), they fall back to the Actions token." ;;
|
|
471
478
|
app.bot_all_repos) _M="Organization bot: when installing, choose \"All repositories\" (new repositories are covered automatically; only those with a .repowarden.conf are managed)." ;;
|
|
@@ -524,12 +531,27 @@ _msg_en() {
|
|
|
524
531
|
bots.ask_app) _M="GitHub App?" ;;
|
|
525
532
|
bots.ask_proteger) _M="Branch protection?" ;;
|
|
526
533
|
bots.ask_npm) _M="npm publishing?" ;;
|
|
534
|
+
bots.desc_delivery) _M="develop → main delivery: automatic (the GitHub App merges the delivery PR as soon as the checks are green; human validation is the merge of each ticket) or human approval (default)" ;;
|
|
535
|
+
bots.ask_delivery_auto) _M="Automatic delivery? (no: human approval)" ;;
|
|
536
|
+
bots.auto_no_app) _M="Automatic delivery without a GitHub App: the automatic merge requires the App (repowarden app init); without it, the delivery PR has to be merged by hand." ;;
|
|
537
|
+
bots.desc_rythme) _M="Pace: on every ticket (prerelease and delivery request on every merge) or grouped (default: evening prerelease, Friday delivery window)" ;;
|
|
538
|
+
bots.ask_each_ticket) _M="On every ticket? (no: grouped)" ;;
|
|
539
|
+
bots.ask_preversion) _M="Prerelease required before a stable version?" ;;
|
|
527
540
|
bots.preview) _M="Preview" ;;
|
|
528
541
|
bots.prev_develop) _M="branch %s created on GitHub from %s" ;;
|
|
529
542
|
bots.prev_conf) _M=".repowarden.conf: integrationBranch = %s, protected branches" ;;
|
|
530
543
|
bots.prev_review) _M=".repowarden.conf: delivery approved by reviewing its PR (no GitHub App)" ;;
|
|
544
|
+
bots.prev_conf_auto) _M=".repowarden.conf: deliveryApproval = auto (automatic delivery)" ;;
|
|
545
|
+
bots.prev_delivery_auto) _M="release.yml: automatic delivery (delivery-auto), the GitHub App merges the delivery PR as soon as the checks are green" ;;
|
|
546
|
+
bots.prev_delivery_approval) _M="release.yml: delivery approved by a person" ;;
|
|
547
|
+
bots.prev_each_ticket) _M="release.yml: on every ticket, prerelease and delivery request on every merge" ;;
|
|
548
|
+
bots.prev_grouped) _M="release.yml: grouped, evening prerelease, Friday delivery window" ;;
|
|
549
|
+
bots.prev_preversion_on) _M="release.yml: prerelease required before a stable version" ;;
|
|
550
|
+
bots.prev_preversion_off) _M="release.yml: stable version possible without a prerelease (preversion-obligatoire: false)" ;;
|
|
531
551
|
bots.prev_kept) _M="%s exists: kept as is (difference with the template: %s line(s))" ;;
|
|
532
552
|
bots.prev_file) _M="%s: created" ;;
|
|
553
|
+
bots.prev_ci_langs) _M=" CI tooling: %s (strict when formatting and tests have their tools)" ;;
|
|
554
|
+
bots.prev_ci_generic) _M=" language not recognized: generic template, add the project tooling (setup-*) then strict: true" ;;
|
|
533
555
|
bots.prev_tickets) _M="tickets: labels and ticket template on GitHub, tickets.yml workflow" ;;
|
|
534
556
|
bots.prev_app) _M="GitHub App: created in the browser, credentials stored as repository variable and secret" ;;
|
|
535
557
|
bots.prev_proteger) _M="GitHub settings: branch and tag rulesets, merge methods" ;;
|
|
@@ -577,6 +599,7 @@ _msg_en() {
|
|
|
577
599
|
tk.init_auto_create_on) _M="Auto ticket creation: ENABLED (ticketAutoCreate = true)" ;;
|
|
578
600
|
tk.init_auto_create_off) _M="Auto ticket creation: DISABLED (default). To enable: git config repowarden.ticketAutoCreate true" ;;
|
|
579
601
|
tk.init_next) _M="Next: commit these files; require the \"ticket\" check (repowarden proteger --checks \"…,ticket\"); in release.yml, wire the tickets job (see the Tickets docs)." ;;
|
|
602
|
+
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." ;;
|
|
580
603
|
tk.prerelease) _M="Available in pre-release **%s**: to be tested before production." ;;
|
|
581
604
|
tk.released) _M="Released in **%s**." ;;
|
|
582
605
|
# Ticket comment
|
package/hooks/lib/i18n/fr.sh
CHANGED
|
@@ -284,10 +284,15 @@ _msg_fr() {
|
|
|
284
284
|
ci.proteger.reviews_invalid) _M="--relecteurs : nombre de 0 à 9 attendu." ;;
|
|
285
285
|
ci.proteger.codeowners_invalid) _M="codeOwnerReview : true ou false." ;;
|
|
286
286
|
ci.proteger.delivery_deploy) _M=" livraison vers main : approbation du déploiement « %s » (Approve and deploy), puis merge par la GitHub App ; merge automatique des PR de travail vers develop : %s" ;;
|
|
287
|
-
ci.proteger.delivery_invalid) _M="deliveryApproval : deployment ou
|
|
287
|
+
ci.proteger.delivery_invalid) _M="deliveryApproval : deployment, review ou auto." ;;
|
|
288
|
+
ci.proteger.auto_needs_automerge) _M="deliveryApproval = auto demande le merge automatique du dépôt : retirer autoMergeWork = false de .repowarden.conf, ou choisir deliveryApproval = deployment ou review." ;;
|
|
289
|
+
ci.proteger.no_delivery_auto) _M="deliveryApproval = auto, mais aucun workflow n'appelle release-auto.yml avec delivery-auto: true : rien n'armera le merge de la livraison, qui se fera à la main (voir docs/releases.md, livraison automatique)." ;;
|
|
290
|
+
ci.proteger.delivery_auto) _M=" livraison vers main : automatique (la GitHub App la merge dès que les vérifications exigées sont vertes ; %s approbation(s) exigée(s))" ;;
|
|
288
291
|
ci.proteger.automerge_invalid) _M="autoMergeWork : true ou false." ;;
|
|
289
292
|
ci.proteger.unattributed_invalid) _M="unattributedApproval : true ou false." ;;
|
|
290
293
|
ci.proteger.no_branch) _M="Aucune des branches « %s » n'existe sur %s." ;;
|
|
294
|
+
ci.proteger.no_integration) _M="Branche d'intégration « %s » absente de %s : rien n'a été modifié." ;;
|
|
295
|
+
ci.proteger.no_integration_hint) _M=" La créer depuis la branche principale : git push origin %s:refs/heads/%s (ou repowarden bots), puis relancer." ;;
|
|
291
296
|
ci.proteger.no_cleanup) _M="Suppression automatique des branches désactivée (elle supprimerait develop) : ajouter un workflow qui appelle nettoyage-branches.yml, sinon les branches mergées restent (voir En organisation)." ;;
|
|
292
297
|
ci.proteger.no_delivery_env) _M="main exigera un déploiement « %s » réussi, mais aucun workflow ne crée ce déploiement : un déploiement que rien ne crée bloquerait main pour toujours. Appeler release-auto.yml avec delivery-environment (voir docs/releases.md, flux develop), ou deliveryApproval = review dans .repowarden.conf." ;;
|
|
293
298
|
ci.proteger.stale_concurrency) _M="%s : une demande de livraison (manuelle ou planifiée) en attente bloquerait en silence les suivantes. Mettre cancel-in-progress: \${{ github.event_name != 'push' }} (une nouvelle demande remplace celle en attente) et un groupe par déclencheur : release-\${{ github.ref_name }}-\${{ github.event.schedule || github.event_name }}." ;;
|
|
@@ -391,19 +396,14 @@ _msg_fr() {
|
|
|
391
396
|
npm.old_npm) _M="npm %s trop ancien : 11.15 au minimum (npm install -g npm@11)." ;;
|
|
392
397
|
npm.step_login) _M="1/3 Compte npm" ;;
|
|
393
398
|
npm.logged) _M="Connecté à npm : %s" ;;
|
|
394
|
-
npm.no_2fa) _M="Double authentification (2FA) non activée sur le compte npm : npm l'exige pour
|
|
399
|
+
npm.no_2fa) _M="Double authentification (2FA) non activée sur le compte npm : npm l'exige pour configurer la publication sans jeton." ;;
|
|
395
400
|
npm.hint_2fa) _M="Activer : npm profile enable-2fa auth-and-writes (QR code pour une application d'authentification), ou https://www.npmjs.com/settings/%s/tfa ; puis relancer cette commande." ;;
|
|
396
|
-
npm.
|
|
397
|
-
npm.
|
|
398
|
-
npm.
|
|
399
|
-
npm.
|
|
400
|
-
npm.
|
|
401
|
-
npm.
|
|
402
|
-
npm.dispatched) _M="Pipeline lancée (%s) : elle publie la dernière release sur npm. Attente… (Ctrl+C : relancer la commande plus tard, elle reprendra)" ;;
|
|
403
|
-
npm.waiting) _M="La prochaine release publie %s : merge une PR (ou laisse le bot merger la PR de release). Attente… (Ctrl+C : relancer la commande plus tard, elle reprendra)" ;;
|
|
404
|
-
npm.still_waiting) _M="toujours en attente (%s min)…" ;;
|
|
405
|
-
npm.not_yet) _M="Pas encore publié : relance cette commande après la prochaine release." ;;
|
|
406
|
-
npm.first_published) _M="%s@%s publié par la pipeline." ;;
|
|
401
|
+
npm.step_first) _M="2/3 Première publication, depuis ce poste (dernière release)" ;;
|
|
402
|
+
npm.no_release) _M="Aucune release encore : rien n'est publié. Relance cette commande après la première release de %s." ;;
|
|
403
|
+
npm.would_publish) _M="[dry-run] %s@%s serait publié depuis la release %s (npm publish, dans ce terminal)" ;;
|
|
404
|
+
npm.publishing) _M="Publication de %s@%s (release %s) : npm peut demander une validation (navigateur ou code)." ;;
|
|
405
|
+
npm.publish_failed) _M="Publication de %s refusée (voir ci-dessus) : rien d'autre n'a été configuré. Relance cette commande." ;;
|
|
406
|
+
npm.first_published) _M="%s@%s publié." ;;
|
|
407
407
|
npm.step_trust) _M="3/3 Publication sans jeton (publication de confiance)" ;;
|
|
408
408
|
npm.trust_exists) _M="Publication de confiance déjà configurée." ;;
|
|
409
409
|
npm.trust_mismatch) _M="Relation de confiance existante mais ne correspond pas aux paramètres attendus :" ;;
|
|
@@ -461,11 +461,18 @@ _msg_fr() {
|
|
|
461
461
|
app.server_failed) _M="Page locale non démarrée." ;;
|
|
462
462
|
app.open) _M="Ouvre %s puis clique sur le bouton vert de GitHub." ;;
|
|
463
463
|
app.no_code) _M="Aucune réponse de GitHub (création annulée, ou délai de 15 min dépassé)." ;;
|
|
464
|
+
app.container) _M="Conteneur détecté : la page locale de création (127.0.0.1) ne serait pas joignable depuis le navigateur de l'hôte. Rien n'a été créé." ;;
|
|
465
|
+
app.howto) _M="Lance la commande sur l'hôte : %s (ou ici avec REPOWARDEN_CONTENEUR=0 si ton navigateur joint le 127.0.0.1 de ce conteneur : réseau de l'hôte, port redirigé)." ;;
|
|
466
|
+
app.page_timeout) _M="Page locale non consultée en %s s : arrêt, rien n'a été créé." ;;
|
|
467
|
+
app.orphan) _M="Si tu as cliqué « Create », l'App existe sans identifiants récupérés : supprime-la (paramètres GitHub → Developer settings → GitHub Apps) avant de relancer." ;;
|
|
464
468
|
app.created) _M="App %s créée ; identifiants rangés (variable %s, secret %s)." ;;
|
|
465
469
|
app.step_install) _M="Installation sur le dépôt" ;;
|
|
466
470
|
app.installed) _M="App %s installée sur %s." ;;
|
|
467
471
|
app.not_installed) _M="App %s pas encore installée sur %s : relance repowarden app init une fois installée." ;;
|
|
468
|
-
app.
|
|
472
|
+
app.not_verified) _M="Installation de l'App %s sur %s non vérifiée : la clé privée n'est pas sur ce poste (seule l'App peut lister ses installations). Si elle n'est pas installée, les workflows échoueront à l'étape « Jeton de l'App ». L'installer : %s" ;;
|
|
473
|
+
app.name_taken) _M="Une GitHub App s'appelle déjà %s (souvent une App orpheline d'un essai interrompu : créée sur GitHub, identifiants jamais rangés)." ;;
|
|
474
|
+
app.name_taken_fix) _M="Au choix : relancer avec --nom <autre nom>, ou supprimer l'App orpheline (Settings → Developer settings → GitHub Apps → l'App → Advanced → Delete) : %s" ;;
|
|
475
|
+
app.name_hint) _M="Si GitHub refuse le nom %s (déjà utilisé) : Ctrl+C, puis relancer avec --nom <autre nom>, ou supprimer l'App orpheline : %s" ;;
|
|
469
476
|
app.done) _M="Les workflows repowarden utilisent désormais l'App : ce qu'ils font déclenche les autres workflows." ;;
|
|
470
477
|
app.next) _M="Sans l'App (variable et secret absents), ils reprennent le jeton des Actions." ;;
|
|
471
478
|
app.bot_all_repos) _M="Bot d'organisation : à l'installation, choisir « All repositories » (les nouveaux dépôts seront couverts d'office ; seuls ceux avec un .repowarden.conf sont gérés)." ;;
|
|
@@ -524,12 +531,27 @@ _msg_fr() {
|
|
|
524
531
|
bots.ask_app) _M="GitHub App ?" ;;
|
|
525
532
|
bots.ask_proteger) _M="Protection des branches ?" ;;
|
|
526
533
|
bots.ask_npm) _M="Publication npm ?" ;;
|
|
534
|
+
bots.desc_delivery) _M="Livraison develop → main : automatique (la GitHub App merge la PR de livraison dès que les vérifications sont vertes ; la validation humaine est le merge de chaque ticket) ou approbation humaine (défaut)" ;;
|
|
535
|
+
bots.ask_delivery_auto) _M="Livraison automatique ? (non : approbation humaine)" ;;
|
|
536
|
+
bots.auto_no_app) _M="Livraison automatique sans GitHub App : le merge automatique exige l'App (repowarden app init) ; sans elle, la PR de livraison reste à merger à la main." ;;
|
|
537
|
+
bots.desc_rythme) _M="Rythme : à chaque ticket (préversion et demande de livraison à chaque merge) ou regroupé (défaut : préversion le soir, fenêtre de livraison le vendredi)" ;;
|
|
538
|
+
bots.ask_each_ticket) _M="À chaque ticket ? (non : regroupé)" ;;
|
|
539
|
+
bots.ask_preversion) _M="Préversion obligatoire avant une version stable ?" ;;
|
|
527
540
|
bots.preview) _M="Aperçu" ;;
|
|
528
541
|
bots.prev_develop) _M="branche %s créée sur GitHub depuis %s" ;;
|
|
529
542
|
bots.prev_conf) _M=".repowarden.conf : integrationBranch = %s, branches protégées" ;;
|
|
530
543
|
bots.prev_review) _M=".repowarden.conf : livraison validée par la revue de sa PR (sans GitHub App)" ;;
|
|
544
|
+
bots.prev_conf_auto) _M=".repowarden.conf : deliveryApproval = auto (livraison automatique)" ;;
|
|
545
|
+
bots.prev_delivery_auto) _M="release.yml : livraison automatique (delivery-auto), la GitHub App merge la PR de livraison dès que les vérifications sont vertes" ;;
|
|
546
|
+
bots.prev_delivery_approval) _M="release.yml : livraison approuvée par une personne" ;;
|
|
547
|
+
bots.prev_each_ticket) _M="release.yml : à chaque ticket, préversion et demande de livraison à chaque merge" ;;
|
|
548
|
+
bots.prev_grouped) _M="release.yml : regroupé, préversion le soir, fenêtre de livraison le vendredi" ;;
|
|
549
|
+
bots.prev_preversion_on) _M="release.yml : préversion obligatoire avant une version stable" ;;
|
|
550
|
+
bots.prev_preversion_off) _M="release.yml : version stable possible sans préversion (preversion-obligatoire: false)" ;;
|
|
531
551
|
bots.prev_kept) _M="%s existe : gardé tel quel (écart avec le modèle : %s ligne(s))" ;;
|
|
532
552
|
bots.prev_file) _M="%s : créé" ;;
|
|
553
|
+
bots.prev_ci_langs) _M=" outillage de la CI : %s (strict si formatage et tests sont outillés)" ;;
|
|
554
|
+
bots.prev_ci_generic) _M=" langage non reconnu : modèle générique, outillage du projet à ajouter (setup-*) puis strict: true" ;;
|
|
533
555
|
bots.prev_tickets) _M="tickets : étiquettes et modèle de ticket sur GitHub, workflow tickets.yml" ;;
|
|
534
556
|
bots.prev_app) _M="GitHub App : créée dans le navigateur, identifiants rangés en variable et secret du dépôt" ;;
|
|
535
557
|
bots.prev_proteger) _M="réglages GitHub : rulesets des branches et des tags, modes de merge" ;;
|
|
@@ -577,6 +599,7 @@ _msg_fr() {
|
|
|
577
599
|
tk.init_auto_create_on) _M="Création auto de ticket : ACTIVÉE (ticketAutoCreate = true)" ;;
|
|
578
600
|
tk.init_auto_create_off) _M="Création auto de ticket : DÉSACTIVÉE (défaut). Pour l'activer : git config repowarden.ticketAutoCreate true" ;;
|
|
579
601
|
tk.init_next) _M="Ensuite : committer ces fichiers ; exiger la vérification « ticket » (repowarden proteger --checks \"…,ticket\") ; dans release.yml, brancher le job tickets (voir la doc Tickets)." ;;
|
|
602
|
+
tk.init_next_wired) _M="Ensuite : committer ces fichiers ; exiger la vérification « ticket » (repowarden proteger --checks \"…,ticket\"). Le job tickets de release.yml est déjà branché." ;;
|
|
580
603
|
tk.prerelease) _M="Disponible en préversion **%s** : à tester avant la production." ;;
|
|
581
604
|
tk.released) _M="Publié dans **%s**." ;;
|
|
582
605
|
# Ticket comment
|
package/hooks/lib/tickets.sh
CHANGED
|
@@ -63,8 +63,10 @@ ticket_branch_r() {
|
|
|
63
63
|
# REPLY = titre de PR d'un ticket : $1 type (« feat » par défaut), $2 titre du
|
|
64
64
|
# ticket → « feat(portée): sujet ». Portée = préfixe du titre avant le premier
|
|
65
65
|
# « : » (« Tickets : … » → « tickets »), 20 caractères au plus, omise si vide ;
|
|
66
|
-
# sujet = le reste, première lettre abaissée
|
|
67
|
-
#
|
|
66
|
+
# sujet = le reste, première lettre abaissée sauf sur un sigle (README, IA :
|
|
67
|
+
# initiale suivie d'une majuscule). 72 caractères au plus, coupé à la dernière
|
|
68
|
+
# espace, jamais dans un mot. Vide si le titre ne donne rien (l'appelant décide
|
|
69
|
+
# du repli).
|
|
68
70
|
ticket_pr_title_r() {
|
|
69
71
|
local type="${1:-feat}" titre="$2" portee sujet tete res
|
|
70
72
|
sujet="$titre"
|
|
@@ -75,15 +77,17 @@ ticket_pr_title_r() {
|
|
|
75
77
|
[ "${#portee}" -le 20 ] || portee=""
|
|
76
78
|
sujet="${BASH_REMATCH[2]}"
|
|
77
79
|
fi
|
|
78
|
-
|
|
80
|
+
[[ "${sujet:1:1}" == [[:upper:]] ]] ||
|
|
81
|
+
sujet="$(printf '%s' "${sujet:0:1}" | LC_ALL=C tr '[:upper:]' '[:lower:]')${sujet:1}"
|
|
79
82
|
tete="$type${portee:+($portee)}: "
|
|
80
83
|
REPLY=""
|
|
81
84
|
[ -n "$sujet" ] || return 0
|
|
82
85
|
res="$tete$sujet"
|
|
83
|
-
# 72 caractères au plus, coupé sur un mot entier (authored_length → REPLY)
|
|
86
|
+
# 72 caractères au plus, coupé sur un mot entier (authored_length → REPLY) ;
|
|
87
|
+
# un mot seul trop long n'est pas tronqué : titre vide
|
|
84
88
|
authored_length "$res"
|
|
85
89
|
while [ "$REPLY" -gt 72 ] && [ -n "$sujet" ]; do
|
|
86
|
-
if [[ "$sujet" == *" "* ]]; then sujet="${sujet% *}"; else sujet="
|
|
90
|
+
if [[ "$sujet" == *" "* ]]; then sujet="${sujet% *}"; else sujet=""; fi
|
|
87
91
|
res="$tete$sujet"
|
|
88
92
|
authored_length "$res"
|
|
89
93
|
done
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "repowarden",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.9.0-next.10",
|
|
4
4
|
"description": "Hooks git et CI multi-langages : messages de commit, nommage des branches, secrets, formatage, tests ciblés, code mort, releases.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"git-hooks",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"type": "git",
|
|
17
17
|
"url": "git+https://github.com/simdevWarden/repowarden.git"
|
|
18
18
|
},
|
|
19
|
-
"license": "
|
|
19
|
+
"license": "GPL-3.0-or-later",
|
|
20
20
|
"author": "SimBienvenueHoulBoumi (https://github.com/SimBienvenueHoulBoumi)",
|
|
21
21
|
"bin": {
|
|
22
22
|
"repowarden": "bin/repowarden",
|