Conteneurisation (site 100 % statique — l'image ne détient AUCUNE donnée, vie privée identique) : - Dockerfile : nginxinc/nginx-unprivileged:alpine (uid 101, port 8080, pas de root), healthcheck wget intégré, labels OCI - nginx.conf : no-cache systématique (cohérence du jeu de fichiers à chaque mise à jour d'image, coût nul : ~600 Ko + gzip sur l'asset PK), gzip, en-têtes de sécurité, deny des dotfiles - .dockerignore : runtime uniquement (docs/ inclus — dialog changelog) ; local-test-data exclu en filet de sécurité - docker-compose.yml : read_only + tmpfs (/var/cache/nginx, /run, /tmp — les temporaires de nginx-unprivileged, constat au premier test réel) + no-new-privileges Nouveaux tests avant release : - scripts/container-test.sh : build + run DURCI (config compose) + healthcheck healthy + endpoints 200 + headers (no-cache/nosniff/DENY/ no-referrer) + gzip réel + MIME strict des modules ES + fichiers cachés non servis + image propre (pas de node_modules/npm) + docs/ embarqué + E2E playwright complet CONTRE LE CONTENEUR (HRT_E2E_BASE) - scripts/e2e.mjs : mode externe HRT_E2E_BASE (pilote un site déjà déployé — conteneur inclus, serveur local non démarré) - scripts/check.sh --release : supplée les 9 vérifications (version ↔ changelog ↔ tag ↔ arbre propre + test conteneur si daemon) Runtime Docker local installé pour le CI-like (colima 2 CPU / 2 Go) : premier build + run réel = 2 problèmes testés et corrigés (tmpfs /tmp, key case header_json curl). CONTAINER TEST OK en configuration durcie.
145 lines
5.5 KiB
Bash
145 lines
5.5 KiB
Bash
#!/usr/bin/env bash
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
# check.sh — vérifications de l'app web (pré-commit / pré-push / pré-release).
|
|
#
|
|
# 1. node --check sur chaque module ES (syntaxe) — attrape les typos avant
|
|
# même de charger l'app dans un navigateur ;
|
|
# 2. présence des fichiers critiques (index.html, asset PK, CSS, changelog) ;
|
|
# 3. cohérence i18n : clés FR/EN synchronisées + clés référencées existantes
|
|
# (leçon Android §12 : une string manquante s'affiche brute) ;
|
|
# 4. tests unitaires Node (node --test) ;
|
|
# 5. E2E navigateur (si playwright est installé — npm i + npx playwright
|
|
# install firefox, cf docs/DEVELOPPEMENT.md §Tests) ;
|
|
# 6. smoke HTTP (--with-serve : serveur + curl des ressources clés).
|
|
#
|
|
# Mode RELEASE (--release) : ajoute les vérifications OBLIGATOIRES avant une
|
|
# release (cf docs/DEVELOPPEMENT.md §10) —
|
|
# 7. cohérence de la version : WEB_VERSION == section `## [X.Y.Z]` de
|
|
# docs/CHANGELOG.md == tag annoté `vX.Y.Z` existant (le bump de version
|
|
# jamais commité côté Android, bug #46, ne doit pas se reproduire ici) ;
|
|
# 8. arbre git propre (tout commité avant publication) ;
|
|
# 9. test conteneur RÉEL (scripts/container-test.sh — build/run durci/
|
|
# headers/gzip/MIME/E2E contre le conteneur) si un daemon Docker est
|
|
# joignable, ignoré sinon (à lancer sur l'hôte qui a Docker).
|
|
#
|
|
# Usage : bash scripts/check.sh [--with-serve] [--release]
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
set -euo pipefail
|
|
cd "$(dirname "$0")/.." # racine du dépôt
|
|
|
|
fail=0
|
|
RELEASE=false
|
|
for arg in "$@"; do
|
|
[[ "$arg" == "--release" ]] && RELEASE=1
|
|
done
|
|
|
|
echo "── 1. Syntaxe des modules (node --check) ──"
|
|
while IFS= read -r f; do
|
|
if ! node --check "$f" 2>/tmp/hrt-check.err; then
|
|
echo "✗ $f"
|
|
cat /tmp/hrt-check.err
|
|
fail=1
|
|
fi
|
|
done < <(find js -name '*.js' -type f | sort)
|
|
echo " tous les modules de js/ sont syntaxiquement valides"
|
|
|
|
echo "── 2. Fichiers critiques ──"
|
|
for f in index.html css/style.css assets/pk_profiles.json docs/CHANGELOG.md \
|
|
js/ui/app.js js/pk/pk-engine.js; do
|
|
if [[ ! -f "$f" ]]; then
|
|
echo "✗ manquant : $f"
|
|
fail=1
|
|
fi
|
|
done
|
|
echo " fichiers critiques présents"
|
|
|
|
echo "── 3. Cohérence i18n FR/EN ──"
|
|
# Vérifie : (a) chaque clé de EN existe dans FR et inversement ;
|
|
# (b) chaque clé utilisée par t('...') dans js/ existe dans EN et FR.
|
|
# (leçon Android §12 : une string manquante s'affiche brute — et FR/EN
|
|
# désynchronisés = UI mi-anglaise mi-française)
|
|
if ! node scripts/i18n-check.mjs; then
|
|
echo "✗ clés i18n manquantes (voir ci-dessus)"
|
|
fail=1
|
|
fi
|
|
|
|
echo "── 4. Tests unitaires ──"
|
|
if ! node --test tests/ 2>&1 | tail -6; then
|
|
fail=1
|
|
fi
|
|
|
|
echo "── 5. E2E navigateur (si playwright installé) ──"
|
|
if [[ -d node_modules/playwright-core && -d "$HOME/Library/Caches/ms-playwright" ]]; then
|
|
if ! node scripts/e2e.mjs 8989; then
|
|
fail=1
|
|
fi
|
|
else
|
|
echo " (ignoré : playwright non installé — npm i && npx playwright install firefox)"
|
|
fi
|
|
|
|
if [[ "${1:-}" == "--with-serve" ]]; then
|
|
echo "── 6. Smoke HTTP ──"
|
|
python3 scripts/serve.py --port 8971 >/tmp/hrt-serve.log 2>&1 &
|
|
SRV=$!
|
|
sleep 1.5
|
|
for path in / /css/style.css /assets/pk_profiles.json /js/ui/app.js /docs/CHANGELOG.md; do
|
|
code=$(curl -s -o /dev/null -w '%{http_code}' "http://127.0.0.1:8971${path}")
|
|
if [[ "$code" != "200" ]]; then
|
|
echo "✗ ${path} → HTTP ${code}"
|
|
fail=1
|
|
else
|
|
echo " 200 ${path}"
|
|
fi
|
|
done
|
|
kill $SRV 2>/dev/null || true
|
|
wait $SRV 2>/dev/null || true
|
|
fi
|
|
|
|
if [[ "$RELEASE" == "1" ]]; then
|
|
echo "── 7. Cohérence de la version (release) ──"
|
|
ver=$(node --input-type=module -e "
|
|
import { WEB_VERSION } from './js/ui/settings.js';
|
|
process.stdout.write(WEB_VERSION);")
|
|
verGrep=$(echo "$ver" | sed 's/\./\\./g') # 1.4.10 → 1\.4\.10 pour grep -E
|
|
if grep -qE "^## \\[$verGrep\\]" docs/CHANGELOG.md; then
|
|
echo " WEB_VERSION = $ver ; section [$ver] présente dans docs/CHANGELOG.md"
|
|
else
|
|
echo "✗ WEB_VERSION ($ver) n'a pas de section correspondante dans docs/CHANGELOG.md"
|
|
fail=1
|
|
fi
|
|
# Le bump de version jamais commité (bug Android #46) ne doit pas se
|
|
# reproduire : la release est faite SUR un tag qui existe.
|
|
if git rev-parse -q --verify "refs/tags/v$ver" >/dev/null 2>&1; then
|
|
echo " tag v$ver présent"
|
|
else
|
|
echo "✗ tag v$ver ABSENT — créer et pousser le tag avant la release (leçon Android #46)"
|
|
fail=1
|
|
fi
|
|
|
|
echo "── 8. Arbre git propre avant publication ──"
|
|
if [[ -n "$(git status --porcelain)" ]]; then
|
|
echo "✗ working tree sale — tout committer avant la release"
|
|
git status --short | head -5
|
|
fail=1
|
|
else
|
|
echo " working tree propre"
|
|
fi
|
|
|
|
echo "── 9. Test conteneur RÉEL (si daemon Docker joignable) ──"
|
|
if docker info --format x >/dev/null 2>&1; then
|
|
if ! bash scripts/container-test.sh 8975; then
|
|
fail=1
|
|
fi
|
|
else
|
|
echo " (ignoré : aucun daemon Docker ici — lancer sur l'hôte cible :"
|
|
echo " bash scripts/container-test.sh ; cf docs/DEVELOPPEMENT.md §10)"
|
|
fi
|
|
fi
|
|
|
|
if [[ $fail -eq 0 ]]; then
|
|
echo "✓ CHECK OK"
|
|
else
|
|
echo "✗ CHECK FAILED"
|
|
exit 1
|
|
fi
|