feat(spartan-customizer): nameplates upscalées IA + sélection emblème… #1328
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 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" |