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.
Configuration
Section titled “Configuration”-
Copier le modèle :
Terminal window cp deploy.config.example.php deploy.config.php -
Renseigner les identifiants dans
deploy.config.php(ignoré par git, il contient le mot de passe FTP).
| Clé | Défaut | Rôle |
|---|---|---|
host | — (requis) | Hôte FTP |
port | 21 | Port |
username | — (requis) | Utilisateur |
password | '' | Mot de passe |
secure | false | FTPS (TLS explicite) |
verifyPeer | true | Vérifie le certificat en FTPS |
passive | true | Mode passif |
timeout | 30 | Timeout connexion/transfert (s) |
remoteRoot | / | Dossier serveur cible |
protectedRemotePaths | [] | Chemins jamais supprimés par --mirror |
manifestPath | .deploy-manifest.json | Fichier d’état local (hash) |
backupEnabled | true | Sauvegarde avant écrasement (active le rollback) |
backupRetention | 5 | Nombre de sauvegardes conservées |
backupPath | var/deploy-backups | Dossier des sauvegardes (local) |
Exclusions
Section titled “Exclusions”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.
Utilisation
Section titled “Utilisation”php bin/deploy.php --dry-run # aperçu du plan, ne contacte pas le serveurphp bin/deploy.php # pousse les changements, supprime les retirésphp bin/deploy.php --mirror # + élague les fichiers distants absents en localOptions :
| Option | Effet |
|---|---|
--config=PATH | Chemin du config (défaut ./deploy.config.php) |
--dry-run | Affiche le plan sans rien envoyer |
--mirror | Supprime aussi les fichiers distants orphelins (hors protectedRemotePaths) |
--rollback | Annule le dernier déploiement (ou --backup=ID) |
--backup=ID | Sauvegarde précise à restaurer (défaut : la plus récente) |
--help | Aide |
Codes de sortie : 0 succès, 1 erreur (config/transfert), 2 arguments invalides.
Rollback
Section titled “Rollback”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 :
php bin/deploy.php --rollback --dry-run # aperçu de la restaurationphp bin/deploy.php --rollback # restaure la dernière sauvegardephp bin/deploy.php --rollback --backup=20260627-143012 # une sauvegarde préciseLe 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 ;
backupRetentionborne l’historique. - Un fichier introuvable au moment de la sauvegarde (dérive du manifeste) est reclassé en « créé » → supprimé au rollback.
Fonctionnement
Section titled “Fonctionnement”- Scan :
LocalScannerparcourt le projet et calcule un hash par fichier (xxh128, replimd5), en élaguant les dossiers ignorés pendant le parcours. - 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
- Mirror (optionnel) : liste récursive du serveur ; tout fichier distant
absent en local et hors
protectedRemotePathsest supprimé. - 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.
Migrations SQL (delta par base)
Section titled “Migrations SQL (delta par base)”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.
Quelle base cible une migration ?
Section titled “Quelle base cible une migration ?”Une directive d’en-tête, sur sa propre ligne, déclare la base :
-- @database: boClé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.
Qu’est-ce qui est « non déployé » ?
Section titled “Qu’est-ce qui est « non déployé » ?”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.
Utilisation
Section titled “Utilisation”php bin/migrations-bundle.php # génère database/deploy/<base>.sqlphp bin/migrations-bundle.php --dry-run # liste le delta sans rien écrirephp bin/migrations-bundle.php --mark # marque le delta comme déployéFlux type :
php bin/migrations-bundle.php→ écritdatabase/deploy/*.sql- exécuter chaque fichier sur la base correspondante
(
mysql hxa_bo < database/deploy/bo.sql, ou via phpMyAdmin) php bin/migrations-bundle.php --mark→ avance le watermark- 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.