merge: accueil citations (une ligne + état tout-complété + texte proc… #158
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Deploy to VPS | |
| on: | |
| push: | |
| branches: [main] | |
| jobs: | |
| # ── Job 0 : Pré-validation rapide (syntaxe — ne nécessite pas de SSH) ────── | |
| pre-check: | |
| name: Pré-validation deploy | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Validation workflows GitHub Actions (actionlint) | |
| # actionlint : binaire Go natif, validation sémantique GitHub Actions | |
| # (script officiel rhysd/actionlint). Remplace l'ancien python3+pyyaml. | |
| run: | | |
| bash <(curl -sSf https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) | |
| ./actionlint -color | |
| - name: Validation syntaxe Bash (scripts/*.sh) | |
| run: | | |
| errors=0 | |
| for f in scripts/*.sh; do | |
| [[ -f "$f" ]] || continue | |
| if bash -n "$f" 2>&1; then echo " ✅ $f" | |
| else echo " ❌ $f"; errors=$((errors + 1)); fi | |
| done | |
| exit $errors | |
| - name: Pas de répertoires fantômes à la racine | |
| run: | | |
| for f in db_profiles.json app_settings.json; do | |
| if [[ -d "$f" ]]; then | |
| echo " ❌ $f est un répertoire — volume Docker corrompu" | |
| exit 1 | |
| fi | |
| done | |
| echo " ✅ Aucun répertoire fantôme à la racine" | |
| # ── Job 1 : Déploiement VPS ──────────────────────────────────────────────── | |
| deploy: | |
| name: Deploy lvelup.info | |
| runs-on: ubuntu-latest | |
| needs: pre-check | |
| steps: | |
| - name: Deploy via SSH | |
| uses: appleboy/ssh-action@v1 | |
| with: | |
| host: ${{ secrets.VPS_HOST }} | |
| username: deploy | |
| key: ${{ secrets.VPS_SSH_KEY }} | |
| script: | | |
| git config --global --add safe.directory /opt/levelup | |
| cd /opt/levelup | |
| bash /opt/levelup/scripts/deploy.sh | |
| # ── Job 2 : Regen données démo ──────────────────────────────────────────── | |
| deploy-demo: | |
| name: Regen demo.lvelup.info | |
| runs-on: ubuntu-latest | |
| needs: deploy | |
| steps: | |
| - name: Regen données démo via SSH | |
| uses: appleboy/ssh-action@v1 | |
| with: | |
| host: ${{ secrets.VPS_HOST }} | |
| username: deploy | |
| key: ${{ secrets.VPS_SSH_KEY }} | |
| script: | | |
| set -euo pipefail | |
| cd /opt/levelup | |
| # Regen données démo — NON DESTRUCTIF (incident 2026-06-05). | |
| # On NE supprime PAS data/demo/warehouse|players AVANT le seed : seed-demo | |
| # est idempotent (os.Remove par fichier puis recrée). Supprimer d'abord = | |
| # si le seed échoue (ex: binaire levelup absent), la démo reste vidée. | |
| # On nettoie uniquement les répertoires fantômes que Docker crée à la place | |
| # d'un JSON absent au bind-mount ; les fichiers valides sont écrasés par seed-demo. | |
| for f in data/demo/db_profiles.json data/demo/app_settings.json; do | |
| if [[ -d "$f" ]]; then | |
| rm -rf "$f" | |
| echo "[regen] Répertoire fantôme supprimé: $f" | |
| fi | |
| done | |
| # Permissions fixées automatiquement par docker-entrypoint.sh (gosu pattern) | |
| mkdir -p data/demo | |
| # Garde anti-crash-loop : si une tache de fond hote (cmd/[b]ackfill_*) tient | |
| # le lock DuckDB, stopper la prod l'empecherait de rouvrir (cf. memoire | |
| # deploy_hazards). On SKIP le regen sans faire echouer le deploiement (la | |
| # demo garde ses donnees sur disque). Le motif [b]ackfill evite que pgrep | |
| # matche le mot dans sa propre ligne de commande (faux positif permanent). | |
| if pgrep -f '[b]ackfill' >/dev/null 2>&1; then | |
| echo "[regen] Tache de fond hote detectee — regen demo SKIP (prod preservee)" | |
| exit 0 | |
| fi | |
| # seed-demo lit les DB source du joueur JGtm que la PROD tient verrouillées | |
| # (lock DuckDB mono-writer) → on stoppe la prod le temps du seed (~5-10 s), | |
| # puis on la REDÉMARRE TOUJOURS (même si le seed échoue, sinon prod down). | |
| # Pas de `levelup seed` ici : seed-demo COPIE la metadata prod (référentiels | |
| # + rank_translations déjà présents) ; l'ancien `levelup seed` verrouillait | |
| # la metadata prod = cause de l'échec historique de ce job. | |
| echo "[regen] Stop prod (libère les locks des DB source)..." | |
| docker compose stop levelup | |
| # Indexation des captures Halo 5 (mp4 web-natifs servis en direct) : associe | |
| # chaque clip à son match h5 par timestamp et écrit media_files/associations | |
| # dans shared_social h5 — lues ensuite par seed-demo pour extraire des clips | |
| # démo (extractDemoMediaH5). Best-effort + IDEMPOTENT (re-association). Requiert | |
| # ffmpeg (miniatures) — présent sur le VPS. Prod stoppée → DB source libres. | |
| # buffer-min 10 : les captures Game Bar sont prises en FIN de match (delta jusqu'à | |
| # ~8 min vs start_time). captures-dir = {media base}/JGtm (résolu par la CLI). | |
| echo "[regen] Index media Halo 5 (captures → associations)..." | |
| docker compose run --rm levelup \ | |
| levelup index-media --gamertag JGtm --title halo_5 --buffer-min 10 \ | |
| || echo "[regen] ⚠️ index-media halo_5 a échoué (pas de clip H5 ce regen)" | |
| # seed-demo seede désormais TOUS les titres où JGtm a des données (dérivés de | |
| # db_profiles) : halo_infinite (flux HLS) + halo_5 (clips mp4 indexés ci-dessus). | |
| docker compose run --rm levelup \ | |
| levelup seed-demo --gamertag JGtm --service-tag SPTA --out data/demo --max-media 12 \ | |
| || echo "[regen] ⚠️ seed-demo a échoué — démo inchangée (prod va être redémarrée)" | |
| echo "[regen] Restart prod..." | |
| docker compose up -d levelup | |
| # [Guard] Vérification post-regen — les configs doivent être des fichiers. | |
| ok=true | |
| for f in data/demo/db_profiles.json data/demo/app_settings.json; do | |
| if [[ -d "/opt/levelup/$f" ]]; then | |
| echo "[regen] ❌ $f est un répertoire (regen incomplet)"; ok=false | |
| else | |
| echo "[regen] ✅ $f OK" | |
| fi | |
| done | |
| $ok || { echo "[regen] ❌ Démo non recréée (configs invalides) — prod déjà redémarrée"; exit 1; } | |
| # Recréer le conteneur démo (nouvelle data + image + mounts à jour). | |
| docker compose up -d --force-recreate levelup-demo | |
| echo "[regen] ✅ levelup-demo recréé avec les données fraîches" |