repowarden 4.4.0 → 4.7.0

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 CHANGED
@@ -1,18 +1,18 @@
1
1
  # repowarden
2
2
 
3
- [![CI](https://github.com/SimBienvenueHoulBoumi/repowarden/actions/workflows/ci.yml/badge.svg)](https://github.com/SimBienvenueHoulBoumi/repowarden/actions/workflows/ci.yml)
4
- [![e2e](https://github.com/SimBienvenueHoulBoumi/repowarden/actions/workflows/e2e.yml/badge.svg)](https://github.com/SimBienvenueHoulBoumi/repowarden/actions/workflows/e2e.yml)
5
- [![Release](https://img.shields.io/github/v/release/SimBienvenueHoulBoumi/repowarden)](https://github.com/SimBienvenueHoulBoumi/repowarden/releases)
3
+ [![CI](https://github.com/simdevWarden/repowarden/actions/workflows/ci.yml/badge.svg)](https://github.com/simdevWarden/repowarden/actions/workflows/ci.yml)
4
+ [![e2e](https://github.com/simdevWarden/repowarden/actions/workflows/e2e.yml/badge.svg)](https://github.com/simdevWarden/repowarden/actions/workflows/e2e.yml)
5
+ [![Release](https://img.shields.io/github/v/release/simdevWarden/repowarden)](https://github.com/simdevWarden/repowarden/releases)
6
6
  [![npm](https://img.shields.io/npm/v/repowarden)](https://www.npmjs.com/package/repowarden)
7
- [![Documentation](https://img.shields.io/badge/docs-site-indigo)](https://simbienvenuehoulboumi.github.io/repowarden/)
8
- [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/SimBienvenueHoulBoumi/repowarden/badge)](https://scorecard.dev/viewer/?uri=github.com/SimBienvenueHoulBoumi/repowarden)
7
+ [![Documentation](https://img.shields.io/badge/docs-site-indigo)](https://simdevwarden.github.io/repowarden/)
8
+ [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/simdevWarden/repowarden/badge)](https://scorecard.dev/viewer/?uri=github.com/simdevWarden/repowarden)
9
9
  [![Licence MIT](https://img.shields.io/badge/licence-MIT-blue)](LICENSE)
10
10
 
11
11
  **repowarden** garde l'entrée de vos dépôts Git : messages de commit, nommage des branches, secrets, formatage et tests, **quel que soit le langage** — sur les postes (hooks), en CI (GitHub, GitLab) et côté serveur.
12
12
 
13
- 📖 **Documentation : https://simbienvenuehoulboumi.github.io/repowarden/** · 🇬🇧 **English: https://simbienvenuehoulboumi.github.io/repowarden/en/**
13
+ 📖 **Documentation : https://simdevwarden.github.io/repowarden/** · 🇬🇧 **English: https://simdevwarden.github.io/repowarden/en/**
14
14
 
15
- > **v4 : repogarde devient repowarden** (paquet npm `repowarden`) et lefthook n'est plus pris en charge. Les anciens noms restent lus en v4. Marche à suivre : [Passer à la v4](https://simbienvenuehoulboumi.github.io/repowarden/migration-v4/).
15
+ > **v4 : repogarde devient repowarden** (paquet npm `repowarden`) et lefthook n'est plus pris en charge. Les anciens noms restent lus en v4. Marche à suivre : [Passer à la v4](https://simdevwarden.github.io/repowarden/migration-v4/).
16
16
 
17
17
  ## Ce qu'il fait
18
18
 
@@ -23,9 +23,24 @@
23
23
  - **Tests** : au push et en CI, seulement les projets touchés, sur le commit poussé.
24
24
  - **Code mort** : seul le nouveau code mort est signalé, prouvé (bloquant) ou candidat (à vérifier) ; `repowarden code-mort` en local.
25
25
  - **Tickets** : chaque PR est reliée à un ticket validé (créé automatiquement s'il manque), suivi de « à valider » à « done » à la release ; `repowarden tickets init`.
26
- - **Versions et releases** : les commits étant conventionnels, la version suivante (semver) et le changelog se déduisent de l'historique ; un workflow réutilisable en fait des releases automatiques (PR de release validée par la CI puis mergée, tag, release), sans jeton ni intervention.
26
+ - **Versions et releases** : les commits étant conventionnels, la version suivante (semver) et le changelog se déduisent de l'historique ; un workflow réutilisable en fait des releases automatiques (PR de release validée par la CI puis mergée, tag, release), sans jeton ; dans le flux `develop` → `main`, un clic d'approbation par livraison.
27
27
 
28
- **Plus de 25 technologies** : Java (Maven, Gradle), JavaScript / TypeScript, Python, Go, Rust, PHP, Ruby, .NET, Dart / Flutter, Swift, Elixir, C / C++, Shell, Terraform, Packer, Ansible, Helm, Kubernetes, Docker, GitHub Actions — [détail](https://simbienvenuehoulboumi.github.io/repowarden/technologies/). Linux, macOS, Windows.
28
+ **Plus de 25 technologies** : Java (Maven, Gradle), JavaScript / TypeScript, Python, Go, Rust, PHP, Ruby, .NET, Dart / Flutter, Swift, Elixir, C / C++, Shell, Terraform, Packer, Ansible, Helm, Kubernetes, Docker, GitHub Actions — [détail](https://simdevwarden.github.io/repowarden/technologies/). Linux, macOS, Windows.
29
+
30
+ ## Ce que tu fais à la main
31
+
32
+ Le reste est automatique. Pas à pas et pièges : [où cliquer](https://simdevwarden.github.io/repowarden/validation/#ou-cliquer).
33
+
34
+ | Geste | Où |
35
+ |---|---|
36
+ | Valider un ticket | étiquette `validé` (d'office si un mainteneur l'ouvre) |
37
+ | Écrire la conception, avant le code | commentaire contenant « Conception retenue » sur le ticket |
38
+ | Terminer une PR | **Ready for review** : elle se merge seule quand la CI est verte |
39
+ | Livrer en production (flux `develop`) | *Actions → release → Run workflow* (ou la demande du vendredi), puis **Review deployments → Approve and deploy** sur le run |
40
+ | Livrer un correctif urgent | étiquette `urgent` (à créer si absente) sur la PR `fix/…` |
41
+ | Relire une PR, si exigé | *Files changed → Review changes → Approve* |
42
+
43
+ Une PR `develop` → `main` ouverte à la main ne reçoit jamais d'approbation : lancer le workflow `release`, qui ouvre la sienne.
29
44
 
30
45
  ## Démarrage
31
46
 
@@ -54,9 +69,23 @@ repowarden code-mort # nouveau code mort de ta branche
54
69
  | Mettre à jour | `npm update -g repowarden` (les hooks suivent) |
55
70
  | Désinstaller | `repowarden uninstall --global`, **puis** `npm uninstall -g repowarden` (dans cet ordre : npm n'exécute rien à la désinstallation, les hooks resteraient branchés sur un dossier supprimé) |
56
71
 
57
- Sans Node : `git clone https://github.com/SimBienvenueHoulBoumi/repowarden.git ~/repowarden && ~/repowarden/install.sh --global` (mise à jour : `git -C ~/repowarden pull`).
72
+ Sans Node : `git clone https://github.com/simdevWarden/repowarden.git ~/repowarden && ~/repowarden/install.sh --global` (mise à jour : `git -C ~/repowarden pull`).
73
+
74
+ ### 4. GitHub App pour l'automatisation (merge auto, tickets, releases)
75
+
76
+ Pour que les workflows déclenchent les autres workflows (merge auto, tickets, releases), il faut une GitHub App au lieu du `GITHUB_TOKEN` :
77
+
78
+ ```bash
79
+ repowarden app init
80
+ ```
81
+
82
+ 1. Ouvre la page locale → clique "Create GitHub App" sur GitHub
83
+ 2. Clique "Install" sur ton repo/org
84
+ 3. Les secrets `REPOWARDEN_APP_CLIENT_ID` / `REPOWARDEN_APP_KEY` sont configurés automatiquement
85
+
86
+ Sans cette étape, le `GITHUB_TOKEN` des Actions est utilisé : **ce qu'il fait ne déclenche pas les autres workflows** (merge auto, tickets, préversions).
58
87
 
59
- **Tester la prochaine version** (avant sa sortie en production) : `npm install -g repowarden@next`, ou `uses: SimBienvenueHoulBoumi/repowarden@develop` en CI. Retour à la version stable : `npm install -g repowarden@latest`. Les problèmes se signalent en [issue](https://github.com/SimBienvenueHoulBoumi/repowarden/issues).
88
+ **Tester la prochaine version** (avant sa sortie en production) : `npm install -g repowarden@next`, ou `uses: simdevWarden/repowarden@develop` en CI. Retour à la version stable : `npm install -g repowarden@latest`. Les problèmes se signalent en [issue](https://github.com/simdevWarden/repowarden/issues).
60
89
 
61
90
  ### 2. Dans un projet d'équipe : les mêmes règles pour tous
62
91
 
@@ -71,7 +100,7 @@ L'essentiel des deux fichiers :
71
100
 
72
101
  ```yaml
73
102
  # .github/workflows/repowarden.yml : vérifications de la PR (dernière version 4.x)
74
- - uses: SimBienvenueHoulBoumi/repowarden@v4
103
+ - uses: simdevWarden/repowarden@v4
75
104
  with: { strict: true } # un outil manquant fait échouer la CI
76
105
  ```
77
106
 
@@ -83,22 +112,22 @@ L'essentiel des deux fichiers :
83
112
 
84
113
  Puis rendre la CI obligatoire pour merger : `repowarden proteger` (protection de `main`, check `repowarden` exigé).
85
114
 
86
- Exemple complet : [repowarden-demo](https://github.com/SimBienvenueHoulBoumi/repowarden-demo) · Releases automatiques : [documentation](https://simbienvenuehoulboumi.github.io/repowarden/releases/).
115
+ Exemple complet : [repowarden-demo](https://github.com/simdevWarden/repowarden-demo) · Releases automatiques : [documentation](https://simdevwarden.github.io/repowarden/releases/).
87
116
 
88
117
  ### 3. Contribuer à repowarden
89
118
 
90
119
  ```bash
91
- git clone https://github.com/SimBienvenueHoulBoumi/repowarden.git && cd repowarden
120
+ git clone https://github.com/simdevWarden/repowarden.git && cd repowarden
92
121
  ./install.sh # repowarden se vérifie lui-même (hooks de ce dépôt)
93
122
  bats test/ # tests (bats-core), aussi lancés au push
94
123
  ```
95
124
 
96
125
  Les PR visent `develop` ; `main` ne reçoit que les livraisons, qui déclenchent les releases. Voir [CONTRIBUTING.md](CONTRIBUTING.md).
97
126
 
98
- **Dans VS Code** : l'extension [repowarden-vscode](https://github.com/SimBienvenueHoulBoumi/repowarden-vscode) guide la rédaction des commits, signale une branche mal nommée et des hooks inactifs. En attendant sa publication sur le Marketplace : `.vsix` dans ses [releases](https://github.com/SimBienvenueHoulBoumi/repowarden-vscode/releases), puis `code --install-extension repowarden-X.Y.Z.vsix`.
127
+ **Dans VS Code** : l'extension [repowarden-vscode](https://github.com/simdevWarden/repowarden-vscode) guide la rédaction des commits, signale une branche mal nommée et des hooks inactifs. En attendant sa publication sur le Marketplace : `.vsix` dans ses [releases](https://github.com/simdevWarden/repowarden-vscode/releases), puis `code --install-extension repowarden-X.Y.Z.vsix`.
99
128
 
100
129
  ## Liens
101
130
 
102
- [Démarrage rapide](https://simbienvenuehoulboumi.github.io/repowarden/demarrage/) · [Hooks et règles](https://simbienvenuehoulboumi.github.io/repowarden/hooks/) · [Technologies](https://simbienvenuehoulboumi.github.io/repowarden/technologies/) · [Configuration](https://simbienvenuehoulboumi.github.io/repowarden/configuration/) · [CI](https://simbienvenuehoulboumi.github.io/repowarden/ci/) · [Versions et releases](https://simbienvenuehoulboumi.github.io/repowarden/releases/) · [Validation humaine](https://simbienvenuehoulboumi.github.io/repowarden/validation/) · [Code mort](https://simbienvenuehoulboumi.github.io/repowarden/code-mort/) · [En organisation](https://simbienvenuehoulboumi.github.io/repowarden/industrialisation/) · [Sources internes (Nexus, Artifactory)](https://simbienvenuehoulboumi.github.io/repowarden/industrialisation/#8-sources-internes-reseau-ferme-nexus-artifactory) · [Désinstallation](https://simbienvenuehoulboumi.github.io/repowarden/desinstallation/) · [Sécurité](SECURITY.md) · [Contribuer](CONTRIBUTING.md) · [Changelog](CHANGELOG.md)
131
+ [Démarrage rapide](https://simdevwarden.github.io/repowarden/demarrage/) · [Hooks et règles](https://simdevwarden.github.io/repowarden/hooks/) · [Technologies](https://simdevwarden.github.io/repowarden/technologies/) · [Configuration](https://simdevwarden.github.io/repowarden/configuration/) · [CI](https://simdevwarden.github.io/repowarden/ci/) · [Versions et releases](https://simdevwarden.github.io/repowarden/releases/) · [Validation humaine](https://simdevwarden.github.io/repowarden/validation/) · [Code mort](https://simdevwarden.github.io/repowarden/code-mort/) · [En organisation](https://simdevwarden.github.io/repowarden/industrialisation/) · [Sources internes (Nexus, Artifactory)](https://simdevwarden.github.io/repowarden/industrialisation/#8-sources-internes-reseau-ferme-nexus-artifactory) · [Désinstallation](https://simdevwarden.github.io/repowarden/desinstallation/) · [Sécurité](SECURITY.md) · [Contribuer](CONTRIBUTING.md) · [Changelog](CHANGELOG.md)
103
132
 
104
133
  Licence [MIT](LICENSE).
package/bin/commit CHANGED
@@ -335,9 +335,9 @@ ticket=""
335
335
  branch_ticket_r "$branch"
336
336
  [ -z "$REPLY" ] || ticket="Ticket : #$REPLY"
337
337
  # Branche de travail sans ticket : prévenu, jamais bloqué. Création proposée
338
- # seulement si repowarden gère la vie des tickets du projet (et sans -m)
338
+ # seulement si repowarden gère la vie des tickets du projet ET ticketAutoCreate (et sans -m)
339
339
  if [ -z "$ticket" ] && [ -z "$DRY_RUN" ] && ! skipped tickets && work_branch "$branch"; then
340
- if [ -z "$BATCH" ] && tickets_managed && has gh; then
340
+ if [ -z "$BATCH" ] && tickets_managed && ticket_auto_create && has gh; then
341
341
  t cc.ticket_offer
342
342
  ask_yn "$REPLY" n
343
343
  if [ -n "$YN" ] && n="$(bash "$ROOT/bin/ticket" nouveau "$description" --type "$type" --porcelain)" && [ -n "$n" ]; then
package/bin/pr-checks ADDED
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env bash
2
+ # Vérifier les checks d'une PR
3
+ # repowarden pr checks <n>
4
+ set -euo pipefail
5
+
6
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
7
+ # shellcheck source=../hooks/lib/common.sh
8
+ source "$ROOT/hooks/lib/common.sh"
9
+ # shellcheck source=../hooks/lib/i18n.sh
10
+ source "$ROOT/hooks/lib/i18n.sh"
11
+
12
+ aide() {
13
+ cat <<EOF
14
+ Usage: repowarden pr checks <n>
15
+
16
+ Affiche l'état des checks de la PR #<n>.
17
+
18
+ Exemple:
19
+ repowarden pr checks 123
20
+ EOF
21
+ }
22
+
23
+ [ $# -eq 1 ] || { aide >&2; exit 1; }
24
+ if [[ "$1" == "--help" || "$1" == "-h" ]]; then
25
+ aide
26
+ exit 0
27
+ fi
28
+ command -v gh >/dev/null || { err_t bot.no_gh; exit 1; }
29
+
30
+ n="${1}"
31
+
32
+ step_t pr.checks.checking "$n"
33
+ gh api "repos/{{owner}}/{{repo}}/pulls/$n/check-runs" --jq '.check_runs[] | {name: .name, conclusion: .conclusion, status: .status, url: .html_url}' 2>/dev/null | while IFS= read -r line; do
34
+ echo "$line"
35
+ done
package/bin/pr-label ADDED
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env bash
2
+ # Gérer les labels d'une PR GitHub
3
+ # repowarden pr label <n> <label> [--remove]
4
+ set -euo pipefail
5
+
6
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
7
+ # shellcheck source=../hooks/lib/common.sh
8
+ source "$ROOT/hooks/lib/common.sh"
9
+ # shellcheck source=../hooks/lib/i18n.sh
10
+ source "$ROOT/hooks/lib/i18n.sh"
11
+
12
+ aide() {
13
+ cat <<EOF
14
+ Usage: repowarden pr label <n> <label> [--remove]
15
+
16
+ Ajoute ou retire un label sur la PR #<n>.
17
+
18
+ Options:
19
+ --remove Retire le label au lieu de l'ajouter
20
+
21
+ Exemples:
22
+ repowarden pr label 123 "ready-for-review"
23
+ repowarden pr label 123 "needs-changes" --remove
24
+ EOF
25
+ }
26
+
27
+ [ $# -ge 2 ] || { aide >&2; exit 1; }
28
+ command -v gh >/dev/null || { err_t bot.no_gh; exit 1; }
29
+
30
+ n="${1}"
31
+ label="${2}"
32
+ remove=false
33
+
34
+ shift 2
35
+ while [ $# -gt 0 ]; do
36
+ case "$1" in
37
+ --remove) remove=true ;;
38
+ *) err_t install.unknown_arg "$1"; exit 1 ;;
39
+ esac
40
+ shift
41
+ done
42
+
43
+ if [ "$remove" = true ]; then
44
+ step_t pr.label.removing "$label" "$n"
45
+ gh pr edit "$n" --remove-label "$label"
46
+ ok_t pr.label.removed "$label" "$n"
47
+ else
48
+ step_t pr.label.adding "$label" "$n"
49
+ gh pr edit "$n" --add-label "$label"
50
+ ok_t pr.label.added "$label" "$n"
51
+ fi
package/bin/proteger CHANGED
@@ -11,8 +11,10 @@
11
11
  #
12
12
  # bin/proteger [--repo propriétaire/nom] [--checks "repowarden,tests (ubuntu-latest)"] [--relecteurs N]
13
13
  # [--codeowners] [--environnement NOM] [--approbateurs "login …"]
14
- # [--sans-tags] [--dry-run]
14
+ # [--sans-tags] [--dry-run] [--verifier]
15
15
  # --sans-tags : dépôt qui déplace lui-même un tag (tag majeur flottant v2…).
16
+ # --verifier : compare les règles en ligne à celles attendues, sans rien modifier
17
+ # (après une mise à jour de repowarden ou de .repowarden.conf).
16
18
  # Réglages équivalents dans .repowarden.conf (requiredReviews, codeOwnerReview,
17
19
  # unattributedApproval, deliveryApproval, environment, environmentReviewers). Demande un gh connecté, admin du dépôt.
18
20
  set -euo pipefail
@@ -38,17 +40,20 @@ APPROVERS="$REPLY"
38
40
  REPO=""
39
41
  CHECKS="repowarden"
40
42
  DRY_RUN=""
43
+ VERIFY=""
44
+ CHECKS_SET=""
41
45
  NO_TAGS=""
42
46
  while [ $# -gt 0 ]; do
43
47
  case "$1" in
44
48
  --repo) shift; REPO="${1:?--repo attend propriétaire/nom}" ;;
45
- --checks) shift; CHECKS="${1:?--checks attend une liste}" ;;
49
+ --checks) shift; CHECKS="${1:?--checks attend une liste}"; CHECKS_SET=1 ;;
46
50
  --relecteurs) shift; REVIEWS="${1:?--relecteurs attend un nombre}" ;;
47
51
  --codeowners) CODEOWNERS=true ;;
48
52
  --environnement) shift; ENVIRONMENT="${1:?--environnement attend un nom}" ;;
49
53
  --approbateurs) shift; APPROVERS="${1:?--approbateurs attend des logins}" ;;
50
54
  --sans-tags) NO_TAGS=1 ;;
51
55
  --dry-run) DRY_RUN=1 ;;
56
+ --verifier) VERIFY=1 ;;
52
57
  -h | --help) sed -n '2,18p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
53
58
  *) err_t install.unknown_arg "$1"; exit 1 ;;
54
59
  esac
@@ -58,9 +63,14 @@ done
58
63
  [[ "$REVIEWS" =~ ^[0-9]$ ]] || { err_t ci.proteger.reviews_invalid; exit 1; }
59
64
  [[ "$CODEOWNERS" =~ ^(true|false)$ ]] || { err_t ci.proteger.codeowners_invalid; exit 1; }
60
65
  [[ "$UNATTRIBUTED" =~ ^(true|false)$ ]] || { err_t ci.proteger.unattributed_invalid; exit 1; }
66
+ # Dev solo (une seule personne avec l'écriture) : aucune règle n'exige une
67
+ # autre personne, qui n'existe pas. Nombre inconnu (appel en échec) : pas solo.
68
+ solo=false
69
+ [ "$(gh api "repos/$REPO/collaborators?per_page=100" \
70
+ --jq '[.[] | select(.permissions.push)] | length' 2>/dev/null)" = 1 ] && solo=true
61
71
  # Avec relecture : le dernier à pousser ne peut pas approuver son propre push
62
72
  last_push=false
63
- [ "$REVIEWS" = 0 ] || last_push=true
73
+ [ "$REVIEWS" = 0 ] || [ "$solo" = true ] || last_push=true
64
74
 
65
75
  cfg_r protectedBranches "main master"
66
76
  protected="$REPLY"
@@ -161,8 +171,10 @@ if [ -n "$integration" ]; then
161
171
  # Livraison vers main = passage à une nouvelle version : approbation
162
172
  # humaine obligatoire (la PR de livraison est ouverte par le workflow,
163
173
  # le mainteneur peut donc l'approuver), sans exiger un autre approbateur
164
- # que l'auteur du dernier push sauf si des relectures sont configurées
174
+ # que l'auteur du dernier push sauf si des relectures sont configurées.
175
+ # Dev solo : pas de minimum (l'auteur de la PR ne peut pas l'approuver)
165
176
  livraison=$((REVIEWS > 0 ? REVIEWS : 1))
177
+ [ "$solo" = false ] || livraison="$REVIEWS"
166
178
  # deliveryApproval = deployment (défaut) : la validation humaine est
167
179
  # l'approbation de l'environnement de livraison (« Approve and deploy »),
168
180
  # exigée par une règle de main (déploiement réussi) ; la revue de PR n'est
@@ -182,12 +194,12 @@ if [ -n "$integration" ]; then
182
194
  # release). Une livraison n'apporte que develop, vérifiée par la CI ; le
183
195
  # retour reste fait quand main a un contenu propre (correctif direct).
184
196
  [ -z "$others" ] || rulesets+=("$(branch_ruleset repowarden "$others" '"merge"' false "$livraison" "$last_push" "$deploiement")")
185
- # Branche d'intégration : PR à jour non exigée. Le retour de main (après
186
- # une release) serait sinon presque toujours en retard, et « mettre à jour »
187
- # fusionnerait develop dans main en contournant la livraison ; la CI
188
- # vérifie de toute façon chaque push sur develop.
197
+ # Branche d'intégration : squash seul (un commit par PR de travail, titre =
198
+ # message : les commits intermédiaires n'entrent jamais) ; plus de retour
199
+ # main → develop à merger, seuls develop et ses instantanés livraison/*
200
+ # entrant dans main. PR à jour non exigée : la CI vérifie chaque push.
189
201
  [[ " $existing " != *" $integration "* ]] ||
190
- rulesets+=("$(branch_ruleset "repowarden ($integration)" "$integration" '"squash", "merge"' false)")
202
+ rulesets+=("$(branch_ruleset "repowarden ($integration)" "$integration" '"squash"' false)")
191
203
  merge_commit=true
192
204
  # Nettoyage par le workflow nettoyage-branches (garde une branche encore
193
205
  # source d'une autre PR ouverte)
@@ -202,6 +214,19 @@ if [ -n "$integration" ]; then
202
214
  if ! grep -qs "nettoyage-branches.yml" "$GIT_TOPLEVEL"/.github/workflows/*.y*ml; then
203
215
  attention_t ci.proteger.no_cleanup
204
216
  fi
217
+ # Règle de déploiement sans workflow qui crée ce déploiement : main
218
+ # bloquée pour toujours (la livraison n'aurait jamais d'approbation)
219
+ if [ "$DELIVERY" = deployment ] &&
220
+ ! grep -qs "delivery-environment:" "$GIT_TOPLEVEL"/.github/workflows/*.y*ml; then
221
+ attention_t ci.proteger.no_delivery_env "$ENVIRONMENT"
222
+ fi
223
+ # Demande de livraison (manuelle, planifiée) qui ne remplace pas celle en
224
+ # attente : une demande oubliée bloquerait en silence les suivantes
225
+ for wf in "$GIT_TOPLEVEL"/.github/workflows/*.y*ml; do
226
+ grep -qs "release-auto.yml" "$wf" && grep -qsE "workflow_dispatch|schedule:" "$wf" &&
227
+ grep -qs "cancel-in-progress: false" "$wf" &&
228
+ attention_t ci.proteger.stale_concurrency "${wf#"$GIT_TOPLEVEL"/}"
229
+ done
205
230
  t ci.proteger.methods_flow "$integration"
206
231
  methods="$REPLY"
207
232
  else
@@ -238,6 +263,7 @@ fi
238
263
  echo_t ci.proteger.5 "$tags_msg"
239
264
  [ -z "$integration" ] || echo_t ci.proteger.6 "$integration"
240
265
  echo_t ci.proteger.7 "$REVIEWS" "$CODEOWNERS" "$UNATTRIBUTED"
266
+ [ "$solo" = false ] || echo_t ci.proteger.solo
241
267
  if [ "$REVIEWS" != 0 ] || [ "$CODEOWNERS" = true ]; then
242
268
  echo_t ci.proteger.8
243
269
  fi
@@ -271,6 +297,56 @@ if [ -n "$ENVIRONMENT" ]; then
271
297
  \"deployment_branch_policy\": {\"protected_branches\": false, \"custom_branch_policies\": true}}"
272
298
  echo_t ci.proteger.9 "$ENVIRONMENT" "$APPROVERS"
273
299
  fi
300
+ # Signature des champs posés par ce script : attendue (JSON produit ci-dessus)
301
+ # et en ligne (gh --jq), comparables sans jq ni python
302
+ sig_attendue() {
303
+ local r="$1" deps checks
304
+ deps="$(sed -n 's/.*"required_deployment_environments": \[\(.*\)\].*/\1/p' <<<"$r" | tr -d '" ')"
305
+ checks="$(grep -o '"context": "[^"]*"' <<<"$r" | sed 's/"context": "\(.*\)"/\1/' | LC_ALL=C sort | paste -sd, -)"
306
+ printf 'approbations=%s dernier_push=%s codeowners=%s deploiement=%s verifications=%s' \
307
+ "$(sed -n 's/.*"required_approving_review_count": \([0-9]*\).*/\1/p' <<<"$r")" \
308
+ "$(sed -n 's/.*"require_last_push_approval": \([a-z]*\).*/\1/p' <<<"$r")" \
309
+ "$(sed -n 's/.*"require_code_owner_review": \([a-z]*\).*/\1/p' <<<"$r")" "$deps" "$checks"
310
+ }
311
+ # shellcheck disable=SC2016 # expression jq (gh --jq), pas du shell
312
+ SIG_EN_LIGNE='(.rules | map(select(.type == "pull_request"))[0].parameters) as $p
313
+ | "approbations=\($p.required_approving_review_count) dernier_push=\($p.require_last_push_approval) codeowners=\($p.require_code_owner_review) deploiement=\([.rules[] | select(.type == "required_deployments") | .parameters.required_deployment_environments[]] | join(",")) verifications=\([.rules[] | select(.type == "required_status_checks") | .parameters.required_status_checks[].context] | sort | join(","))"'
314
+
315
+ if [ -n "$VERIFY" ]; then
316
+ ecarts=0
317
+ for ruleset in "${rulesets[@]}"; do
318
+ grep -q '"target": "branch"' <<<"$ruleset" || continue
319
+ name="$(sed -n 's/^ "name": "\(.*\)",$/\1/p' <<<"$ruleset")"
320
+ attendu="$(sig_attendue "$ruleset")"
321
+ id="$(gh api "repos/$REPO/rulesets" --jq ".[] | select(.name == \"$name\") | .id")"
322
+ en_ligne=""
323
+ [ -z "$id" ] || en_ligne="$(gh api "repos/$REPO/rulesets/$id" --jq "$SIG_EN_LIGNE")"
324
+ # Vérifications exigées : comparées seulement si --checks est donné (la
325
+ # liste n'est pas dans .repowarden.conf ; sinon faux écart)
326
+ if [ -z "$CHECKS_SET" ]; then
327
+ attendu="${attendu% verifications=*}"
328
+ en_ligne="${en_ligne% verifications=*}"
329
+ fi
330
+ if [ -z "$en_ligne" ]; then
331
+ err_t ci.proteger.verify_missing "$name"
332
+ ecarts=$((ecarts + 1))
333
+ elif [ "$en_ligne" != "$attendu" ]; then
334
+ err_t ci.proteger.verify_diff "$name" "$en_ligne" "$attendu"
335
+ ecarts=$((ecarts + 1))
336
+ fi
337
+ done
338
+ [ "$ecarts" = 0 ] || { err_t ci.proteger.verify_fix; exit 1; }
339
+ ok_t ci.proteger.verify_ok
340
+ exit 0
341
+ fi
342
+
343
+ # Étiquette « urgent » (flux develop) : son merge lance la demande de livraison
344
+ urgent=""
345
+ if [ -n "$integration" ] && ! gh api "repos/$REPO/labels/urgent" --silent 2>/dev/null; then
346
+ urgent=1
347
+ info_t ci.proteger.urgent
348
+ fi
349
+
274
350
  if [ -n "$DRY_RUN" ]; then
275
351
  printf '%s\n' "${rulesets[@]}"
276
352
  [ -z "$env_json" ] || printf '%s\n' "$env_json"
@@ -311,4 +387,6 @@ if [ -n "$env_json" ]; then
311
387
  done
312
388
  ok_t ci.proteger.12 "$ENVIRONMENT"
313
389
  fi
390
+ [ -z "$urgent" ] || gh label create urgent -R "$REPO" --color B60205 \
391
+ --description "Livraison immédiate après merge" >/dev/null
314
392
  ok_t ci.proteger.13
package/bin/repowarden CHANGED
@@ -8,6 +8,12 @@
8
8
  # repowarden code-mort nouveau code mort de la branche
9
9
  # repowarden ticket <n> branche du ticket (créée, liée, si besoin)
10
10
  # repowarden ticket nouveau "<titre>" nouveau ticket
11
+ # repowarden ticket comment <n> "<texte>" commentaire sur un ticket
12
+ # repowarden ticket label <n> <label> [--remove] gère les labels d'un ticket
13
+ # repowarden pr label <n> <label> [--remove] gère les labels d'une PR
14
+ # repowarden pr checks <n> vérifie les checks d'une PR
15
+ # repowarden run rerun <id|--failed|--workflow> relance un workflow
16
+ # repowarden run list [--workflow <nom>] liste les runs récents
11
17
  # repowarden tickets init suivi des tickets (GitHub)
12
18
  # repowarden proteger [options] protection des branches (GitHub)
13
19
  # repowarden npm-publication publication npm automatique
@@ -29,7 +35,7 @@ source "$ROOT/hooks/lib/ui.sh"
29
35
  # shellcheck source=../hooks/lib/i18n.sh
30
36
  source "$ROOT/hooks/lib/i18n.sh"
31
37
 
32
- aide() { sed -n '2,15p' "$ROOT/bin/repowarden" | sed 's/^# \{0,1\}//'; }
38
+ aide() { sed -n '2,21p' "$ROOT/bin/repowarden" | sed 's/^# \{0,1\}//'; }
33
39
 
34
40
  commande="${1:-}"
35
41
  [ $# -eq 0 ] || shift
@@ -48,6 +54,12 @@ case "$commande" in
48
54
  code-mort | deadcode) exec bash "$ROOT/bin/code-mort" "$@" ;;
49
55
  tickets) exec bash "$ROOT/bin/tickets" "$@" ;;
50
56
  ticket) exec bash "$ROOT/bin/ticket" "$@" ;;
57
+ ticket-comment) exec bash "$ROOT/bin/ticket-comment" "$@" ;;
58
+ ticket-label) exec bash "$ROOT/bin/ticket-label" "$@" ;;
59
+ pr-label) exec bash "$ROOT/bin/pr-label" "$@" ;;
60
+ run-rerun) exec bash "$ROOT/bin/run-rerun" "$@" ;;
61
+ run-list) exec bash "$ROOT/bin/run-list" "$@" ;;
62
+ pr-checks) exec bash "$ROOT/bin/pr-checks" "$@" ;;
51
63
  proteger | protect) exec bash "$ROOT/bin/proteger" "$@" ;;
52
64
  npm-publication | npm-publish) exec bash "$ROOT/bin/npm-publication" "$@" ;;
53
65
  app) exec bash "$ROOT/bin/app" "$@" ;;
package/bin/run-list ADDED
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env bash
2
+ # Lister les runs de workflow GitHub Actions
3
+ # repowarden run list [--workflow <nom>] [--limit N]
4
+ set -euo pipefail
5
+
6
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
7
+ # shellcheck source=../hooks/lib/common.sh
8
+ source "$ROOT/hooks/lib/common.sh"
9
+ # shellcheck source=../hooks/lib/i18n.sh
10
+ source "$ROOT/hooks/lib/i18n.sh"
11
+
12
+ aide() {
13
+ cat <<EOF
14
+ Usage: repowarden run list [--workflow <nom>] [--limit N]
15
+
16
+ Liste les runs de workflows récents.
17
+
18
+ Options:
19
+ --workflow <nom> Filtre par nom de workflow
20
+ --limit N Nombre max de runs (défaut: 20)
21
+
22
+ Exemples:
23
+ repowarden run list
24
+ repowarden run list --workflow "CI" --limit 10
25
+ EOF
26
+ }
27
+
28
+ if [[ "$1" == "--help" || "$1" == "-h" ]]; then
29
+ aide
30
+ exit 0
31
+ fi
32
+ command -v gh >/dev/null || { err_t bot.no_gh; exit 1; }
33
+
34
+ workflow=""
35
+ limit=20
36
+
37
+ while [ $# -gt 0 ]; do
38
+ case "$1" in
39
+ --workflow) shift; workflow="${1:?--workflow attend un nom}" ;;
40
+ --limit) shift; limit="${1:?--limit attend un nombre}" ;;
41
+ *) err_t install.unknown_arg "$1"; exit 1 ;;
42
+ esac
43
+ shift
44
+ done
45
+
46
+ repo="${GH_REPO:-$(gh repo view --json nameWithOwner -q .nameWithOwner)}"
47
+
48
+ if [ -n "$workflow" ]; then
49
+ step_t run.listing.workflow "$workflow"
50
+ gh run list --repo "$repo" --workflow "$workflow" --limit "$limit" \
51
+ --json databaseId,name,conclusion,createdAt,headBranch \
52
+ --template '{{range .}}{{.databaseId}} {{.name}} {{.conclusion}} {{.createdAt}} {{.headBranch}}{{"\n"}}{{end}}'
53
+ else
54
+ step_t run.listing.all
55
+ gh run list --repo "$repo" --limit "$limit" \
56
+ --json databaseId,name,conclusion,createdAt,headBranch \
57
+ --template '{{range .}}{{.databaseId}} {{.name}} {{.conclusion}} {{.createdAt}} {{.headBranch}}{{"\n"}}{{end}}'
58
+ fi
package/bin/run-rerun ADDED
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env bash
2
+ # Relancer un workflow GitHub Actions échoué
3
+ # repowarden run rerun <run-id|--failed|--workflow>
4
+ set -euo pipefail
5
+
6
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
7
+ # shellcheck source=../hooks/lib/common.sh
8
+ source "$ROOT/hooks/lib/common.sh"
9
+ # shellcheck source=../hooks/lib/i18n.sh
10
+ source "$ROOT/hooks/lib/i18n.sh"
11
+
12
+ aide() {
13
+ cat <<EOF
14
+ Usage: repowarden run rerun <run-id|--failed|--workflow <nom>>
15
+
16
+ Relance un workflow GitHub Actions.
17
+
18
+ Options:
19
+ <run-id> ID du run à relancer
20
+ --failed Relance le dernier run échoué du repo
21
+ --workflow <nom> Relance le dernier run du workflow spécifié
22
+
23
+ Exemples:
24
+ repowarden run rerun 123456789
25
+ repowarden run rerun --failed
26
+ repowarden run rerun --workflow "CI"
27
+ EOF
28
+ }
29
+
30
+ [ $# -ge 1 ] || { aide >&2; exit 1; }
31
+ if [[ "$1" == "--help" || "$1" == "-h" ]]; then
32
+ aide
33
+ exit 0
34
+ fi
35
+ command -v gh >/dev/null || { err_t bot.no_gh; exit 1; }
36
+
37
+ arg="${1}"
38
+ run_id=""
39
+
40
+ case "$arg" in
41
+ --failed)
42
+ step_t run.rerun.failed
43
+ run_id=$(gh run list --repo "${GH_REPO:-$(gh repo view --json nameWithOwner -q .nameWithOwner)}" --limit 1 --json databaseId,conclusion --jq '.[] | select(.conclusion=="failure") | .databaseId')
44
+ [ -n "$run_id" ] || { err_t run.rerun.none_failed; exit 1; }
45
+ ;;
46
+ --workflow)
47
+ shift
48
+ workflow="${1:?--workflow attend un nom}"
49
+ step_t run.rerun.workflow "$workflow"
50
+ run_id=$(gh run list --repo "${GH_REPO:-$(gh repo view --json nameWithOwner -q .nameWithOwner)}" --workflow "$workflow" --limit 1 --json databaseId --jq '.[0].databaseId')
51
+ [ -n "$run_id" ] || { err_t run.rerun.none_workflow "$workflow"; exit 1; }
52
+ ;;
53
+ *)
54
+ if [[ "$arg" =~ ^[0-9]+$ ]]; then
55
+ run_id="$arg"
56
+ else
57
+ err_t install.unknown_arg "$arg"
58
+ exit 1
59
+ fi
60
+ ;;
61
+ esac
62
+
63
+ step_t run.rerun.running "$run_id"
64
+ gh run rerun "$run_id"
65
+ ok_t run.rerun.done "$run_id"
package/bin/statut CHANGED
@@ -81,6 +81,7 @@ if [ -n "$GIT_TOPLEVEL" ]; then
81
81
  fi
82
82
  fi
83
83
  info_t st.repo_forge "$FORGE"
84
+ [ "$FORGE" != github ] || dim_t st.repo_rules
84
85
  fi
85
86
 
86
87
  # Outils : secrets, code mort (selon les langages)
package/bin/ticket CHANGED
@@ -5,6 +5,9 @@
5
5
  # repowarden ticket nouveau "<titre>" [--type fix] [--description "…"]
6
6
  # crée le ticket (« à valider » si le suivi
7
7
  # est géré par repowarden, sinon avec sa branche)
8
+ # repowarden ticket comment <n> "<texte>" ajoute un commentaire sur le ticket
9
+ # repowarden ticket label <n> <label> [--remove]
10
+ # gère les labels du ticket
8
11
  # repowarden ticket ticket de la branche courante
9
12
  # Demande un gh connecté (https://cli.github.com).
10
13
  set -euo pipefail
@@ -108,6 +111,8 @@ cmd_nouveau() {
108
111
  case "${1:-}" in
109
112
  -h | --help | help) aide ;;
110
113
  nouveau | new) shift; cmd_nouveau "$@" ;;
114
+ comment) shift; exec bash "$ROOT/bin/ticket-comment" "$@" ;;
115
+ label) shift; exec bash "$ROOT/bin/ticket-label" "$@" ;;
111
116
  "")
112
117
  branche="$(git symbolic-ref --short HEAD 2>/dev/null || echo "")"
113
118
  branch_ticket_r "$branche"
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env bash
2
+ # Ajouter un commentaire sur un ticket GitHub
3
+ # repowarden ticket comment <n> "<texte>"
4
+ set -euo pipefail
5
+
6
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
7
+ # shellcheck source=../hooks/lib/common.sh
8
+ source "$ROOT/hooks/lib/common.sh"
9
+ # shellcheck source=../hooks/lib/i18n.sh
10
+ source "$ROOT/hooks/lib/i18n.sh"
11
+
12
+ aide() {
13
+ cat <<EOF
14
+ Usage: repowarden ticket comment <n> "<texte>"
15
+
16
+ Ajoute un commentaire sur le ticket #<n>.
17
+
18
+ Exemples:
19
+ repowarden ticket comment 123 "Conception retenue : ..."
20
+ repowarden ticket comment 456 "PR prête pour review"
21
+ EOF
22
+ }
23
+
24
+ [ $# -ge 2 ] || { aide >&2; exit 1; }
25
+ command -v gh >/dev/null || { err_t bot.no_gh; exit 1; }
26
+
27
+ n="${1}"
28
+ texte="${2}"
29
+
30
+ step_t tk.comment.adding "$n"
31
+ gh issue comment "$n" --body "$texte"
32
+ ok_t tk.comment.added "$n"