[DTP-Worker] Sprint 1 · CI/CD Gitea Actions (gate qualité 4Big · DevOps)
Débloque le dernier livrable DevOps Sprint 1 authorable en-repo (GAP §7). - .gitea/workflows/ci.yml : pipeline Gitea Actions (Gitea ONLY, jamais GitHub) 4 jobs : constraints-guard · validate-json · check-docs · gate agrégat. - ci/guard_constraints.sh : enforce contraintes NON-NÉGOCIABLES CLAUDE.md (GitHub/GitLab/Bitbucket #2 · EspoCRM/HubSpot #3 · Stripe #10 · /var/www/html/static · git clean · remote non-Gitea). Heuristique zéro faux positif (ignore lignes de prohibition) + escape ci-allow. - ci/validate_json.sh : parse strict schémas Faisabilité↔Publiciste. - ci/check_docs.sh : liens Markdown internes [HARD] + auto-score 4Big [SOFT]. - ci/README.md : doc pipeline + procédure enregistrement act_runner (VPS/DevOps). - GAP_ANALYSIS §7 : critère CI/CD Gitea Actions -> done (runner VPS restant). Validé localement : 3 scripts verts (exit 0) sans faux positif ; test négatif (hubspot+github.com) -> guard exit 1 correct. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
# ============================================================================
|
||||
# CI · OTO Enterprise OS DTP · Gitea Actions
|
||||
# ----------------------------------------------------------------------------
|
||||
# Gate qualité DevOps (roadmap Sprint 1 · GAP_ANALYSIS §7).
|
||||
# Plateforme : Gitea Actions UNIQUEMENT (CLAUDE.md #2 · JAMAIS GitHub).
|
||||
# Runner : act_runner enregistré sur le VPS avec le label « ubuntu-latest ».
|
||||
# Voir ci/README.md pour l'enregistrement du runner.
|
||||
# Aucune dépendance réseau/marketplace externe hors actions/checkout.
|
||||
# ============================================================================
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
constraints-guard:
|
||||
name: Contraintes NON-NÉGOCIABLES (CLAUDE.md)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Guard des contraintes
|
||||
run: bash ci/guard_constraints.sh
|
||||
|
||||
validate-json:
|
||||
name: Validation JSON (schémas Faisabilité)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Valider les JSON
|
||||
run: bash ci/validate_json.sh
|
||||
|
||||
check-docs:
|
||||
name: Qualité documentaire (liens + 4Big)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Contrôle docs
|
||||
run: bash ci/check_docs.sh
|
||||
|
||||
gate:
|
||||
name: Gate qualité (agrégat)
|
||||
runs-on: ubuntu-latest
|
||||
needs: [constraints-guard, validate-json, check-docs]
|
||||
steps:
|
||||
- name: Résultat
|
||||
run: echo "✅ Gate qualité 4Big franchi — tous les checks verts."
|
||||
@@ -199,7 +199,7 @@ Chaque item confirmé lève le marqueur **⚠ à confirmer VPS** correspondant.
|
||||
| Critère | Responsable | Statut |
|
||||
|---|---|---|
|
||||
| Repo Gitea mandat live + fichiers poussés | DevOps | ⚠ à confirmer VPS |
|
||||
| CI/CD Gitea Actions configuré | DevOps | ☐ à faire |
|
||||
| CI/CD Gitea Actions configuré | DevOps | ✅ `.gitea/workflows/ci.yml` + `ci/` (guard contraintes · JSON · docs) — ⚠ enregistrement runner VPS restant |
|
||||
| **Gap analysis complète** | Tous / ce doc | ✅ **présent document** |
|
||||
| Template faisabilité canonique v1.0 | Faisabilité | ✅ `faisabilite/TEMPLATE_FAISABILITE_CANONIQUE_v1.0.md` (+ schémas) |
|
||||
| Baseline Playwright (`/crm` `/waf-home` `/qa` `/choisir-mon-unite`) | QA | ☐ à faire |
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
# Daily Report · 2026-07-30 · Claude Code DTP Worker
|
||||
|
||||
**Session** : `20260730_002624`
|
||||
|
||||
## Tâche exécutée
|
||||
**Sprint 1 · Livrable DevOps « CI/CD Gitea Actions »**
|
||||
(roadmap `04_roadmap/ROADMAP_8_WEEKS_OR_LESS.md` §Sprint 1 · GAP_ANALYSIS_SPRINT1 §7 = `☐ à faire`).
|
||||
|
||||
## Contexte / analyse
|
||||
- Relu `CLAUDE.md`, `ROADMAP_8_WEEKS_OR_LESS.md`, `GAP_ANALYSIS_SPRINT1.md`, daily report 2026-07-29, AGENT.md DevOps + QA.
|
||||
- **Sprint 1 non terminé.** Critères de sortie restants (§7) authorables **dans ce repo sans toucher au VPS** :
|
||||
1. **CI/CD Gitea Actions** (DevOps · marqué *PRIORITÉ S1* · gate qualité qui conditionne tous les sprints).
|
||||
2. Baseline Playwright (QA) — dépend des endpoints VPS pour s'exécuter réellement.
|
||||
- Priorité évidente : **CI/CD Gitea Actions** — 100 % authorable en-repo, débloque le gate qualité 4Big, déjà signalé comme prochaine tâche par la session précédente.
|
||||
|
||||
## Réalisé
|
||||
- Créé `.gitea/workflows/ci.yml` : pipeline Gitea Actions (push/PR `main` + `workflow_dispatch`), 4 jobs → `constraints-guard`, `validate-json`, `check-docs`, `gate` agrégat. Zéro dépendance marketplace hors `actions/checkout`. **Gitea Actions uniquement** (contrainte #2, jamais GitHub).
|
||||
- Créé `ci/guard_constraints.sh` : enforce les contraintes NON-NÉGOCIABLES de CLAUDE.md — GitHub/GitLab/Bitbucket (#2), EspoCRM/HubSpot (#3), Stripe (#10), écriture `/var/www/html/static/`, `git clean`, remote git non-Gitea. **Heuristique zéro faux positif** : ignore les lignes portant un marqueur de prohibition (`jamais`/`❌`/`only`/`interdit`…) + escape hatch `ci-allow`.
|
||||
- Créé `ci/validate_json.sh` : parse strict de tous les `*.json` suivis (contrat Faisabilité↔Publiciste).
|
||||
- Créé `ci/check_docs.sh` : liens Markdown internes cassés [HARD] + présence auto-score 4Big [SOFT].
|
||||
- Créé `ci/README.md` : doc pipeline + exécution locale + **procédure d'enregistrement du runner Gitea** (act_runner, à exécuter côté VPS par DevOps).
|
||||
- Mis à jour `GAP_ANALYSIS_SPRINT1.md` §7 : critère « CI/CD Gitea Actions » → ✅ (runner VPS restant à confirmer).
|
||||
|
||||
## Vérifications effectuées (dans le repo, sans toucher au VPS)
|
||||
- Les 3 scripts passent au **vert (exit 0)** sur l'état actuel du repo — aucun faux positif sur le texte de politique de CLAUDE.md/AGENT.md.
|
||||
- **Test négatif** : fichier de violation temporaire (`hubspot` + `github.com`) → guard retourne **exit 1** et pointe les 2 violations, en ignorant correctement les lignes de prohibition. Fichier de test retiré (repo propre).
|
||||
- `git remote -v` = Gitea (`gitea.otov7.com`) → conforme #2.
|
||||
|
||||
## Non fait (hors périmètre worker · touche au VPS)
|
||||
- Enregistrement de l'`act_runner` Gitea (label `ubuntu-latest`) → DevOps sur VPS (procédure dans `ci/README.md` §4).
|
||||
- Activation de Gitea Actions au niveau instance + repo → DevOps.
|
||||
- Baseline Playwright QA (`/crm`, `/waf-home`, `/qa`, `/choisir-mon-unite`) → nécessite endpoints VPS.
|
||||
|
||||
## Note de convention
|
||||
Rapport écrit dans `05_deliverables_mvp/daily_reports/` (chemin canonique fixé roadmap l.92 + session précédente) plutôt que `05_activity_log/`, pour éviter un doublon (workflow #5).
|
||||
|
||||
## Prochaine tâche suggérée
|
||||
- QA S1 : fichiers Playwright baseline (`tests/e2e/`) — authorables en-repo, exécution différée VPS.
|
||||
- Ou Faisabilité S2/S3 : scaffold doc du générateur 4 volets automatique consommant le template v1.0.
|
||||
- Ou Publiciste S2 : scaffold doc `otoia/capabilities/publiciste.py` (seul module net-neuf, chemin critique).
|
||||
|
||||
---
|
||||
|
||||
**Auto-score 4Big du livrable CI/CD : 96/100.** Réserve −4 : runner Gitea à enregistrer sur VPS (DevOps) avant exécution serveur ; scripts validés localement.
|
||||
@@ -0,0 +1,95 @@
|
||||
# CI/CD · OTO Enterprise OS DTP · Gitea Actions
|
||||
|
||||
> **Livrable Sprint 1** (roadmap `04_roadmap/ROADMAP_8_WEEKS_OR_LESS.md` §Sprint 1 · DevOps)
|
||||
> _« CI/CD Gitea Actions »_ — gate qualité qui conditionne tous les sprints suivants.
|
||||
>
|
||||
> **Plateforme : Gitea Actions UNIQUEMENT** (CLAUDE.md contrainte #2 · JAMAIS GitHub).
|
||||
|
||||
---
|
||||
|
||||
## 1. Ce que fait le pipeline
|
||||
|
||||
Workflow : `.gitea/workflows/ci.yml`. Déclenché sur `push` / `pull_request` vers `main`
|
||||
et manuellement (`workflow_dispatch`). Quatre jobs :
|
||||
|
||||
| Job | Script | Rôle | Blocant |
|
||||
|---|---|---|---|
|
||||
| `constraints-guard` | `ci/guard_constraints.sh` | Enforce les contraintes NON-NÉGOCIABLES de CLAUDE.md | ✅ oui |
|
||||
| `validate-json` | `ci/validate_json.sh` | Parse strict de tous les `*.json` (schémas Faisabilité↔Publiciste) | ✅ oui |
|
||||
| `check-docs` | `ci/check_docs.sh` | Liens Markdown internes + présence auto-score 4Big | ✅ oui (liens) |
|
||||
| `gate` | — | Agrégat vert = gate qualité 4Big franchi | ✅ oui |
|
||||
|
||||
Aucune dépendance réseau/marketplace hors `actions/checkout`. Tout tourne avec
|
||||
`bash` + `git` + `python3` (déjà présents sur un runner standard).
|
||||
|
||||
## 2. Détail des contrôles
|
||||
|
||||
### `guard_constraints.sh` — contraintes NON-NÉGOCIABLES
|
||||
Détecte l'**usage** (pas la simple mention) de :
|
||||
- Plateformes git interdites : `github.com`, `gitlab.com`, `bitbucket.org` (#2).
|
||||
- CRM interdits : `EspoCRM`, `HubSpot` (#3).
|
||||
- Paiement interdit : `Stripe` (#10 · Cardnet only).
|
||||
- Écriture directe dans `/var/www/html/static/` (Interdit absolu).
|
||||
- Commande `git clean` (Interdit absolu).
|
||||
- Remote git pointant ailleurs que Gitea/interne.
|
||||
|
||||
**Zéro faux positif** : une ligne contenant un marqueur de prohibition
|
||||
(`jamais`, `❌`, `only`, `pas de`, `interdit`…) est un rappel de règle → ignorée.
|
||||
Escape hatch documenté : ajouter `ci-allow` sur une ligne pour l'exclure.
|
||||
|
||||
### `validate_json.sh`
|
||||
Parse chaque `*.json` suivi (dont `version.schema.json` et
|
||||
`projets_master.schema.json`, contrat de données Faisabilité → Publiciste).
|
||||
Un JSON cassé casse le pipeline aval → attrapé ici.
|
||||
|
||||
### `check_docs.sh`
|
||||
- **[HARD]** liens Markdown relatifs internes : la cible doit exister.
|
||||
- **[SOFT]** livrables `05_deliverables_mvp/*.md` : mention d'auto-score 4Big
|
||||
attendue (≥95/100, CLAUDE.md #5). Avertissement seul, non blocant.
|
||||
|
||||
## 3. Exécution locale (avant push)
|
||||
|
||||
```bash
|
||||
bash ci/guard_constraints.sh # contraintes CLAUDE.md
|
||||
bash ci/validate_json.sh # schémas JSON
|
||||
bash ci/check_docs.sh # liens + score
|
||||
```
|
||||
|
||||
Chaque script retourne `0` si conforme, `1` sinon. Reproduit exactement ce que
|
||||
fait la CI (mêmes scripts, aucune logique cachée côté YAML).
|
||||
|
||||
## 4. Enregistrement du runner Gitea (ops · à faire sur le VPS)
|
||||
|
||||
> ⚠ Étape **hors périmètre de ce worker** (touche au VPS). À réaliser par
|
||||
> l'agent DevOps. Documenté ici pour traçabilité.
|
||||
|
||||
Le workflow cible un runner avec le label `ubuntu-latest`. Sur le VPS Gitea
|
||||
(`:3015`), enregistrer un `act_runner` :
|
||||
|
||||
```bash
|
||||
# Sur le VPS, récupérer le token runner :
|
||||
# Gitea → Site Administration → Actions → Runners → Create new Runner
|
||||
act_runner register \
|
||||
--instance http://153.75.250.214:3015 \
|
||||
--token <RUNNER_TOKEN> \
|
||||
--labels ubuntu-latest:docker://node:20-bookworm \
|
||||
--name oto-dtp-runner
|
||||
act_runner daemon # ou service systemd dédié
|
||||
```
|
||||
|
||||
Vérifier ensuite : Gitea → repo `michel/oto-enterprise-os-dtp` → **Settings →
|
||||
Actions** doit être activé, et le runner doit apparaître « Idle ».
|
||||
|
||||
## 5. Checklist de vérification (DevOps, sur VPS)
|
||||
|
||||
- `[ ]` Gitea Actions activé au niveau instance ET repo.
|
||||
- `[ ]` `act_runner` enregistré, label `ubuntu-latest`, statut Idle.
|
||||
- `[ ]` Push de test → les 4 jobs apparaissent et passent au vert.
|
||||
- `[ ]` PR de test avec violation volontaire → `constraints-guard` bloque (rouge).
|
||||
|
||||
---
|
||||
|
||||
**Auto-score 4Big du livrable : 96/100.** _Réserve −4_ : l'enregistrement du
|
||||
runner (§4) est hors périmètre repo et reste à confirmer sur le VPS par DevOps ;
|
||||
tant que le runner n'est pas Idle, la CI ne s'exécute pas côté serveur bien que
|
||||
les scripts soient validés localement.
|
||||
Executable
+60
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env bash
|
||||
# ============================================================================
|
||||
# check_docs.sh · OTO Enterprise OS DTP
|
||||
# ----------------------------------------------------------------------------
|
||||
# Contrôle qualité documentaire (gate 4Big, roadmap Sprint 1) :
|
||||
# [HARD] Liens Markdown relatifs internes → la cible doit exister.
|
||||
# [SOFT] Livrables 05_deliverables_mvp/*.md → auto-score 4Big attendu.
|
||||
# Dépendances : bash, git, grep, sed. Aucun réseau requis.
|
||||
# ============================================================================
|
||||
set -uo pipefail
|
||||
cd "$(git rev-parse --show-toplevel)"
|
||||
|
||||
FAIL=0
|
||||
report() { printf ' \033[31m✗\033[0m %s\n' "$1"; FAIL=1; }
|
||||
warn() { printf ' \033[33m⚠\033[0m %s\n' "$1"; }
|
||||
ok() { printf ' \033[32m✓\033[0m %s\n' "$1"; }
|
||||
|
||||
echo "== 1. Liens Markdown relatifs internes (cible existe ?) =="
|
||||
broken=0
|
||||
while read -r md; do
|
||||
dir="$(dirname "$md")"
|
||||
# Extrait les cibles [texte](cible) ; ignore http(s), mailto, ancres pures,
|
||||
# gabarits {{...}} et liens wiki [[...]].
|
||||
grep -oE '\]\([^)]+\)' "$md" 2>/dev/null \
|
||||
| sed -E 's/^\]\(//; s/\)$//' \
|
||||
| while read -r link; do
|
||||
link="${link%% *}" # retire un éventuel "titre"
|
||||
link="${link%%#*}" # retire l'ancre
|
||||
[[ -z "$link" ]] && continue
|
||||
case "$link" in
|
||||
http://*|https://*|mailto:*|tel:*|\#*|\{\{*|data:*) continue ;;
|
||||
esac
|
||||
target="$dir/$link"
|
||||
if [[ ! -e "$target" ]]; then
|
||||
printf ' \033[31m✗\033[0m %s → lien cassé : %s\n' "$md" "$link"
|
||||
echo "BROKEN" >> /tmp/brokenlinks
|
||||
fi
|
||||
done
|
||||
done < <(git ls-files '*.md')
|
||||
if [[ -s /tmp/brokenlinks ]]; then FAIL=1; rm -f /tmp/brokenlinks; else ok "Aucun lien interne cassé"; fi
|
||||
|
||||
echo "== 2. Auto-score 4Big sur les livrables (SOFT · CLAUDE.md #5 · ≥95/100) =="
|
||||
while read -r md; do
|
||||
case "$md" in
|
||||
05_deliverables_mvp/daily_reports/*) continue ;; # rapports : hors gate score
|
||||
esac
|
||||
if grep -qiE 'score|/100' "$md"; then
|
||||
ok "$md — mention de score présente"
|
||||
else
|
||||
warn "$md — pas de mention d'auto-score 4Big (recommandé ≥95/100)"
|
||||
fi
|
||||
done < <(git ls-files '05_deliverables_mvp/*.md')
|
||||
|
||||
echo
|
||||
if [[ "$FAIL" -eq 0 ]]; then
|
||||
echo -e "\033[32m✅ Documentation conforme (liens internes OK).\033[0m"
|
||||
else
|
||||
echo -e "\033[31m❌ Lien(s) interne(s) cassé(s) — corriger avant merge.\033[0m"
|
||||
fi
|
||||
exit "$FAIL"
|
||||
Executable
+94
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env bash
|
||||
# ============================================================================
|
||||
# guard_constraints.sh · OTO Enterprise OS DTP
|
||||
# ----------------------------------------------------------------------------
|
||||
# Enforce les contraintes NON-NÉGOCIABLES de CLAUDE.md dans la CI.
|
||||
# Objectif : empêcher qu'un commit introduise un outil/plateforme interdit
|
||||
# ou une pratique proscrite. Gate qualité DevOps (roadmap Sprint 1).
|
||||
#
|
||||
# Principe de robustesse (zéro faux positif sur le texte de politique) :
|
||||
# - On détecte l'USAGE d'un terme interdit, PAS sa simple mention.
|
||||
# - Une ligne qui contient un MARQUEUR DE PROHIBITION (jamais, ❌, only,
|
||||
# pas de, interdit, SEUL...) est un rappel de la règle → on l'ignore.
|
||||
# - Escape hatch explicite : une ligne contenant « ci-allow » est ignorée.
|
||||
#
|
||||
# Sortie : exit 0 si conforme, exit 1 sinon (liste des violations).
|
||||
# Dépendances : bash, git, grep. Aucun réseau requis.
|
||||
# ============================================================================
|
||||
set -uo pipefail
|
||||
|
||||
cd "$(git rev-parse --show-toplevel)"
|
||||
|
||||
# Marqueur de prohibition : si présent sur la ligne, c'est un rappel de règle.
|
||||
PROHIBITION='jamais|JAMAIS|Jamais|❌|SEUL|Seul|only|Only|ONLY|pas de|pas d|\(pas |NON-|non-|[Ii]nterdit|INTERDIT|forbidden|proscrit|éliminer'
|
||||
|
||||
# ci-allow : échappatoire manuel documenté.
|
||||
ALLOW='ci-allow'
|
||||
|
||||
FAIL=0
|
||||
report() { printf ' \033[31m✗\033[0m %s\n' "$1"; FAIL=1; }
|
||||
ok() { printf ' \033[32m✓\033[0m %s\n' "$1"; }
|
||||
|
||||
# Fichiers suivis (exclut ce script lui-même : il liste les termes interdits).
|
||||
tracked_files() {
|
||||
git ls-files -- . \
|
||||
':(exclude)ci/guard_constraints.sh' \
|
||||
':(exclude).gitea/workflows/*.yml'
|
||||
}
|
||||
|
||||
# scan_forbidden <label> <regex-terme>
|
||||
# Flag toute occurrence NON préfixée d'un marqueur de prohibition / ci-allow.
|
||||
scan_forbidden() {
|
||||
local label="$1" term="$2" hits
|
||||
hits="$(tracked_files | while read -r f; do
|
||||
grep -inE "$term" "$f" 2>/dev/null \
|
||||
| grep -ivE "$PROHIBITION" \
|
||||
| grep -ivE "$ALLOW" \
|
||||
| sed "s#^#${f}:#"
|
||||
done)"
|
||||
if [[ -n "$hits" ]]; then
|
||||
report "Interdit détecté — $label :"
|
||||
echo "$hits" | sed 's/^/ /'
|
||||
else
|
||||
ok "Aucun usage interdit — $label"
|
||||
fi
|
||||
}
|
||||
|
||||
echo "== 1. Plateformes git interdites (CLAUDE.md #2 · Gitea SEULEMENT) =="
|
||||
scan_forbidden "GitHub" 'github\.com|git@github|github\.io'
|
||||
scan_forbidden "GitLab" 'gitlab\.com|gitlab\.io'
|
||||
scan_forbidden "Bitbucket" 'bitbucket\.org'
|
||||
|
||||
echo "== 2. CRM interdits (CLAUDE.md #3 · CRM = ERPNext natif) =="
|
||||
scan_forbidden "EspoCRM" 'espocrm'
|
||||
scan_forbidden "HubSpot" 'hubspot'
|
||||
|
||||
echo "== 3. Paiement interdit (CLAUDE.md #10 · Cardnet, pas Stripe) =="
|
||||
scan_forbidden "Stripe" 'stripe'
|
||||
|
||||
echo "== 4. Écriture directe /var/www/html/static (Interdit absolu) =="
|
||||
scan_forbidden "chemin /var/www/html/static en écriture" '/var/www/html/static/'
|
||||
|
||||
echo "== 5. Commande git clean (Interdit absolu) =="
|
||||
scan_forbidden "git clean" 'git[[:space:]]+clean'
|
||||
|
||||
echo "== 6. Remote git = Gitea uniquement =="
|
||||
if git remote -v >/dev/null 2>&1 && [[ -n "$(git remote)" ]]; then
|
||||
bad_remote="$(git remote -v | grep -iE 'github\.com|gitlab\.com|bitbucket\.org' || true)"
|
||||
if [[ -n "$bad_remote" ]]; then
|
||||
report "Remote git interdit configuré :"; echo "$bad_remote" | sed 's/^/ /'
|
||||
else
|
||||
ok "Remotes git conformes (Gitea / interne uniquement)"
|
||||
fi
|
||||
else
|
||||
ok "Aucun remote git configuré (CI checkout) — rien à vérifier"
|
||||
fi
|
||||
|
||||
echo
|
||||
if [[ "$FAIL" -eq 0 ]]; then
|
||||
echo -e "\033[32m✅ Contraintes NON-NÉGOCIABLES respectées.\033[0m"
|
||||
else
|
||||
echo -e "\033[31m❌ Violation(s) de contrainte détectée(s). Voir ci-dessus.\033[0m"
|
||||
echo " (Faux positif légitime ? Ajouter « ci-allow » sur la ligne concernée.)"
|
||||
fi
|
||||
exit "$FAIL"
|
||||
Executable
+39
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env bash
|
||||
# ============================================================================
|
||||
# validate_json.sh · OTO Enterprise OS DTP
|
||||
# ----------------------------------------------------------------------------
|
||||
# Valide que tous les fichiers .json suivis sont bien formés (parse strict).
|
||||
# Les schémas JSON (version.schema.json, projets_master.schema.json) sont le
|
||||
# contrat de données Faisabilité ↔ Publiciste : un JSON cassé bloque le
|
||||
# pipeline en aval → on l'attrape ici.
|
||||
# Dépendances : bash, git, python3. Aucun réseau requis.
|
||||
# ============================================================================
|
||||
set -uo pipefail
|
||||
cd "$(git rev-parse --show-toplevel)"
|
||||
|
||||
FAIL=0
|
||||
mapfile -t files < <(git ls-files '*.json')
|
||||
|
||||
if [[ "${#files[@]}" -eq 0 ]]; then
|
||||
echo "Aucun fichier .json suivi — rien à valider."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
for f in "${files[@]}"; do
|
||||
if python3 -c "import json,sys; json.load(open(sys.argv[1]))" "$f" 2>/tmp/jsonerr; then
|
||||
printf ' \033[32m✓\033[0m %s\n' "$f"
|
||||
# Si un $schema est déclaré, contrôle que 'draft' est reconnu (info seule).
|
||||
else
|
||||
printf ' \033[31m✗\033[0m %s\n' "$f"
|
||||
sed 's/^/ /' /tmp/jsonerr
|
||||
FAIL=1
|
||||
fi
|
||||
done
|
||||
|
||||
echo
|
||||
if [[ "$FAIL" -eq 0 ]]; then
|
||||
echo -e "\033[32m✅ Tous les JSON sont bien formés.\033[0m"
|
||||
else
|
||||
echo -e "\033[31m❌ JSON invalide détecté.\033[0m"
|
||||
fi
|
||||
exit "$FAIL"
|
||||
Reference in New Issue
Block a user