Fait avec Chinaski

Mises à niveau & migrations

Mises à niveau et migrations : comment le schéma et le code de Chinaski avancent. Cette page est ancrée dans la mécanique réelle du dépôt : soixante-deux fichiers de migration numérotés comme récit d'évolution du schéma, et deux chemins de mise à niveau concrets : le script de déploiement en ligne et le script air-gapped de bundle signé.

Le récit des migrations (évolution du schéma)

  • migrations/ porte 62 fichiers SQL numérotés, de 001_phase2_database_foundation.sql à 062_form_submissions_read_at.sql. Chacun se documente lui-même : un en-tête listant ce qui change, et la commande d'application (sqlite3 chinaski.db < migrations/…) sur chaque fichier. Les noms de fichiers font double emploi de changelog : lisez le répertoire de bas en haut et vous lisez l'histoire du produit : la fondation phase-2 (contraintes CHECK, index de déduplication, colonnes mortes supprimées), les documents (phase 45), toute la famille des stacks (020 jusqu'à l'héritage en 043), le durcissement des forms (tokens de référence, attribution, quotas, validation du consentement, read-at), la journalisation d'événements, la hiérarchie/slots/renumérotation de la nav, les versions de la garde de promotion, les paramètres de durabilité du build, et le cache de rendu.
  • schema.sql est le point d'aboutissement des installations fraîches de la même histoire : une nouvelle installation bootstrape depuis schema.sql directement, donc les deux chemins doivent aboutir à la même forme. C'est imposé, pas supposé : bin/check-schema-sync.pl compare une base vivante à schema.sql et sort avec un code non nul accompagné d'une note « Fix: add the missing tables/columns to schema.sql » quand ils divergent. Le mémo de correctif est le propre contrat du projet : les installations fraîches doivent correspondre aux vivantes.
  • L'ordre des migrations est porteur de sens : le commentaire du script d'exécution note « Must run before phase41: pages/posts rebuild SELECTs og_image_url from existing rows, so a DB predating the column would fail that rebuild. » Un gros bloc de writers helpers dans le code ne s'exécute chacun que lorsque leur tour vient.
  • Chaque migration est écrite pour l'idempotence : des notes de type IF NOT EXISTS à travers le corpus des migrations (la langue a tourné deux fois dans un chemin d'installation fraîche/boot bien des fois), pour qu'un balayage de migrations au démarrage n'explose jamais sur des rejeux.

Exécuter les migrations : automatique

Les migrations tournent au démarrage de l'app : Chinaski::Migrations run_all() chaîne les helpers _apply_* dans un ordre fixé (_apply_perf_indexes d'abord, puis les familles content/stacks/forms/nav/doc dans l'ordre des dépendances). Un opérateur ne lance jamais une migration à la main ; l'application converge sa propre base vers le schéma courant du code.

Des estampilles de version existent là où une migration saute par détection de vieille base : un bump du PRAGMA user_version de SQLite à l'intérieur de l'un des helpers _apply_* de la chaîne (observé : la barrière qui déplace une entrée antérieure à la 53 directement à 53 pour sauter le travail antérieur sur une base récente). La correspondance avec les numéros de version courants est dans le code, pas dans une table ; aucune liste de versions face à l'opérateur n'est livrée.

Mettre à niveau une instance en marche

En ligne (sur un hôte connecté)

deploy/deploy.sh <N> : la recette permanente : 1. git tire l'arbre d'installation et installe les dépendances. 2. perl -c cms.pl vérifie la syntaxe de l'application (une casse de syntaxe avorte avant de toucher à quoi que ce soit). 3. Rebuild du site statique avec CHINASKI_DB/CHINASKI_OUTPUT fixés explicitement. 4. Redémarre le service, sauf si le builder a échoué, auquel cas le déploiement avorte et le service conserve l'arbre servi précédemment (un redémarrage par-dessus une sortie à moitié faite publierait une corruption du service).

Air-gapped

scripts/apply_update.sh : le script de mise à niveau hors ligne : 1. Sur une machine connectée, récupérez le bundle de version depuis son manifeste (un .tar.gz) et sa signature Ed25519. 2. Transférez les deux vers la cible et fournissez votre clé publique de release. 3. Le script vérifie d'abord la signature, sauvegarde l'arbre applicatif courant, puis applique la mise à jour, en gardant la version précédente récupérable.

Notification des mises à jour : fixez une URL de manifeste de mise à jour quand les mises à jour doivent être vérifiées ; les installations air-gapped sans CHINASKI_UPDATE_MANIFEST_URL ne se connectent jamais.

Restaurer à travers les frontières de version

Restaurer une sauvegarde refuse un décalage de version de schéma : une vieille sauvegarde ne se restaure que dans un schéma assorti, c'est-à-dire dans la version d'app correspondante. Donc mettre à niveau l'app pour correspondre à la version de schéma de la sauvegarde fait partie d'une procédure de restauration (la page de reprise après sinistre parcourt ce chemin).

Quand une mise à niveau apporte des changements de schéma, la mécanique de restauration des sauvegardes les reflète dans la barrière de schéma (la barrière de restauration de l'outillage), pas une migration automatique ; l'app démarre le changement au prochain bootstrap.

L'épinglage : les tests

L'hygiène des migrations est imposée dans la suite de tests aussi bien que dans les scripts :

  • Migration lint (migrations_lint.t) vérifie que les fichiers de migration suivent l'hygiène du projet (ids propres, rejeu sûr).
  • Les tests de migrations/suites de code exercent le flux réel run-all contre des bases de fixtures ; migrations_helpers fait tourner la mécanique avec des gestionnaires de base dry/mochés (CHINASKI_DB pointé vers n'importe quel chemin ; saute dans les tests).

Checklist pour une mise à niveau

  1. Sauvegardez d'abord (base de données + fichiers qui comptent ; soit la sauvegarde système, soit une archive in-app).
  2. deploy.sh <N> sur les hôtes connectés (ce qui fait vérification de syntaxe, rebuild, redémarrage), ou apply_update.sh avec un bundle signé sur un hôte air-gapped.
  3. Si le deploy.sh a échoué au niveau du schéma (par ex. les migrations n'ont pas tourné), vérifiez le journal : les migrations tournent au démarrage, pas pendant le script de déploiement lui-même.
  4. Divergence d'installation fraîche : lancez bin/check-schema-sync.pl pour comparer schema.sql à la base vivante, son code de sortie non nul signale immédiatement l'édition que les installations fraîches devront ajouter.
  5. Vérifiez que le site affiche les pages plus /health, vérifiez la complétude du build via l'historique des builds.
Lisez ce site en