Organiser les patches d'une application
Organiser les patches d'une application
Un patch est un script Python qui modifie le schéma ou les données de la base pendant bench migrate. Le fichier patches.txt d'une application liste ses patches. Dodock exécute chaque patch une seule fois par site et l'enregistre dans le Journal de Patch.
Sections du fichier patches.txt
Le fichier patches.txt se divise en sections. La section d'un patch décide de son moment d'exécution :
| Section | Exécution | Usage |
|---|---|---|
[pre_model_sync] | Avant la synchronisation du schéma des DocTypes | Patch qui lit l'ancien schéma (colonne renommée ou supprimée par la nouvelle version) |
[post_model_sync] | Après la synchronisation du schéma | Patch de données qui utilise le nouveau schéma |
[post_fixture_sync] | Après la synchronisation des fixtures, des Champs personnalisés et des Property Setters | Patch qui utilise un champ ou un DocType ajouté par une fixture ou une personnalisation |
Dans une section, les patches s'exécutent dans l'ordre du fichier. Les sections [pre_model_sync] et [post_model_sync] sont obligatoires dans un fichier à sections. La section [post_fixture_sync] est facultative.
[pre_model_sync]
mon_app.patches.v2_0.renommer_ancienne_colonne
[post_model_sync]
mon_app.patches.v2_0.mettre_a_jour_statuts
[post_fixture_sync]
mon_app.patches.v2_0.remplir_remise_fidelite
Une ligne qui commence par execute: contient une instruction Python à la place d'un chemin de module :
[post_model_sync]
execute:frappe.delete_doc_if_exists("Report", "Ancien rapport")
Créer un patch
- Lancez la commande interactive depuis le dossier du bench :
bench create-patch - Choisissez l'application, puis le DocType concerné.
- Décrivez le patch. La description devient la docstring et propose un nom de fichier.
La commande crée le fichier dans le dossier patches du DocType. Elle ajoute aussi son chemin à la fin de patches.txt, donc dans la dernière section du fichier. Déplacez la ligne si le patch doit aller dans une autre section.
Le fichier contient une fonction execute() sans argument. Écrivez la modification dans cette fonction.
Exemple
Cet exemple est fictif. Une application ajoute à Client deux champs personnalisés par une fixture : custom_statut_fidelite (Bronze, Argent, Or) et custom_remise_fidelite. Un patch remplit la remise selon le statut.
# mon_app/patches/v2_0/remplir_remise_fidelite.py
import frappe
REMISES = {"Bronze": 5, "Argent": 10, "Or": 15}
def execute():
for statut, remise in REMISES.items():
frappe.db.set_value(
"Customer",
{"custom_statut_fidelite": statut},
"custom_remise_fidelite",
remise,
update_modified=False,
)
Le patch va dans [post_fixture_sync]. Dans [post_model_sync], les champs personnalisés n'existent pas encore lors d'une première installation de la version, et le patch échoue.
Écrire un patch sûr
- Rendez le patch rejouable : une deuxième exécution ne doit rien casser.
- Testez la migration sur une copie de la base avant la production.
- Gardez le patch court. Pour un gros volume, traitez les données par lots.
Vérifier l'exécution
Ouvrez la liste Journal de Patch. Chaque patch exécuté y figure avec sa date. Avec bench migrate --skip-failing, un patch en échec y figure comme ignoré, et la migration continue. Pour interdire cela sur un patch critique, utilisez le hook never_skip_patches (voir la Référence des hooks).