Skip to content

feat(spartan-customizer): nameplates upscalées IA + sélection emblème… #1328

feat(spartan-customizer): nameplates upscalées IA + sélection emblème…

feat(spartan-customizer): nameplates upscalées IA + sélection emblème… #1328

name: Deploy Pre-Check
# Valide l'infrastructure de déploiement SANS connexion SSH au VPS.
# Couvre les cas qui font échouer deploy.yml en production :
# - Dockerfile invalide / build cassé
# - docker-compose.yml mal formé
# - Permissions UID 1000 (appuser = même UID que deploy sur VPS)
# - Volumes bind-mount fichiers remplacés par des répertoires fantômes
# - Syntaxe des scripts shell/Python
on:
push:
branches:
- main
- chore/**
- fix/**
- feat/**
- refactor/**
pull_request:
branches:
- main
workflow_dispatch: {}
jobs:
# ────────────────────────────────────────────────────────────────
# Job 1 — Valider la syntaxe (YAML, Bash, Python) sans Docker
# ────────────────────────────────────────────────────────────────
validate-syntax:
name: Syntaxe (YAML / Bash / Python)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Validation workflows GitHub Actions (actionlint)
# actionlint : binaire Go natif, valide syntaxe YAML + sémantique
# spécifique GitHub Actions (expressions ${{ }}, matrix, needs, etc.).
# Remplace l'ancien python3+pyyaml qui ne validait que la syntaxe YAML.
# Script officiel : https://github.com/rhysd/actionlint/blob/main/docs/usage.md
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: "Vérifier que db_profiles.json racine est un fichier (pas répertoire)"
run: |
if [[ -d "db_profiles.json" ]]; then
echo " ❌ db_profiles.json est un RÉPERTOIRE — volume Docker cassé"
exit 1
elif [[ -f "db_profiles.json" ]]; then
echo " ✅ db_profiles.json est un fichier"
else
echo " ⚠️ db_profiles.json absent (normal si non configuré)"
fi
# ────────────────────────────────────────────────────────────────
# Job 2 — Build Docker + validation images
# ────────────────────────────────────────────────────────────────
docker-build:
name: Docker Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Build image LevelUp
uses: docker/build-push-action@v5
with:
context: .
push: false
load: true
tags: levelup-test:ci
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Vérifier UID appuser dans l'image
run: |
# L'image démarre root (entrypoint gosu), mais appuser doit être UID 1000
UID_IN_IMAGE=$(docker run --rm --entrypoint id levelup-test:ci -u appuser 2>/dev/null \
|| docker run --rm levelup-test:ci id -u)
echo " UID appuser détecté : ${UID_IN_IMAGE}"
if [[ "${UID_IN_IMAGE}" == "1000" ]]; then
echo " ✅ UID correct : 1000 (même que deploy sur VPS)"
else
echo " ❌ UID inattendu : ${UID_IN_IMAGE} (attendu 1000)"
exit 1
fi
- name: Valider docker-compose.yml (docker compose config)
run: |
# Créer les fichiers requis pour que compose config passe
touch .env.local
echo '{"version":"2.1","warehouse_path":"data/warehouse","profiles":{}}' > db_profiles.json
echo '{}' > app_settings.json
# Créer les répertoires de données vides pour satisfaire les volumes
mkdir -p data/demo/warehouse data/demo/players data/logs data/warehouse data/players
touch data/demo/db_profiles.json data/demo/app_settings.json
docker compose config --quiet
echo " ✅ docker-compose.yml valide"
# ────────────────────────────────────────────────────────────────
# Job 3 — Simulation permissions (entrypoint gosu + cas VPS réaliste)
# ────────────────────────────────────────────────────────────────
permissions-simulation:
name: Permissions entrypoint gosu (simulation VPS)
runs-on: ubuntu-latest
needs: docker-build
steps:
- uses: actions/checkout@v7
- name: Build image
run: |
docker build -t levelup-test:ci . -q
- name: "Cas A : data/ appartient à deploy (UID 1000) → entrypoint fixe les perms"
run: |
mkdir -p data/demo data/logs
# Simuler l'état VPS : fichiers appartenant au user host (pas au container)
sudo chown -R 1000:1000 data/
# L'entrypoint (root → chown → gosu appuser) doit corriger automatiquement
docker run --rm \
-v "$PWD/data:/app/data" \
levelup-test:ci \
/bin/sh -c "mkdir -p /app/data/demo/warehouse && echo 'OK'"
echo " ✅ Entrypoint a corrigé les permissions automatiquement"
- name: "Cas B : data/ appartient à root → entrypoint fixe aussi"
run: |
sudo chown -R root:root data/
docker run --rm \
-v "$PWD/data:/app/data" \
levelup-test:ci \
/bin/sh -c "mkdir -p /app/data/demo/test_root && echo 'OK'"
echo " ✅ Entrypoint a corrigé les permissions root:root"
- name: "Cas C : Reproduction bug répertoire fantôme Docker bind-mount"
run: |
# Reprendre la main sur data/ laissé en root:root par le Cas B
sudo chown -R "$(id -u):$(id -g)" data/
mkdir -p data/demo
# Supprimer db_profiles.json (simule un regen raté)
rm -f data/demo/db_profiles.json
# Premier compose up avec source absente → Docker crée un répertoire
# On le simule manuellement car on ne peut pas faire 2x compose up dans le CI
mkdir -p data/demo/db_profiles.json # Simule ce que Docker fait
if [[ -d "data/demo/db_profiles.json" ]]; then
echo " ✅ Bug reproduit : data/demo/db_profiles.json est un répertoire"
echo " Nettoyage..."
rm -rf data/demo/db_profiles.json
echo " ✅ Nettoyage OK"
else
echo " ❌ Impossible de reproduire le bug — vérifier le test"
exit 1
fi
- name: "Cas D : Vérifier la syntaxe de scripts/deploy.sh"
run: |
bash -n scripts/deploy.sh
echo " ✅ scripts/deploy.sh : syntaxe bash OK"
# ────────────────────────────────────────────────────────────────
# Job 4 — Simulation end-to-end regen demo (sans données réelles)
# ────────────────────────────────────────────────────────────────
e2e-regen-demo-precheck:
name: Simulation regen demo (sans données)
runs-on: ubuntu-latest
needs: [docker-build, permissions-simulation]
steps:
- uses: actions/checkout@v7
- name: Build image
run: docker build -t levelup-test:ci . -q
- name: "Simulation étape 1 : rm -rf (comme dans deploy.yml)"
run: |
mkdir -p data/demo data/logs data/warehouse data/players
# Créer des artefacts à supprimer pour simuler un état "après regen précédent"
mkdir -p data/demo/warehouse
touch data/demo/db_profiles.json data/demo/app_settings.json
# Exécuter le rm -rf exact du workflow
rm -rf data/demo/warehouse data/demo/db_profiles.json data/demo/app_settings.json \
data/demo/players/DEMO/stats.duckdb 2>/dev/null || true
echo " ✅ Étape 1 rm -rf OK"
# Vérifier qu'aucun répertoire fantôme n'a été créé
for f in data/demo/db_profiles.json data/demo/app_settings.json; do
if [[ -d "$f" ]]; then
echo " ❌ Répertoire fantôme créé : $f"
exit 1
fi
done
echo " ✅ Pas de répertoire fantôme après rm -rf"
- name: "Simulation étape 2 : docker compose run (écriture dans data/demo/)"
run: |
# L'entrypoint fait le chown automatiquement — pas de -u ni chown manuel.
# Le `/bin/sh -c "..."` dans l'image est POSIX sh (dash) : pas de [[ ]]
# ni de chainage complexe — on garde minimal et on verifie ensuite en
# bash dans le runner.
docker run --rm \
-v "$PWD/data:/app/data" \
levelup-test:ci \
/bin/sh -c "mkdir -p /app/data/demo/warehouse /app/data/demo/players/DEMO && \
echo '{\"version\": \"2.1\"}' > /app/data/demo/db_profiles.json && \
echo '{}' > /app/data/demo/app_settings.json && \
echo 'Simulation demo data : OK'"
# Verifications post-docker en bash (runner GitHub Actions, pas container).
for f in data/demo/db_profiles.json data/demo/app_settings.json; do
if [[ -d "$f" ]]; then
echo " ❌ $f est un répertoire — compose up levelup-demo va échouer"
exit 1
elif [[ -f "$f" ]]; then
echo " ✅ $f est un fichier"
else
echo " ❌ $f absent — regen n'a pas produit le fichier attendu"
exit 1
fi
done
echo " ✅ Tous les volumes bind-mount fichiers sont OK pour levelup-demo"