name: Build and deploy on: push: branches: [main, dev] # Le job "test" tourne sur CHAQUE push (main et dev) : jusqu'ici aucune # étape de CI n'exécutait la suite de tests, rien n'empêchait un commit # cassé d'atteindre la production (voir l'audit qualité de la Phase 0 du # plan). "build-and-push"/"deploy", eux, restent réservés à main (via le # filtre "if" sur gitea.ref) — un push sur dev ne doit jamais redéployer # la prod, seulement faire tourner les tests. # Secrets à configurer dans Gitea (Paramètres du dépôt > Actions > Secrets) : # REGISTRY_HOST adresse du registre d'images (ex: gitea.exemple.com) # REGISTRY_IMAGE chemin complet de l'image (ex: gitea.exemple.com/mon-compte/forge-engine) # REGISTRY_USER utilisateur pour "docker login" sur ce registre # REGISTRY_TOKEN jeton d'accès (scope package:write) pour ce registre # DEPLOY_HOST adresse du serveur de production # DEPLOY_USER utilisateur SSH sur ce serveur # DEPLOY_SSH_KEY clé privée SSH (au format PEM) autorisée sur ce serveur # DEPLOY_PATH dossier sur le serveur où vit docker-compose.prod.yml (ex: /home/deploy/forge-engine) # # Utilise directement docker/ssh/scp en ligne de commande plutôt que des # actions du marketplace, pour ne pas dépendre de la disponibilité de # github.com / du miroir gitea.com depuis le runner self-hosted. jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 # Conteneurs officiels plutôt que actions/setup-python|setup-node du # marketplace — même logique que le reste de ce fichier (éviter une # dépendance à la disponibilité de github.com/du miroir gitea.com # depuis le runner self-hosted), et le runner n'a pas besoin # d'installer quoi que ce soit d'autre que Docker, déjà requis pour # build-and-push. - name: Tests Python (pytest) run: | docker run --rm -v "$PWD":/app -w /app python:3.13-slim sh -c " pip install --quiet -r requirements-dev.txt && python -m pytest tests/ -q " - name: Tests JS (node:test — logique pure de static/js/play/, voir le plan de modularisation) run: | docker run --rm -v "$PWD":/app -w /app node:20-slim \ node --test static/js/play/__tests__/*.test.js build-and-push: needs: test if: gitea.ref == 'refs/heads/main' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Connexion au registre d'images run: echo "${{ secrets.REGISTRY_TOKEN }}" | docker login "${{ secrets.REGISTRY_HOST }}" -u "${{ secrets.REGISTRY_USER }}" --password-stdin - name: Build de l'image run: | docker build \ -t "${{ secrets.REGISTRY_IMAGE }}:${{ gitea.sha }}" \ -t "${{ secrets.REGISTRY_IMAGE }}:latest" \ . - name: Publication de l'image run: | docker push "${{ secrets.REGISTRY_IMAGE }}:${{ gitea.sha }}" docker push "${{ secrets.REGISTRY_IMAGE }}:latest" deploy: needs: build-and-push if: gitea.ref == 'refs/heads/main' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Préparation de la clé SSH run: | mkdir -p ~/.ssh echo "${{ secrets.DEPLOY_SSH_KEY }}" > ~/.ssh/deploy_key chmod 600 ~/.ssh/deploy_key ssh-keyscan -H "${{ secrets.DEPLOY_HOST }}" >> ~/.ssh/known_hosts - name: Envoi du docker-compose.prod.yml sur le serveur run: | scp -i ~/.ssh/deploy_key docker-compose.prod.yml \ "${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }}:${{ secrets.DEPLOY_PATH }}/docker-compose.prod.yml" - name: Pull et redémarrage sur le serveur run: | ssh -i ~/.ssh/deploy_key "${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }}" ' set -e cd "${{ secrets.DEPLOY_PATH }}" echo "REGISTRY_IMAGE=${{ secrets.REGISTRY_IMAGE }}" > .env echo "IMAGE_TAG=${{ gitea.sha }}" >> .env docker login "${{ secrets.REGISTRY_HOST }}" -u "${{ secrets.REGISTRY_USER }}" -p "${{ secrets.REGISTRY_TOKEN }}" docker compose -f docker-compose.prod.yml pull docker compose -f docker-compose.prod.yml up -d docker image prune -f '