Skip to content

Déploiement FTP

Pipeline de mise en production sur un serveur FTP/FTPS. À chaque exécution, seul le delta est poussé : les fichiers modifiés ou nouveaux sont envoyés, les fichiers supprimés localement sont effacés du serveur.

Pour l’inventaire complet des scripts en ligne de commande (crons, workers, outils ponctuels et de debug), voir docs/bin.md.

  1. Copier le modèle :

    Terminal window
    cp deploy.config.example.php deploy.config.php
  2. Renseigner les identifiants dans deploy.config.php (ignoré par git, il contient le mot de passe FTP).

CléDéfautRôle
host— (requis)Hôte FTP
port21Port
username— (requis)Utilisateur
password''Mot de passe
securefalseFTPS (TLS explicite)
verifyPeertrueVérifie le certificat en FTPS
passivetrueMode passif
timeout30Timeout connexion/transfert (s)
remoteRoot/Dossier serveur cible
protectedRemotePaths[]Chemins jamais supprimés par --mirror
manifestPath.deploy-manifest.jsonFichier d’état local (hash)
backupEnabledtrueSauvegarde avant écrasement (active le rollback)
backupRetention5Nombre de sauvegardes conservées
backupPathvar/deploy-backupsDossier des sauvegardes (local)

Les fichiers exclus sont définis dans .deployignore (syntaxe type gitignore : # commentaire, / en tête = ancré à la racine, / en fin = dossiers uniquement, globs */?).

Quoi qu’il arrive, le déployeur n’enverra jamais les secrets et l’état local : .env, .env.*, deploy.config.php, .deploy-manifest*.json, .deployignore, .git/. Cette liste est codée en dur et ne dépend pas de .deployignore.

Terminal window
php bin/deploy.php --dry-run # aperçu du plan, ne contacte pas le serveur
php bin/deploy.php # pousse les changements, supprime les retirés
php bin/deploy.php --mirror # + élague les fichiers distants absents en local

Options :

OptionEffet
--config=PATHChemin du config (défaut ./deploy.config.php)
--dry-runAffiche le plan sans rien envoyer
--mirrorSupprime aussi les fichiers distants orphelins (hors protectedRemotePaths)
--rollbackAnnule le dernier déploiement (ou --backup=ID)
--backup=IDSauvegarde précise à restaurer (défaut : la plus récente)
--helpAide

Codes de sortie : 0 succès, 1 erreur (config/transfert), 2 arguments invalides.

Tant que backupEnabled est vrai, chaque déploiement réel sauvegarde d’abord les octets distants qu’il va écraser ou supprimer, sous var/deploy-backups/<timestamp>/ (local, jamais uploadé, git-ignoré) :

<timestamp>/
files/<chemin> anciens octets des fichiers modifiés/supprimés
manifest.before.json manifeste tel qu'avant le déploiement
backup.json { created:[…], restored:[…] }

Pour revenir en arrière après un déploiement fautif :

Terminal window
php bin/deploy.php --rollback --dry-run # aperçu de la restauration
php bin/deploy.php --rollback # restaure la dernière sauvegarde
php bin/deploy.php --rollback --backup=20260627-143012 # une sauvegarde précise

Le rollback ré-uploade les fichiers sauvegardés (restored), supprime ceux que le déploiement avait créés (created), puis restaure manifest.before.json comme manifeste courant — de sorte que le delta suivant repart de l’état restauré.

Limites (FTP pur, sans copie serveur ni symlink) :

  • Pas atomique : la restauration se fait fichier par fichier (court intervalle incohérent possible).
  • Une seule sauvegarde par déploiement ; backupRetention borne l’historique.
  • Un fichier introuvable au moment de la sauvegarde (dérive du manifeste) est reclassé en « créé » → supprimé au rollback.
  1. Scan : LocalScanner parcourt le projet et calcule un hash par fichier (xxh128, repli md5), en élaguant les dossiers ignorés pendant le parcours.
  2. Delta : comparaison avec le manifeste du dernier déploiement réussi (relativePath => hash). FTP n’expose pas de hash, d’où ce manifeste local.
    • hash différent ou fichier nouveau → upload
    • présent au manifeste mais absent du disque → delete
  3. Mirror (optionnel) : liste récursive du serveur ; tout fichier distant absent en local et hors protectedRemotePaths est supprimé.
  4. Manifeste : réécrit après un déploiement réussi (non-dry-run) pour refléter l’état désormais en ligne.

Transport : tout passe par curl (l’extension ext-ftp n’est pas disponible), qui gère FTP et FTPS. Connexion réutilisée entre les transferts.

Il n’y a pas de runner de migrations automatisé : les changements de schéma sont appliqués à la main sur le serveur. bin/migrations-bundle.php regroupe les migrations non encore déployées en un fichier consolidé par base, sous database/deploy/<clé>.sql, à exécuter puis supprimer après chaque déploiement.

Une directive d’en-tête, sur sa propre ligne, déclare la base :

-- @database: bo

Clés acceptées : main (défaut si absente → DB_NAME), bo (BO_DB_NAME, hxa_bo), work (WORK_DB_NAME). La base geo est en lecture seule (pas de migrations). Le fichier généré n’émet aucun USE : tu choisis toi-même la base au moment de l’exécution.

Toute migration dont le préfixe YYYY_MM_DD_HHMMSS est postérieur au watermark stocké dans database/migrations/.bundle-state.json ({"deployedThrough": "..."}). Le watermark est seedé sur la dernière migration existante : seules les nouvelles sont regroupées.

Terminal window
php bin/migrations-bundle.php # génère database/deploy/<base>.sql
php bin/migrations-bundle.php --dry-run # liste le delta sans rien écrire
php bin/migrations-bundle.php --mark # marque le delta comme déployé

Flux type :

  1. php bin/migrations-bundle.php → écrit database/deploy/*.sql
  2. exécuter chaque fichier sur la base correspondante (mysql hxa_bo < database/deploy/bo.sql, ou via phpMyAdmin)
  3. php bin/migrations-bundle.php --mark → avance le watermark
  4. supprimer database/deploy/*.sql (déjà git-ignoré)

La génération est sans effet de bord (relançable) : seul --mark avance le watermark, à lancer une fois le déploiement réussi.