repowarden 4.4.0-next.7 → 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 +45 -16
- package/bin/commit +2 -2
- 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/lib/i18n/en.sh +41 -0
- package/hooks/lib/i18n/fr.sh +41 -0
- package/hooks/lib/tickets.sh +71 -4
- package/hooks/pre-push +89 -2
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
# repowarden
|
|
2
2
|
|
|
3
|
-
[](https://github.com/simdevWarden/repowarden/actions/workflows/ci.yml)
|
|
4
|
+
[](https://github.com/simdevWarden/repowarden/actions/workflows/e2e.yml)
|
|
5
|
+
[](https://github.com/simdevWarden/repowarden/releases)
|
|
6
6
|
[](https://www.npmjs.com/package/repowarden)
|
|
7
|
-
[](https://
|
|
8
|
-
[](https://simdevwarden.github.io/repowarden/)
|
|
8
|
+
[](https://scorecard.dev/viewer/?uri=github.com/simdevWarden/repowarden)
|
|
9
9
|
[](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://
|
|
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://
|
|
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
|
|
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://
|
|
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/
|
|
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:
|
|
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:
|
|
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/
|
|
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/
|
|
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/
|
|
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://
|
|
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 :
|
|
186
|
-
#
|
|
187
|
-
#
|
|
188
|
-
#
|
|
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"
|
|
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,
|
|
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
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"
|