repowarden 4.4.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 +86 -25
- package/bin/commit +12 -6
- package/bin/pr-checks +35 -0
- package/bin/pr-label +51 -0
- package/bin/proteger +87 -9
- package/bin/repowarden +13 -1
- package/bin/run-list +58 -0
- package/bin/run-rerun +65 -0
- package/bin/statut +1 -0
- package/bin/ticket +5 -0
- package/bin/ticket-comment +32 -0
- package/bin/ticket-label +52 -0
- package/bin/tickets +14 -1
- package/ci/tickets/issue.sh +19 -4
- package/ci/tickets/pr.sh +23 -7
- package/ci/tickets/push.sh +95 -13
- package/ci/tickets/registre.sh +19 -0
- package/ci/tickets/release.sh +1 -0
- package/hooks/commit-msg +33 -0
- package/hooks/lib/common.sh +17 -0
- package/hooks/lib/i18n/en.sh +51 -2
- package/hooks/lib/i18n/fr.sh +51 -2
- package/hooks/lib/tickets.sh +73 -5
- package/hooks/lib/ui.sh +21 -1
- package/hooks/pre-push +89 -2
- package/hooks/prepare-commit-msg +4 -1
- package/package.json +4 -4
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." ;;
|
|
@@ -118,6 +126,8 @@ _msg_en() {
|
|
|
118
126
|
hook.pre_push.5) _M="%s: no changed file, nothing to test." ;;
|
|
119
127
|
hook.pre_push.6) _M="Nothing to test (branch deletion only)." ;;
|
|
120
128
|
hook.pre_push.7) _M="Pre-push OK" ;;
|
|
129
|
+
hook.pre_push.lint.missing) _M="%s not installed, %s not checked (install: %s)." ;;
|
|
130
|
+
hook.pre_push.lint.run) _M="%s: %s" ;;
|
|
121
131
|
hook.branch_hint.1) _M="Branch name \"%s\" does not follow the convention: commits and pushes will be refused. Rename:" ;;
|
|
122
132
|
hook.branch_hint.2) _M=" Format <type>/<topic> (e.g. feat/signup); full help on the next commit." ;;
|
|
123
133
|
hook.post_merge.1) _M="🧹 Local branch deleted (merged and deleted on the server): %s" ;;
|
|
@@ -262,6 +272,7 @@ _msg_en() {
|
|
|
262
272
|
ci.proteger.5) _M=" v* tags: %s" ;;
|
|
263
273
|
ci.proteger.6) _M=" default branch: %s" ;;
|
|
264
274
|
ci.proteger.7) _M=" required approvals: %s; CODEOWNERS review: %s; approval of unattributed changes: %s" ;;
|
|
275
|
+
ci.proteger.solo) _M=" solo repository (a single person with write access): no approval by another person required" ;;
|
|
265
276
|
ci.proteger.8) _M=" (admins keep an explicit bypass, recorded in the PR history)" ;;
|
|
266
277
|
ci.proteger.9) _M=" \"%s\" environment: approval by %s; protected branches and v* tags" ;;
|
|
267
278
|
ci.proteger.10) _M="Ruleset \"%s\" updated." ;;
|
|
@@ -276,6 +287,13 @@ _msg_en() {
|
|
|
276
287
|
ci.proteger.unattributed_invalid) _M="unattributedApproval: true or false." ;;
|
|
277
288
|
ci.proteger.no_branch) _M="None of the branches \"%s\" exists on %s." ;;
|
|
278
289
|
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)." ;;
|
|
290
|
+
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." ;;
|
|
291
|
+
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 }}." ;;
|
|
292
|
+
ci.proteger.urgent) _M=" \"urgent\" label created (its merge triggers the delivery request)" ;;
|
|
293
|
+
ci.proteger.verify_missing) _M="%s: ruleset missing online" ;;
|
|
294
|
+
ci.proteger.verify_diff) _M="%s: online rules differ\n online: %s\n expected: %s" ;;
|
|
295
|
+
ci.proteger.verify_fix) _M="Outdated rules: run repowarden proteger again to update them." ;;
|
|
296
|
+
ci.proteger.verify_ok) _M="Online rules up to date." ;;
|
|
279
297
|
ci.proteger.delivery) _M=" delivery into main: %s approval(s) required (moving to a new version); auto-merge of work PRs into develop: %s" ;;
|
|
280
298
|
ci.proteger.methods_flow) _M="main: merge commit; %s: squash or merge commit" ;;
|
|
281
299
|
ci.proteger.tags_org) _M="reserved for workflows" ;;
|
|
@@ -363,6 +381,7 @@ _msg_en() {
|
|
|
363
381
|
st.repo_version_old) _M="The project requires repowarden %s; installed: %s" ;;
|
|
364
382
|
st.repo_version_ok) _M="Version required by the project (%s): met" ;;
|
|
365
383
|
st.repo_forge) _M="Platform: %s" ;;
|
|
384
|
+
st.repo_rules) _M="GitHub rules up to date? repowarden proteger --verifier (read-only)" ;;
|
|
366
385
|
st.tools) _M="Tools present: %s · missing: %s (depending on the projects' languages)" ;;
|
|
367
386
|
st.next) _M="Next step:" ;;
|
|
368
387
|
st.ready) _M="All set: git cc to commit, repowarden code-mort on a branch." ;;
|
|
@@ -403,13 +422,16 @@ _msg_en() {
|
|
|
403
422
|
tk.validated_waiting) _M="Ticket validated, waiting to be taken: its branch will be created when it is assigned, or by taking it yourself with \`repowarden ticket %s\`." ;;
|
|
404
423
|
tk.pr_inverted) _M="PR closed automatically: a PR from \`%s\` to \`%s\` is pointless. A persistent branch only goes out for a delivery (develop → main) or a back-merge (main → develop). To update a work branch: on that branch, \`git merge origin/%s\`, then \`git push\`." ;;
|
|
405
424
|
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." ;;
|
|
425
|
+
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." ;;
|
|
406
426
|
tk.branch_registered) _M="Ticket branch: \`%s\`." ;;
|
|
407
427
|
tk.branch_second) _M="Second branch for this ticket: \`%s\` (already: %s). One ticket, one branch: group the work, or open a separate ticket." ;;
|
|
408
428
|
tk.adopted) _M="Existing tickets: %s sorted, %s branch(es) registered." ;;
|
|
409
429
|
tk.init_adopt) _M="Existing tickets and branches" ;;
|
|
410
430
|
tk.abandoned) _M="Ticket #%s abandoned: PR closed, branch deleted." ;;
|
|
411
431
|
tk.branch_deleted) _M="Branch %s deleted (ticket #%s abandoned)" ;;
|
|
432
|
+
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." ;;
|
|
412
433
|
tk.draft_opened) _M="Draft PR #%s opened for ticket #%s" ;;
|
|
434
|
+
tk.draft_updated) _M="PR #%s (ticket #%s): title and description taken from the ticket" ;;
|
|
413
435
|
tk.created_body) _M="Ticket created automatically for PR #%s, which cited none. To be validated by a maintainer (\"validé\" label)." ;;
|
|
414
436
|
tk.created) _M="Ticket #%s created for PR #%s and linked in its description: to be validated by a maintainer." ;;
|
|
415
437
|
tk.init_labels) _M="Labels (statuses and validation)" ;;
|
|
@@ -417,9 +439,36 @@ _msg_en() {
|
|
|
417
439
|
tk.init_exists) _M="%s already exists: left as is." ;;
|
|
418
440
|
tk.init_written) _M="%s created." ;;
|
|
419
441
|
tk.init_done) _M="Ticket tracking ready." ;;
|
|
442
|
+
tk.init_auto_create_on) _M="Auto ticket creation: ENABLED (ticketAutoCreate = true)" ;;
|
|
443
|
+
tk.init_auto_create_off) _M="Auto ticket creation: DISABLED (default). To enable: git config repowarden.ticketAutoCreate true" ;;
|
|
420
444
|
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)." ;;
|
|
421
445
|
tk.prerelease) _M="Available in pre-release **%s**: to be tested before production." ;;
|
|
422
446
|
tk.released) _M="Released in **%s**." ;;
|
|
447
|
+
# Ticket comment
|
|
448
|
+
tk.comment.adding) _M="Adding comment to ticket #%s..." ;;
|
|
449
|
+
tk.comment.added) _M="Comment added to ticket #%s." ;;
|
|
450
|
+
# Ticket label
|
|
451
|
+
tk.label.adding) _M="Adding label \"%s\" to ticket #%s..." ;;
|
|
452
|
+
tk.label.added) _M="Label \"%s\" added to ticket #%s." ;;
|
|
453
|
+
tk.label.removing) _M="Removing label \"%s\" from ticket #%s..." ;;
|
|
454
|
+
tk.label.removed) _M="Label \"%s\" removed from ticket #%s." ;;
|
|
455
|
+
# PR label
|
|
456
|
+
pr.label.adding) _M="Adding label \"%s\" to PR #%s..." ;;
|
|
457
|
+
pr.label.added) _M="Label \"%s\" added to PR #%s." ;;
|
|
458
|
+
pr.label.removing) _M="Removing label \"%s\" from PR #%s..." ;;
|
|
459
|
+
pr.label.removed) _M="Label \"%s\" removed from PR #%s." ;;
|
|
460
|
+
# Run rerun
|
|
461
|
+
run.rerun.failed) _M="Rerunning last failed run..." ;;
|
|
462
|
+
run.rerun.workflow) _M="Rerunning last run of workflow \"%s\"..." ;;
|
|
463
|
+
run.rerun.running) _M="Rerunning run #%s..." ;;
|
|
464
|
+
run.rerun.done) _M="Run #%s rerun." ;;
|
|
465
|
+
run.rerun.none_failed) _M="No failed run found." ;;
|
|
466
|
+
run.rerun.none_workflow) _M="No run found for workflow \"%s\"." ;;
|
|
467
|
+
# Run list
|
|
468
|
+
run.listing.all) _M="Listing recent runs..." ;;
|
|
469
|
+
run.listing.workflow) _M="Listing runs for workflow \"%s\"..." ;;
|
|
470
|
+
# PR checks
|
|
471
|
+
pr.checks.checking) _M="Checking checks for PR #%s..." ;;
|
|
423
472
|
*) _M="" ;;
|
|
424
473
|
esac
|
|
425
474
|
}
|
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." ;;
|
|
@@ -116,6 +124,8 @@ _msg_fr() {
|
|
|
116
124
|
hook.pre_push.5) _M="%s : aucun fichier modifié, rien à tester." ;;
|
|
117
125
|
hook.pre_push.6) _M="Rien à tester (suppression de branche uniquement)." ;;
|
|
118
126
|
hook.pre_push.7) _M="Pre-push OK" ;;
|
|
127
|
+
hook.pre_push.lint.missing) _M="%s absent, %s non vérifié (installation : %s)." ;;
|
|
128
|
+
hook.pre_push.lint.run) _M="%s : %s" ;;
|
|
119
129
|
hook.branch_hint.1) _M="Nom de branche « %s » non conforme : commits et push seront refusés. Renommer :" ;;
|
|
120
130
|
hook.branch_hint.2) _M=" Format <type>/<sujet> (ex. feat/inscription) ; aide complète au prochain commit." ;;
|
|
121
131
|
hook.post_merge.1) _M="🧹 Branche locale supprimée (mergée et supprimée sur le serveur) : %s" ;;
|
|
@@ -262,6 +272,7 @@ _msg_fr() {
|
|
|
262
272
|
ci.proteger.5) _M=" tags v* : %s" ;;
|
|
263
273
|
ci.proteger.6) _M=" branche par défaut : %s" ;;
|
|
264
274
|
ci.proteger.7) _M=" approbations exigées : %s ; revue des CODEOWNERS : %s ; approbation des changements non attribués : %s" ;;
|
|
275
|
+
ci.proteger.solo) _M=" dépôt solo (une seule personne avec l'écriture) : aucune approbation par une autre personne exigée" ;;
|
|
265
276
|
ci.proteger.8) _M=" (les admins gardent un contournement explicite, tracé dans l'historique de la PR)" ;;
|
|
266
277
|
ci.proteger.9) _M=" environnement « %s » : approbation de %s ; branches protégées et tags v*" ;;
|
|
267
278
|
ci.proteger.10) _M="Ruleset « %s » mis à jour." ;;
|
|
@@ -276,6 +287,13 @@ _msg_fr() {
|
|
|
276
287
|
ci.proteger.unattributed_invalid) _M="unattributedApproval : true ou false." ;;
|
|
277
288
|
ci.proteger.no_branch) _M="Aucune des branches « %s » n'existe sur %s." ;;
|
|
278
289
|
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)." ;;
|
|
290
|
+
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." ;;
|
|
291
|
+
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 }}." ;;
|
|
292
|
+
ci.proteger.urgent) _M=" étiquette « urgent » créée (son merge lance la demande de livraison)" ;;
|
|
293
|
+
ci.proteger.verify_missing) _M="%s : ruleset absent en ligne" ;;
|
|
294
|
+
ci.proteger.verify_diff) _M="%s : règles en ligne différentes\n en ligne : %s\n attendu : %s" ;;
|
|
295
|
+
ci.proteger.verify_fix) _M="Règles périmées : relancer repowarden proteger pour les mettre à jour." ;;
|
|
296
|
+
ci.proteger.verify_ok) _M="Règles en ligne à jour." ;;
|
|
279
297
|
ci.proteger.delivery) _M=" livraison vers main : %s approbation(s) exigée(s) (passage à une nouvelle version) ; merge automatique des PR de travail vers develop : %s" ;;
|
|
280
298
|
ci.proteger.methods_flow) _M="main : merge commit ; %s : squash ou merge commit" ;;
|
|
281
299
|
ci.proteger.tags_org) _M="réservés aux workflows" ;;
|
|
@@ -363,6 +381,7 @@ _msg_fr() {
|
|
|
363
381
|
st.repo_version_old) _M="Le projet demande repowarden %s ; installé : %s" ;;
|
|
364
382
|
st.repo_version_ok) _M="Version demandée par le projet (%s) : respectée" ;;
|
|
365
383
|
st.repo_forge) _M="Plateforme : %s" ;;
|
|
384
|
+
st.repo_rules) _M="Règles GitHub à jour ? repowarden proteger --verifier (lecture seule)" ;;
|
|
366
385
|
st.tools) _M="Outils présents : %s · absents : %s (selon les langages des projets)" ;;
|
|
367
386
|
st.next) _M="Étape suivante :" ;;
|
|
368
387
|
st.ready) _M="Tout est prêt : git cc pour commiter, repowarden code-mort sur une branche." ;;
|
|
@@ -403,13 +422,16 @@ _msg_fr() {
|
|
|
403
422
|
tk.validated_waiting) _M="Ticket validé, en attente d'être pris : sa branche sera créée à l'assignation, ou en le prenant soi-même avec \`repowarden ticket %s\`." ;;
|
|
404
423
|
tk.pr_inverted) _M="PR fermée automatiquement : une PR de \`%s\` vers \`%s\` est sans objet. Une branche persistante ne part que pour une livraison (develop → main) ou un retour (main → develop). Pour mettre une branche de travail à jour : sur cette branche, \`git merge origin/%s\`, puis \`git push\`." ;;
|
|
405
424
|
tk.pr_backmerge_empty) _M="PR fermée automatiquement : \`%s\` n'apporte aucun contenu à \`%s\`. Le retour est fait automatiquement après une release, seulement quand il y a quelque chose à rapporter." ;;
|
|
425
|
+
tk.pr_delivery_manual) _M="PR fermée automatiquement : la livraison \`%s\` → \`%s\` est ouverte par le workflow de release ; une PR ouverte à la main n'aurait jamais d'approbation de déploiement. Lancer *Actions → release → Run workflow* sur \`%s\` (ou \`gh workflow run release.yml --ref %s\`), puis **Approve and deploy** sur le run." ;;
|
|
406
426
|
tk.branch_registered) _M="Branche du ticket : \`%s\`." ;;
|
|
407
427
|
tk.branch_second) _M="Seconde branche pour ce ticket : \`%s\` (déjà : %s). Un ticket, une branche : regrouper le travail, ou ouvrir un ticket séparé." ;;
|
|
408
428
|
tk.adopted) _M="Tickets existants : %s rangé(s), %s branche(s) inscrite(s)." ;;
|
|
409
429
|
tk.init_adopt) _M="Tickets et branches existants" ;;
|
|
410
430
|
tk.abandoned) _M="Ticket #%s abandonné : PR fermée, branche supprimée." ;;
|
|
411
431
|
tk.branch_deleted) _M="Branche %s supprimée (ticket #%s abandonné)" ;;
|
|
432
|
+
tk.branch_kept) _M="Branche \`%s\` gardée : %s commit(s) absent(s) de la branche d'intégration, PR ouverte(s) : %s. À supprimer à la main si le travail est ailleurs." ;;
|
|
412
433
|
tk.draft_opened) _M="PR #%s ouverte en brouillon pour le ticket #%s" ;;
|
|
434
|
+
tk.draft_updated) _M="PR #%s (ticket #%s) : titre et description repris du ticket" ;;
|
|
413
435
|
tk.created_body) _M="Ticket créé automatiquement pour la PR #%s, qui n'en citait aucun. À valider par un mainteneur (étiquette « validé »)." ;;
|
|
414
436
|
tk.created) _M="Ticket #%s créé pour la PR #%s et relié à sa description : à valider par un mainteneur." ;;
|
|
415
437
|
tk.init_labels) _M="Étiquettes (statuts et validation)" ;;
|
|
@@ -417,9 +439,36 @@ _msg_fr() {
|
|
|
417
439
|
tk.init_exists) _M="%s existe déjà : laissé tel quel." ;;
|
|
418
440
|
tk.init_written) _M="%s créé." ;;
|
|
419
441
|
tk.init_done) _M="Suivi des tickets prêt." ;;
|
|
442
|
+
tk.init_auto_create_on) _M="Création auto de ticket : ACTIVÉE (ticketAutoCreate = true)" ;;
|
|
443
|
+
tk.init_auto_create_off) _M="Création auto de ticket : DÉSACTIVÉE (défaut). Pour l'activer : git config repowarden.ticketAutoCreate true" ;;
|
|
420
444
|
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)." ;;
|
|
421
445
|
tk.prerelease) _M="Disponible en préversion **%s** : à tester avant la production." ;;
|
|
422
446
|
tk.released) _M="Publié dans **%s**." ;;
|
|
447
|
+
# Ticket comment
|
|
448
|
+
tk.comment.adding) _M="Ajout d'un commentaire sur le ticket #%s..." ;;
|
|
449
|
+
tk.comment.added) _M="Commentaire ajouté au ticket #%s." ;;
|
|
450
|
+
# Ticket label
|
|
451
|
+
tk.label.adding) _M="Ajout du label « %s » sur le ticket #%s..." ;;
|
|
452
|
+
tk.label.added) _M="Label « %s » ajouté au ticket #%s." ;;
|
|
453
|
+
tk.label.removing) _M="Retrait du label « %s » du ticket #%s..." ;;
|
|
454
|
+
tk.label.removed) _M="Label « %s » retiré du ticket #%s." ;;
|
|
455
|
+
# PR label
|
|
456
|
+
pr.label.adding) _M="Ajout du label « %s » sur la PR #%s..." ;;
|
|
457
|
+
pr.label.added) _M="Label « %s » ajouté à la PR #%s." ;;
|
|
458
|
+
pr.label.removing) _M="Retrait du label « %s » de la PR #%s..." ;;
|
|
459
|
+
pr.label.removed) _M="Label « %s » retiré de la PR #%s." ;;
|
|
460
|
+
# Run rerun
|
|
461
|
+
run.rerun.failed) _M="Relance du dernier run échoué..." ;;
|
|
462
|
+
run.rerun.workflow) _M="Relance du dernier run du workflow « %s »..." ;;
|
|
463
|
+
run.rerun.running) _M="Relance du run #%s..." ;;
|
|
464
|
+
run.rerun.done) _M="Run #%s relancé." ;;
|
|
465
|
+
run.rerun.none_failed) _M="Aucun run échoué trouvé." ;;
|
|
466
|
+
run.rerun.none_workflow) _M="Aucun run trouvé pour le workflow « %s »." ;;
|
|
467
|
+
# Run list
|
|
468
|
+
run.listing.all) _M="Liste des runs récents..." ;;
|
|
469
|
+
run.listing.workflow) _M="Liste des runs du workflow « %s »..." ;;
|
|
470
|
+
# PR checks
|
|
471
|
+
pr.checks.checking) _M="Vérification des checks de la PR #%s..." ;;
|
|
423
472
|
*) _M="" ;;
|
|
424
473
|
esac
|
|
425
474
|
}
|
package/hooks/lib/tickets.sh
CHANGED
|
@@ -24,21 +24,73 @@ branch_ticket_r() {
|
|
|
24
24
|
if [[ "$1" =~ ^[a-z]+/([0-9]+)(-|$) ]]; then REPLY="${BASH_REMATCH[1]}"; fi
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
# $1 → sans accents (un à un : les classes [àâ] sont fausses en locale C) ;
|
|
28
|
+
# les autres caractères sont conservés, le nettoyage reste à l'appelant
|
|
29
|
+
sans_accents() {
|
|
30
|
+
printf '%s' "$1" | sed -e 's/à/a/g' -e 's/â/a/g' -e 's/ä/a/g' -e 's/é/e/g' -e 's/è/e/g' -e 's/ê/e/g' -e 's/ë/e/g' -e 's/î/i/g' -e 's/ï/i/g' -e 's/ô/o/g' -e 's/ö/o/g' -e 's/ù/u/g' -e 's/û/u/g' -e 's/ü/u/g' -e 's/ç/c/g' -e 's/œ/oe/g' -e 's/æ/ae/g' -e 's/À/a/g' -e 's/Â/a/g' -e 's/Ä/a/g' -e 's/É/e/g' -e 's/È/e/g' -e 's/Ê/e/g' -e 's/Ë/e/g' -e 's/Î/i/g' -e 's/Ï/i/g' -e 's/Ô/o/g' -e 's/Ö/o/g' -e 's/Ù/u/g' -e 's/Û/u/g' -e 's/Ü/u/g' -e 's/Ç/c/g' -e 's/Œ/oe/g' -e 's/Æ/ae/g'
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
# Mots vides qu'un nom de branche (ou une portée) ne garde pas en fin de coupe :
|
|
34
|
+
# « …-garde-la-trace-de » → « …-garde-la-trace »
|
|
35
|
+
MOTS_VIDES="a au aux de des du en et l la le les of on ou par pour sur the to un une"
|
|
36
|
+
|
|
37
|
+
# $1 (minuscules, tirets) → sans ses mots vides finaux
|
|
38
|
+
sans_mots_vides() {
|
|
39
|
+
local slug="$1" mot
|
|
40
|
+
while [[ "$slug" == *-* ]]; do
|
|
41
|
+
mot="${slug##*-}"
|
|
42
|
+
[[ " $MOTS_VIDES " == *" $mot "* ]] || break
|
|
43
|
+
slug="${slug%-*}"
|
|
44
|
+
done
|
|
45
|
+
printf '%s' "$slug"
|
|
46
|
+
}
|
|
47
|
+
|
|
27
48
|
# REPLY = nom de branche d'un ticket : $1 numéro, $2 titre, $3 type (feat
|
|
28
49
|
# par défaut) → feat/12-ajoute-le-panier (minuscules, sans accents, 40
|
|
29
|
-
# caractères
|
|
50
|
+
# caractères au plus, coupé sur un tiret puis sur un mot entier)
|
|
30
51
|
ticket_branch_r() {
|
|
31
52
|
local n="$1" titre="$2" type="${3:-feat}" slug
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
LC_ALL=C tr '[:upper:]' '[:lower:]' | LC_ALL=C sed -e 's/[^a-z0-9]\{1,\}/-/g' -e 's/^-//' -e 's/-$//')"
|
|
53
|
+
slug="$(sans_accents "$titre" | LC_ALL=C tr '[:upper:]' '[:lower:]' |
|
|
54
|
+
LC_ALL=C sed -e 's/[^a-z0-9]\{1,\}/-/g' -e 's/^-//' -e 's/-$//')"
|
|
35
55
|
if [ "${#slug}" -gt 40 ]; then
|
|
36
56
|
slug="${slug:0:40}"
|
|
37
57
|
[[ "$slug" == *-* ]] && slug="${slug%-*}"
|
|
38
58
|
fi
|
|
59
|
+
slug="$(sans_mots_vides "$slug")"
|
|
39
60
|
REPLY="$type/$n${slug:+-$slug}"
|
|
40
61
|
}
|
|
41
62
|
|
|
63
|
+
# REPLY = titre de PR d'un ticket : $1 type (« feat » par défaut), $2 titre du
|
|
64
|
+
# ticket → « feat(portée): sujet ». Portée = préfixe du titre avant le premier
|
|
65
|
+
# « : » (« Tickets : … » → « tickets »), 20 caractères au plus, omise si vide ;
|
|
66
|
+
# sujet = le reste, première lettre abaissée. 72 caractères au plus, coupé sur
|
|
67
|
+
# un mot entier. Vide si le titre ne donne rien (l'appelant décide du repli).
|
|
68
|
+
ticket_pr_title_r() {
|
|
69
|
+
local type="${1:-feat}" titre="$2" portee sujet tete res
|
|
70
|
+
sujet="$titre"
|
|
71
|
+
portee=""
|
|
72
|
+
if [[ "$titre" =~ ^([^:]{1,30})[[:space:]]*:[[:space:]]+(.+)$ ]]; then
|
|
73
|
+
portee="$(sans_accents "${BASH_REMATCH[1]}" | LC_ALL=C tr '[:upper:]' '[:lower:]' |
|
|
74
|
+
LC_ALL=C sed -e 's/[^a-z0-9._-]\{1,\}/-/g' -e 's/^-//' -e 's/-$//')"
|
|
75
|
+
[ "${#portee}" -le 20 ] || portee=""
|
|
76
|
+
sujet="${BASH_REMATCH[2]}"
|
|
77
|
+
fi
|
|
78
|
+
sujet="$(printf '%s' "${sujet:0:1}" | LC_ALL=C tr '[:upper:]' '[:lower:]')${sujet:1}"
|
|
79
|
+
tete="$type${portee:+($portee)}: "
|
|
80
|
+
REPLY=""
|
|
81
|
+
[ -n "$sujet" ] || return 0
|
|
82
|
+
res="$tete$sujet"
|
|
83
|
+
# 72 caractères au plus, coupé sur un mot entier (authored_length → REPLY)
|
|
84
|
+
authored_length "$res"
|
|
85
|
+
while [ "$REPLY" -gt 72 ] && [ -n "$sujet" ]; do
|
|
86
|
+
if [[ "$sujet" == *" "* ]]; then sujet="${sujet% *}"; else sujet="${sujet%?}"; fi
|
|
87
|
+
res="$tete$sujet"
|
|
88
|
+
authored_length "$res"
|
|
89
|
+
done
|
|
90
|
+
[ -n "$sujet" ] || res=""
|
|
91
|
+
REPLY="$res"
|
|
92
|
+
}
|
|
93
|
+
|
|
42
94
|
# REPLY = type de branche d'après les étiquettes d'un ticket (une par ligne) :
|
|
43
95
|
# « type: fix », « bug » → fix ; feat par défaut
|
|
44
96
|
ticket_type_r() {
|
|
@@ -90,6 +142,21 @@ tickets_managed() {
|
|
|
90
142
|
[ "$TICKETS_MANAGED" = oui ]
|
|
91
143
|
}
|
|
92
144
|
|
|
145
|
+
# Vrai si la création automatique de ticket est activée : réglage
|
|
146
|
+
# ticketAutoCreate = true (défaut false)
|
|
147
|
+
TICKET_AUTO_CREATE=""
|
|
148
|
+
ticket_auto_create() {
|
|
149
|
+
if [ -z "$TICKET_AUTO_CREATE" ]; then
|
|
150
|
+
TICKET_AUTO_CREATE=non
|
|
151
|
+
cfg_r ticketAutoCreate ""
|
|
152
|
+
case "$REPLY" in
|
|
153
|
+
true | oui | yes) TICKET_AUTO_CREATE=oui ;;
|
|
154
|
+
false | non | no | "") ;;
|
|
155
|
+
esac
|
|
156
|
+
fi
|
|
157
|
+
[ "$TICKET_AUTO_CREATE" = oui ]
|
|
158
|
+
}
|
|
159
|
+
|
|
93
160
|
# Branche de travail sans ticket : avertissement, jamais bloquant. Création
|
|
94
161
|
# proposée seulement si repowarden gère la vie des tickets du projet (et que
|
|
95
162
|
# gh est là pour la faire) ; sinon, comment faire taire l'avertissement.
|
|
@@ -101,7 +168,8 @@ ticket_hint() {
|
|
|
101
168
|
[ -z "$REPLY" ] || return 0
|
|
102
169
|
attention_t tk.cli.no_ticket "$branch"
|
|
103
170
|
if tickets_managed && has gh; then
|
|
104
|
-
|
|
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
|
|
105
173
|
else
|
|
106
174
|
dim_t tk.cli.silence
|
|
107
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/pre-push
CHANGED
|
@@ -46,8 +46,6 @@ if ! skipped protect-branch; then
|
|
|
46
46
|
done <<<"$REFS"
|
|
47
47
|
fi
|
|
48
48
|
|
|
49
|
-
skipped tests && { info "Tests désactivés (repowarden.skip)."; exit 0; }
|
|
50
|
-
|
|
51
49
|
REMOTE="${1:-origin}"
|
|
52
50
|
|
|
53
51
|
# Fichiers modifiés par le push de <sha> : depuis l'état distant connu, ou pour
|
|
@@ -68,6 +66,95 @@ changed_files() {
|
|
|
68
66
|
fi
|
|
69
67
|
}
|
|
70
68
|
|
|
69
|
+
# Linting des fichiers modifiés (shellcheck, actionlint, etc.) : ce que la CI
|
|
70
|
+
# refusera doit être vu avant le push. Désactivable avec repowarden.skip lint.
|
|
71
|
+
if ! skipped lint; then
|
|
72
|
+
# Sévérité shellcheck : warning (défaut), error, style. Config : repowarden.lintSeverity.
|
|
73
|
+
cfg_r lintSeverity warning
|
|
74
|
+
LINT_SEVERITY="$REPLY"
|
|
75
|
+
|
|
76
|
+
# Commande d'installation suggérée selon l'OS
|
|
77
|
+
lint_install_cmd() {
|
|
78
|
+
case "$1" in
|
|
79
|
+
shellcheck)
|
|
80
|
+
case "${OSTYPE:-}" in
|
|
81
|
+
darwin*) printf 'brew install shellcheck' ;;
|
|
82
|
+
linux*) printf 'apt-get install shellcheck' ;;
|
|
83
|
+
msys*|cygwin*|win*) printf 'choco install shellcheck' ;;
|
|
84
|
+
*) printf 'https://www.shellcheck.net/' ;;
|
|
85
|
+
esac
|
|
86
|
+
;;
|
|
87
|
+
actionlint)
|
|
88
|
+
case "${OSTYPE:-}" in
|
|
89
|
+
darwin*) printf 'brew install actionlint' ;;
|
|
90
|
+
linux*) printf 'go install github.com/rhysd/actionlint/cmd/actionlint@latest' ;;
|
|
91
|
+
msys*|cygwin*|win*) printf 'scoop install actionlint' ;;
|
|
92
|
+
*) printf 'https://github.com/rhysd/actionlint' ;;
|
|
93
|
+
esac
|
|
94
|
+
;;
|
|
95
|
+
*) printf '%s' "$1" ;;
|
|
96
|
+
esac
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
# Vrai si le fichier $1 est un script shell (extension .sh/.bash ou shebang)
|
|
100
|
+
is_shell_script() {
|
|
101
|
+
local file="$1" first_line
|
|
102
|
+
case "$file" in
|
|
103
|
+
*.sh|*.bash) return 0 ;;
|
|
104
|
+
esac
|
|
105
|
+
# Pas d'extension reconnue : on lit la 1re ligne (shebang)
|
|
106
|
+
IFS= read -r first_line <"$file" 2>/dev/null || return 1
|
|
107
|
+
case "$first_line" in
|
|
108
|
+
'#!/bin/sh'|'#!/bin/bash'|'#!/usr/bin/env sh'|'#!/usr/bin/env bash'|'#!/usr/bin/env -S bash'*)
|
|
109
|
+
return 0 ;;
|
|
110
|
+
esac
|
|
111
|
+
return 1
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
lint_changed_files() {
|
|
115
|
+
local changed_file rc=0
|
|
116
|
+
# Les checks optionnels (style, info) ne sont activés que si la sévérité le demande
|
|
117
|
+
local shellcheck_opts="--severity=$LINT_SEVERITY"
|
|
118
|
+
case "$LINT_SEVERITY" in
|
|
119
|
+
style|info) shellcheck_opts="$shellcheck_opts -o all" ;;
|
|
120
|
+
esac
|
|
121
|
+
while IFS= read -r changed_file; do
|
|
122
|
+
[ -f "$changed_file" ] || continue
|
|
123
|
+
if is_shell_script "$changed_file"; then
|
|
124
|
+
if has shellcheck; then
|
|
125
|
+
step_t hook.pre_push.lint.run "shellcheck" "$changed_file"
|
|
126
|
+
# shellcheck disable=SC2086
|
|
127
|
+
shellcheck $shellcheck_opts "$changed_file" || rc=1
|
|
128
|
+
else
|
|
129
|
+
local install_cmd; install_cmd="$(lint_install_cmd shellcheck)"
|
|
130
|
+
warn_t hook.pre_push.lint.missing "shellcheck" "$changed_file" "$install_cmd"
|
|
131
|
+
[ -n "${REPOWARDEN_WARN_FILE:-}" ] && return 1
|
|
132
|
+
fi
|
|
133
|
+
elif case "$changed_file" in .github/workflows/*.yml|.github/workflows/*.yaml) true;; *) false;; esac; then
|
|
134
|
+
if has actionlint; then
|
|
135
|
+
step_t hook.pre_push.lint.run "actionlint" "$changed_file"
|
|
136
|
+
actionlint "$changed_file" || rc=1
|
|
137
|
+
else
|
|
138
|
+
local install_cmd; install_cmd="$(lint_install_cmd actionlint)"
|
|
139
|
+
warn_t hook.pre_push.lint.missing "actionlint" "$changed_file" "$install_cmd"
|
|
140
|
+
[ -n "${REPOWARDEN_WARN_FILE:-}" ] && return 1
|
|
141
|
+
fi
|
|
142
|
+
fi
|
|
143
|
+
done
|
|
144
|
+
return "$rc"
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
LINT_FAILED=0
|
|
148
|
+
while read -r _ local_sha _ remote_sha; do
|
|
149
|
+
# suppression de branche : rien à lint
|
|
150
|
+
if [ -z "$local_sha" ] || [[ "$local_sha" =~ ^0+$ ]]; then continue; fi
|
|
151
|
+
changed_files "$local_sha" "$remote_sha" | lint_changed_files || LINT_FAILED=1
|
|
152
|
+
done <<<"$REFS"
|
|
153
|
+
[ "$LINT_FAILED" -eq 0 ] || exit 1
|
|
154
|
+
fi
|
|
155
|
+
|
|
156
|
+
skipped tests && { info "Tests désactivés (repowarden.skip)."; exit 0; }
|
|
157
|
+
|
|
71
158
|
run_tests_for() { test_projects <"$1"; }
|
|
72
159
|
|
|
73
160
|
TESTED=""
|
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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "repowarden",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.7.1",
|
|
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",
|
|
@@ -10,11 +10,11 @@
|
|
|
10
10
|
"ci",
|
|
11
11
|
"release"
|
|
12
12
|
],
|
|
13
|
-
"homepage": "https://
|
|
14
|
-
"bugs": "https://github.com/
|
|
13
|
+
"homepage": "https://simdevwarden.github.io/repowarden/",
|
|
14
|
+
"bugs": "https://github.com/simdevWarden/repowarden/issues",
|
|
15
15
|
"repository": {
|
|
16
16
|
"type": "git",
|
|
17
|
-
"url": "git+https://github.com/
|
|
17
|
+
"url": "git+https://github.com/simdevWarden/repowarden.git"
|
|
18
18
|
},
|
|
19
19
|
"license": "MIT",
|
|
20
20
|
"author": "SimBienvenueHoulBoumi (https://github.com/SimBienvenueHoulBoumi)",
|