devzone 0.5.2 → 0.5.3

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.
@@ -3,6 +3,9 @@
3
3
  # clusters Kubernetes, puis récapitulatif de ce qui reste à faire (devzone).
4
4
  # Séquentiel : le récapitulatif voit l'identité tout juste posée ; l'échec
5
5
  # d'une étape n'empêche pas les suivantes.
6
+ # Jamais de question (gh, kubectl et ses plugins d'authentification) : sortie
7
+ # invisible derrière make, une attente bloquerait (voir post-create.sh)
8
+ exec </dev/null
6
9
  ICI="$(dirname "$0")"
7
10
  bash "$ICI/git-identite.sh" || echo "démarrage : identité git non traitée (bash $ICI/git-identite.sh)"
8
11
  bash "$ICI/kube-config.sh" || echo "démarrage : clusters non traités (bash $ICI/kube-config.sh)"
@@ -3,6 +3,12 @@
3
3
  # - volumes montés au démarrage seulement
4
4
  # - npm fourni par la feature node, ajoutée après le Dockerfile
5
5
  set -euo pipefail
6
+ # Jamais de question : le CLI devcontainer lance cette étape sous terminal,
7
+ # sortie envoyée dans .devzone.log par make, donc invisible ; une question
8
+ # (repowarden install propose « repowarden bots » dans un dépôt GitHub dont
9
+ # gh est administrateur) attendrait indéfiniment. Entrée vide : chaque outil
10
+ # passe en mode non interactif (bots : « plus tard, repowarden bots »)
11
+ exec </dev/null
6
12
 
7
13
  # Volumes nommés créés en root → rendre au user vscode
8
14
  # (et ~/.config, créé par Docker pour monter ~/.config/opencode)
package/Makefile CHANGED
@@ -2,10 +2,9 @@
2
2
  DC := npx -y @devcontainers/cli
3
3
  WS := --workspace-folder $(CURDIR)
4
4
  FILTRE := --filter "label=devcontainer.local_folder=$(CURDIR)"
5
- LOG := $(CURDIR)/.devzone.log
6
5
 
7
6
  .DEFAULT_GOAL := help
8
- .PHONY: help hors-conteneur up shell stop down rebuild status test-fonctionnel desinstaller
7
+ .PHONY: help hors-conteneur up shell stop down rebuild status test-fonctionnel test-cli desinstaller
9
8
 
10
9
  # Ces commandes pilotent le conteneur depuis la machine : lancées dans le
11
10
  # conteneur, elles créeraient un devzone dans son Docker interne, sans rien
@@ -19,9 +18,10 @@ hors-conteneur:
19
18
  help: ## Liste les commandes
20
19
  @grep -E '^[a-z-]+:.*## ' $(MAKEFILE_LIST) | awk -F':.*## ' '{printf " make %-16s %s\n", $$1, $$2}'
21
20
 
21
+ # up et rebuild : étapes affichées, journal complet dans .devzone.log, question
22
+ # posée dans le conteneur signalée au lieu d'attendre (lancer.sh)
22
23
  up: hors-conteneur ## Lance le conteneur (le crée si absent)
23
- @$(DC) up $(WS) >$(LOG) 2>&1 && echo "devzone lancé" \
24
- || { tail -15 $(LOG); echo "échec — log complet : .devzone.log"; exit 1; }
24
+ @bash lancer.sh up "$(CURDIR)"
25
25
 
26
26
  shell: hors-conteneur up ## Ouvre un shell dans le conteneur
27
27
  @$(DC) exec $(WS) bash
@@ -35,8 +35,7 @@ down: hors-conteneur ## Supprime le conteneur (volumes, image et Docker interne
35
35
  docker rm -f $$ids >/dev/null && echo "devzone supprimé (désinstallation complète : make desinstaller)"; fi
36
36
 
37
37
  rebuild: hors-conteneur ## Reconstruit de zéro (après modif de .devcontainer/)
38
- @$(DC) up $(WS) --remove-existing-container >$(LOG) 2>&1 && echo "devzone reconstruit" \
39
- || { tail -15 $(LOG); echo "échec — log complet : .devzone.log"; exit 1; }
38
+ @bash lancer.sh rebuild "$(CURDIR)"
40
39
 
41
40
  status: hors-conteneur ## État du conteneur
42
41
  @docker ps -a $(FILTRE) --format '{{.Status}}' | grep . || echo "aucun conteneur"
@@ -44,5 +43,8 @@ status: hors-conteneur ## État du conteneur
44
43
  test-fonctionnel: hors-conteneur ## Tests fonctionnels : devzone isolé, construit puis supprimé (5 à 10 min)
45
44
  @bash test/fonctionnel.sh
46
45
 
46
+ test-cli: hors-conteneur ## Tests de la CLI dans un vrai terminal : devzone isolé, puis supprimé (10 à 15 min)
47
+ @bash test/cli-terminal.sh
48
+
47
49
  desinstaller: hors-conteneur ## Supprime tout ce que devzone a créé, après confirmation (GARDER=connexions : garde les connexions)
48
50
  @GARDER="$(GARDER)" bash desinstaller.sh
package/README.md CHANGED
@@ -70,7 +70,7 @@ Le choix est **propre à chaque utilisateur** et gardé dans le volume `devzone-
70
70
  | État | — | `make status` | — |
71
71
  | **Désinstaller** (tout ce que devzone a créé, après confirmation) | — | `make desinstaller` | `bash desinstaller.sh` |
72
72
 
73
- `make` seul affiche la liste. Les journaux de `up` et `rebuild` vont dans `.devzone.log` ; seule la fin s'affiche en cas d'échec.
73
+ `make` seul affiche la liste. `up` et `rebuild` affichent leurs étapes (construction de l'image, installation, démarrage, puis l'état de devzone) et un signe de vie au moins toutes les 30 s ; le journal complet va dans `.devzone.log` (sa fin s'affiche en cas d'échec). Aucune étape automatique ne pose de question : si l'une le faisait, `make` l'afficherait et s'arrêterait au lieu d'attendre en silence (voir [Dépannage](#dépannage)).
74
74
 
75
75
  > Ne pas lancer `make up` pendant que VS Code ouvre ou reconstruit le conteneur : deux lancements simultanés créent des conteneurs en double.
76
76
 
@@ -198,8 +198,9 @@ Empreinte d'une archive : `curl -fsSL <url> | shasum -a 256`.
198
198
  |---|---|---|---|
199
199
  | Commande `devzone` du conteneur et commande npm (unitaires) | `bats test/` | dans le conteneur | quelques secondes |
200
200
  | Fonctionnels : un devzone construit et utilisé comme par un utilisateur (outils, modules, Kubernetes avec kind, hooks repowarden, redémarrage, rebuild) | `make test-fonctionnel` | sur ta machine (Docker, Node) | 5 à 10 min |
201
+ | CLI dans un vrai terminal : chaque commande tapée comme par un humain (pseudo-terminal), avec un délai maximal ; une commande qui attend une entrée échoue. Cibles `make` (`help`, `up`, `shell`, `status`, `stop`, `down`, `rebuild`, `desinstaller`), commande npm (`devzone <dossier>`, `desinstaller`, `--version`, `--help`), commande `devzone` du conteneur, scripts de démarrage | `make test-cli` | sur ta machine (Docker, Node, Python 3) | 10 à 15 min |
201
202
 
202
- Les tests fonctionnels travaillent sur une copie du dépôt, avec leurs propres volumes (`devzone-test-…`), puis suppriment tout (conteneur, volumes, image), même en cas d'échec : ton devzone, tes connexions et le cluster de ta machine ne sont jamais touchés (seul un cluster kind de test est utilisé). En CI, le workflow `fonctionnel` les lance sur chaque PR qui modifie `.devcontainer/`, `test/` ou le `Makefile`, et à la main (*Actions → fonctionnel → Run workflow*).
203
+ Les tests fonctionnels et ceux de la CLI travaillent sur une copie du dépôt, avec leurs propres volumes (`devzone-test-…`), puis suppriment tout (conteneur, volumes, image), même en cas d'échec : ton devzone, tes connexions et le cluster de ta machine ne sont jamais touchés (seul un cluster kind de test est utilisé). En CI, le workflow `fonctionnel` les lance (deux jobs en parallèle) sur chaque PR qui modifie `.devcontainer/`, `test/`, `bin/`, le `Makefile` ou les scripts `lancer.sh` et `desinstaller.sh`, et à la main (*Actions → fonctionnel → Run workflow*).
203
204
 
204
205
  ## Versions et livraison
205
206
 
@@ -225,6 +226,7 @@ Prérequis de la livraison automatique : la GitHub App du dépôt (`repowarden a
225
226
 
226
227
  | Symptôme | Cause | Solution |
227
228
  |---|---|---|
229
+ | `make up` ou `make rebuild` semble figé | une étape longue (première construction de l'image : plusieurs minutes), ou une question posée dans le conteneur | `make` affiche un signe de vie avec la dernière ligne du journal au moins toutes les 30 s : suivre le détail avec `tail -f .devzone.log`. Une question (ligne finissant par `[o/N]`, `?`…) est signalée et le lancement arrêté : la [signaler](https://github.com/SimBienvenueHoulBoumi/devzone/issues), puis `make rebuild`. Version antérieure de devzone, figée sur « Configurer les bots … ? [o/N] » (invisible) : `Ctrl+C`, mettre devzone à jour puis `make rebuild` ; les bots se configurent à la main dans le conteneur : `repowarden bots` |
228
230
  | `git push` refusé : « refusing to allow an OAuth App to create or update workflow … without `workflow` scope » | jeton `gh` sans la permission `workflow` | `gh auth refresh -h github.com -s workflow` |
229
231
  | PR bloquée, run `action_required`, bandeau « Approve workflows to run » | PR ouverte ou poussée par le bot `github-actions` : pour les événements `pull_request` `opened`, `synchronize` et `reopened`, GitHub attend l'accord d'une personne ayant l'écriture ([doc GitHub](https://docs.github.com/en/actions/how-tos/write-workflows/choose-when-workflows-run/trigger-a-workflow)) | vérifier les changements (surtout `.github/workflows/`), puis *Approve workflows to run* ; pour ne plus avoir à le faire : `repowarden app init` dans le projet |
230
232
  | PR de livraison bloquée : « aucune préversion vX.Y.Z-next.N » | la préversion n'est pas encore publiée (sans `preversion-on-push`, elle part le soir) | attendre celle du soir, *Actions → release → Run workflow* sur `develop`, `preversion-on-push: true`, ou ne plus l'exiger : `preversion-obligatoire: false` |
@@ -249,26 +251,29 @@ devzone/
249
251
  │ ├── devcontainer.json # features (langages, Docker, Kubernetes, gh), volumes, extensions VS Code
250
252
  │ ├── devcontainer-lock.json # versions figées des features
251
253
  │ ├── devzone # commande devzone : modules (ia, kubernetes), versions des assistants IA
252
- │ ├── post-create.sh # premier démarrage : droits des volumes, git, repowarden, modules actifs
254
+ │ ├── post-create.sh # premier démarrage : droits des volumes, git, repowarden, modules actifs (sans question)
253
255
  │ ├── demarrage.sh # chaque démarrage : identité git, clusters, puis récapitulatif (devzone)
254
256
  │ ├── kube-config.sh # contextes kind ; module kubernetes : cluster de l'hôte, metrics-server
255
257
  │ ├── metrics-server.sh # metrics-server sur les clusters locaux (CPU et RAM dans k9s)
256
258
  │ └── git-identite.sh # identité git déduite du compte gh si elle manque
257
259
  ├── .github/workflows/
258
- │ ├── fonctionnel.yml # tests fonctionnels (PR touchant .devcontainer/, test/ ou le Makefile)
260
+ │ ├── fonctionnel.yml # tests fonctionnels et de la CLI sous terminal (PR touchant le conteneur, les tests ou la CLI)
259
261
  │ ├── repowarden.yml # vérifications repowarden de chaque PR (PR mal visée reciblée vers develop)
260
262
  │ ├── tickets.yml # suivi des tickets : branche, PR brouillon, statuts jusqu'à la production
261
263
  │ ├── release.yml # préversions sur develop, livraison develop → main
262
264
  │ └── nettoyage.yml # branches mergées supprimées (main et develop conservées)
263
265
  ├── .repowarden.conf # réglages repowarden : flux develop → main
264
266
  ├── Makefile # pilotage sans VS Code
267
+ ├── lancer.sh # make up / rebuild : étapes affichées, question du conteneur signalée
265
268
  ├── desinstaller.sh # make desinstaller : retire tout ce que devzone a créé
266
269
  ├── bin/devzone # commande npm : npx devzone <dossier>, devzone desinstaller
267
270
  ├── package.json, LICENSE # paquet npm devzone (licence GPL-3.0-only)
268
271
  ├── test/
269
272
  │ ├── devzone.bats # tests de la commande devzone (bats test/)
270
- │ ├── cli.bats # tests de la commande npm et du contenu du paquet
271
- │ └── fonctionnel.sh # tests fonctionnels (make test-fonctionnel)
273
+ │ ├── cli.bats # tests de la commande npm, du contenu du paquet et de lancer.sh
274
+ │ ├── fonctionnel.sh # tests fonctionnels (make test-fonctionnel)
275
+ │ ├── cli-terminal.sh # tests de la CLI dans un vrai terminal (make test-cli)
276
+ │ └── terminal.py # lance une commande sous pseudo-terminal, avec délai maximal
272
277
  └── workspace/ # tes projets (ignorés par git, chacun son dépôt)
273
278
  ```
274
279
 
package/bin/devzone CHANGED
@@ -10,7 +10,7 @@ set -euo pipefail
10
10
 
11
11
  PAQUET="$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}" 2>/dev/null || echo "${BASH_SOURCE[0]}")")/.." && pwd)"
12
12
  # Fichiers d'un devzone (même liste que « files » de package.json, sans bin/)
13
- FICHIERS=(.devcontainer Makefile .gitattributes desinstaller.sh README.md LICENSE)
13
+ FICHIERS=(.devcontainer Makefile .gitattributes lancer.sh desinstaller.sh README.md LICENSE)
14
14
 
15
15
  version() { node -p "require('$PAQUET/package.json').version" 2>/dev/null || echo inconnue; }
16
16
 
@@ -44,7 +44,7 @@ workspace/*
44
44
  .devzone.log
45
45
  .devzone.etat
46
46
  EOF
47
- chmod +x "$cible/desinstaller.sh"
47
+ chmod +x "$cible/desinstaller.sh" "$cible/lancer.sh"
48
48
  cible="$(cd "$cible" && pwd)"
49
49
  echo "✔ devzone $(version) créé dans $cible"
50
50
  if [ -n "${DEVZONE_SANS_DEMARRER:-}" ]; then
@@ -55,11 +55,7 @@ EOF
55
55
  if command -v make >/dev/null 2>&1; then
56
56
  make -C "$cible" up
57
57
  else
58
- npx -y @devcontainers/cli up --workspace-folder "$cible" >"$cible/.devzone.log" 2>&1 || {
59
- tail -15 "$cible/.devzone.log"
60
- echo "✖ échec ; journal : $cible/.devzone.log" >&2
61
- exit 1
62
- }
58
+ bash "$cible/lancer.sh" up "$cible"
63
59
  fi
64
60
  echo "Ensuite : cd $cible && make shell (ou ouvre le dossier dans VS Code : Reopen in Container)."
65
61
  }
package/lancer.sh ADDED
@@ -0,0 +1,132 @@
1
+ #!/usr/bin/env bash
2
+ # Lance le conteneur sur l'hôte, sans jamais rester muet :
3
+ # bash lancer.sh up [dossier] (make up)
4
+ # bash lancer.sh rebuild [dossier] (make rebuild : reconstruit de zéro)
5
+ # Sortie complète du CLI devcontainer dans <dossier>/.devzone.log ; dans le
6
+ # terminal : les étapes clés, un signe de vie au plus toutes les
7
+ # DEVZONE_SIGNE_DE_VIE secondes (30), et une question posée dans le conteneur
8
+ # (dernière ligne du journal restée sans réponse DEVZONE_ATTENTE_QUESTION
9
+ # secondes, 20) est affichée et le lancement arrêté : personne ne peut y
10
+ # répondre (le CLI tourne sans entrée), attendre serait bloquer indéfiniment.
11
+ # Portable : bash 3.2 (macOS) et Linux.
12
+ set -uo pipefail
13
+
14
+ mode="${1:-}"
15
+ DOSSIER="${2:-$PWD}"
16
+ case "$mode" in
17
+ up) options=() fini="devzone lancé" ;;
18
+ rebuild) options=(--remove-existing-container) fini="devzone reconstruit" ;;
19
+ *)
20
+ echo "usage : bash lancer.sh up|rebuild [dossier]" >&2
21
+ exit 2
22
+ ;;
23
+ esac
24
+ LOG="$DOSSIER/.devzone.log"
25
+ VIE="${DEVZONE_SIGNE_DE_VIE:-30}"
26
+ QUESTION="${DEVZONE_ATTENTE_QUESTION:-20}"
27
+ ESC="$(printf '\033')"
28
+
29
+ # Ligne du journal lisible : sans codes de couleur ni retours chariot
30
+ propre() { sed "s/${ESC}\[[0-9;?]*[A-Za-z]//g" | tr -d '\r'; }
31
+ # Dernière ligne non vide du journal, raccourcie
32
+ derniere() { tail -c 2000 "$LOG" | propre | grep -v '^[[:space:]]*$' | tail -1 | cut -c1-110; }
33
+
34
+ # Question en attente : dernière ligne inachevée (sans retour à la ligne,
35
+ # comme une invite) qui finit par [o/N], [y/N], ? ou une demande de mot de passe
36
+ motif='(\[[^]]*/[^]]*\]|\?|[Pp]assword[^:]*:|[Mm]ot de passe[^:]*:)[[:space:]]*$'
37
+ question() {
38
+ local ligne
39
+ # Dernier octet : vide après $( ) si c'est un retour à la ligne
40
+ [ -n "$(tail -c 1 "$LOG")" ] || return 1
41
+ ligne="$(tail -c 600 "$LOG" | propre | tail -1)"
42
+ [[ "$ligne" =~ $motif ]] || return 1
43
+ printf '%s\n' "$ligne" | cut -c1-200
44
+ }
45
+
46
+ # Étapes clés, chacune affichée une fois ; état de devzone recopié tel quel
47
+ vus=" "
48
+ lues=0
49
+ etapes() {
50
+ local total ligne
51
+ total="$(wc -l <"$LOG" | tr -d ' ')"
52
+ [ "$total" -gt "$lues" ] || return 0
53
+ while IFS= read -r ligne; do
54
+ case "$ligne" in
55
+ *"Start: Run: docker buildx build"* | *"Start: Run: docker build"*) annoncer image "Construction de l'image (plusieurs minutes la première fois)" ;;
56
+ *"Start: Run: docker run"*) annoncer conteneur "Création du conteneur" ;;
57
+ *"Running the postCreateCommand"*) annoncer postcreate "Installation dans le conteneur (repowarden, modules)" ;;
58
+ *"Running the postStartCommand"*) annoncer poststart "Démarrage (identité git, clusters, état)" ;;
59
+ "devzone prêt"* | "devzone : "* | " ✔ "* | " ✖ "* | " ○ "* | " ⚠ "* | " "[!\ ]* | "git-identite : "* | "kube-config : "* | "metrics-server : "*)
60
+ echo " $ligne"
61
+ derniere_annonce="$(date +%s)"
62
+ ;;
63
+ esac
64
+ done < <(sed -n "$((lues + 1)),${total}p" "$LOG" | propre)
65
+ lues="$total"
66
+ }
67
+ annoncer() {
68
+ case "$vus" in *" $1 "*) return 0 ;; esac
69
+ vus="$vus$1 "
70
+ echo "▶ $2"
71
+ derniere_annonce="$(date +%s)"
72
+ }
73
+
74
+ arreter() {
75
+ [ -n "${pid:-}" ] || return 0
76
+ pkill -TERM -P "$pid" 2>/dev/null || true
77
+ kill -TERM "$pid" 2>/dev/null || true
78
+ wait "$pid" 2>/dev/null || true
79
+ pid=""
80
+ }
81
+ trap 'arreter; echo; echo "interrompu — journal : .devzone.log"; exit 130' INT TERM
82
+
83
+ : >"$LOG"
84
+ debut="$(date +%s)"
85
+ derniere_annonce="$debut"
86
+ echo "▶ Lancement de devzone (journal complet : .devzone.log)"
87
+ # Entrée vide : le CLI ne relaie rien ; une question posée dans le conteneur
88
+ # resterait sans réponse, d'où sa détection ci-dessous
89
+ npx -y @devcontainers/cli up --workspace-folder "$DOSSIER" ${options[@]+"${options[@]}"} </dev/null >"$LOG" 2>&1 &
90
+ pid=$!
91
+
92
+ taille=0
93
+ calme=0
94
+ while kill -0 "$pid" 2>/dev/null; do
95
+ sleep 1
96
+ t="$(wc -c <"$LOG" | tr -d ' ')"
97
+ if [ "$t" != "$taille" ]; then
98
+ taille="$t"
99
+ calme=0
100
+ etapes
101
+ else
102
+ calme=$((calme + 1))
103
+ fi
104
+ if [ "$calme" -ge "$QUESTION" ] && q="$(question)"; then
105
+ arreter
106
+ echo "✖ Une étape du conteneur pose une question et attend une réponse (journal immobile depuis $calme s) :" >&2
107
+ echo " $q" >&2
108
+ echo " Personne ne peut y répondre ici : lancement arrêté au lieu d'attendre indéfiniment." >&2
109
+ echo " Journal complet : .devzone.log ; signale-le : https://github.com/SimBienvenueHoulBoumi/devzone/issues" >&2
110
+ echo " Le conteneur est peut-être incomplet : make rebuild pour repartir de zéro." >&2
111
+ exit 1
112
+ fi
113
+ maintenant="$(date +%s)"
114
+ if [ $((maintenant - derniere_annonce)) -ge "$VIE" ]; then
115
+ ecoule=$((maintenant - debut))
116
+ info="en cours depuis $((ecoule / 60)) min $((ecoule % 60)) s"
117
+ [ "$calme" -lt "$VIE" ] || info="$info, aucune nouvelle ligne depuis $calme s"
118
+ echo " … $info : $(derniere)"
119
+ derniere_annonce="$maintenant"
120
+ fi
121
+ done
122
+ wait "$pid"
123
+ code=$?
124
+ pid=""
125
+ etapes
126
+ if [ "$code" -eq 0 ]; then
127
+ echo "$fini"
128
+ else
129
+ tail -15 "$LOG" | propre
130
+ echo "échec — log complet : .devzone.log"
131
+ exit 1
132
+ fi
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devzone",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "description": "Zone de dev conteneurisée : Java, Node, Python, Docker, Kubernetes et outils repowarden, dans un devcontainer",
5
5
  "license": "GPL-3.0-only",
6
6
  "repository": {
@@ -24,6 +24,7 @@
24
24
  ".devcontainer/",
25
25
  "Makefile",
26
26
  ".gitattributes",
27
+ "lancer.sh",
27
28
  "desinstaller.sh",
28
29
  "README.md",
29
30
  "LICENSE"