Aller au contenu

Les migrations

Vous avez ajouté un champ. La base ne le connaît pas. Kewos offre deux chemins, et choisir le mauvais est la façon la plus courante de perdre une colonne.

Rapprocher, ou migrer

kewos reconcilekewos migrate
Ce qu’il faitajoute ce qui manque : tables, colonnes sûresapplique un fichier écrit, quel qu’il soit
Ce qu’il ne fait jamaissupprimer, renommer, changer un typerien : il fait ce que le fichier dit
Où on l’utiliseà chaque déploiement, sur tous les tenantsquand le changement ne peut pas être deviné

Le rapprochement est additif par construction. C’est ce qui permet de le lancer à chaque déploiement sans le relire : il ne peut pas détruire, donc il n’a pas besoin d’être approuvé.

L’étape 2 du second parcours en est l’exemple : deux champs contribués à un modèle existant, et rien d’autre à faire.

main [active]: reconciled (0 migration(s), 2 column(s))

Voir l’écart avant d’y toucher

Fenêtre de terminal
kewos migrate plan --database-url "$KEWOS_DATABASE_URL"
- DropTable: DropTable(table='gear_item')
- AlterColumnType: AlterColumnType(table='esign_field', column='value_image',
from_type='BYTEA', to_type='BLOB')
- AddForeignKey: AddForeignKey(table='pipeline_lead', column='rivals_competitor_id',
target_table='rivals_competitor', target_column='id', on_delete='SET NULL')

Ce plan est réel, et il mérite d’être lu lentement, parce qu’il contient trois choses de natures très différentes : une clé étrangère à créer (inoffensif), un type à changer (à vérifier), et quatre tables à supprimer parce que leurs modules ne sont plus dans l’arbre lu par la commande.

Un plan est une proposition, pas un diagnostic. Il compare la base à ce que le registre déclare ici et maintenant ; un module absent du dossier ressemble donc à un module supprimé.

Écrire le fichier

Fenêtre de terminal
kewos migrate generate \
--database-url "$KEWOS_DATABASE_URL" \
--module pipeline_rivals --revision 0001_rivals \
--description "add the competitor links" --output migrations/
wrote migrations/0001_rivals.py (classification=destructive, down_revision=0001_reconcile_link)

Le mot destructive n’est pas décoratif : il est calculé à partir des opérations, il est écrit dans le fichier, et il vous dit qu’il faut le lire avant de l’appliquer.

"""Auto-generated migration: add the competitor links.
Module: pipeline_rivals
Classification: destructive
"""
revision = '0001_rivals'
down_revision = '0001_reconcile_link'
classification = 'destructive'
def upgrade() -> Migration:
return (
Migration()
.drop_table(table='gear_item')
.add_foreign_key(table='pipeline_lead', column='rivals_competitor_id',
target_table='rivals_competitor', target_column='id',
on_delete='SET NULL')
)
def downgrade() -> Migration:
# TODO: downgrade for DropTable on 'gear_item' cannot be auto-generated
# (data was lost); restore manually.
return (
Migration()
.drop_foreign_key(table='pipeline_lead', column='rivals_competitor_id',
target_table='rivals_competitor', target_column='id')
)

Le fichier se lit, et le retour arrière dit ce qu’il ne sait pas défaire. Une suppression de table ne se déjoue pas : la donnée n’est plus là. Ce TODO n’est pas une négligence du générateur, c’est la seule réponse honnête.

Votre travail sur ce fichier : retirer ce que vous n’avez pas voulu. Ici, les quatre drop_table de modules qui existent ailleurs.

auto ne tourne qu’en développement

Fenêtre de terminal
kewos migrate auto ...
MigrationGuardError: `kewos migrate auto` refuses to run outside development
(KEWOS_ENV is 'production'). Run `generate` then `apply` explicitly.

auto fait les trois gestes d’affilée : détecter, écrire, appliquer. C’est pratique sur votre poste et inacceptable ailleurs, parce que personne n’a lu le fichier entre le deuxième et le troisième. Le garde-fou refuse et nomme la marche à suivre au lieu de dire non.

Le piège qui ne se voit pas en test

Un modèle qui déclare une valeur par défaut au niveau serveur et une migration qui ne la pose pas donnent un couple silencieux : les tests créent leurs tables depuis le modèle, donc ils voient la valeur par défaut et passent. La production, elle, a la table créée par la migration, sans la valeur : la première insertion qui compte sur elle échoue.

Le symptôme est un test vert et une erreur 500 au premier enregistrement réel. Quand vous ajoutez un server_default, vérifiez que la migration le pose aussi.

L’ordre en production

  1. déployer le code ;
  2. kewos reconcile --confirm : les ajouts sûrs, sur tous les tenants ;
  3. kewos migrate apply seulement pour les fichiers qui ne pouvaient pas être devinés, après lecture.

Jamais migrate auto. Jamais un schéma créé automatiquement à partir des modèles.