La règle qui évite la plupart des mauvaises surprises sur Odoo.sh tient en une phrase : rien n'arrive en production sans un build vert sur une copie réelle de la base du client, avec le même commit que celui qui va être fusionné. La documentation explique la plateforme, pas le flux d'un partner. Voici le nôtre.
Cet article complète et remplace Odoo.sh pour l'ecommerce ; le résumé pour les boutiques se trouve à la fin.
Trois étapes, et ce que chacune fait vraiment
Odoo.sh a trois étapes : production (une seule branche), staging et développement. La différence tient à la base avec laquelle démarre chaque build :
- Développement : base neuve avec démo, installe les modules de la branche et exécute les tests ; dure environ trois jours. C'est la seule étape qui teste : les tests dépendent de la démo.
- Staging : le build duplique la base de production et la neutralise. La copie est supprimée au bout d'un mois.
- Production : le push redémarre le serveur ; si vous avez augmenté la version du module dans
__manifest__.py, il exécute la mise à jour (équivalente à-u) et l'instance passe en maintenance. En cas d'échec, il revient à la révision précédente et restaure la base.
D'où la conséquence que presque personne ne lit : fusionner transporte le code, jamais ce que vous avez modifié à la main dans la base de staging. Ce que vous voulez voir arriver doit figurer dans le XML du module, avec la version augmentée.
Structure de branches pour un partner
Avec un seul client, dev, staging et production suffisent. Avec plusieurs : une branche de développement par tâche ; une branche de staging par client et par livraison, reconstruite avant chaque validation ; l'unique branche de production qu'impose Odoo.sh ; et, si le module va sur l'App Store de Odoo, une par version d'Odoo.
Dans notre dépôt, il y a aujourd'hui 144 branches, dont 17.0, 18.0, 19.0 et production : 41 portent le suffixe -17, -18 ou -19 (un connecteur, une version) et 19 sont production-pre-<cambio>-<fecha> : le commit qui faisait tourner la production avant chaque déploiement délicat. Revenir en arrière, c'est un push.
Piège vérifié : une branche créée par git est construite avec la version par défaut du projet, pas avec celle de la branche dont vous partez. Nous avons créé une -17 à partir de 17.0 et Odoo.sh l'a construite en 19.0 : le manifest 17.0.x est resté non installable. La version s'assigne dans les paramètres, et uniquement sur les branches de développement.
Le build comme porte : ce qu'il vérifie et ce qu'il ne vérifie pas
Un build est vert (sans erreurs ni avertissements), jaune (avertissements) ou rouge (erreurs) ; seul le vert se livre. Un build de développement vérifie que les modules de la branche s'installent sur une base propre avec démo et que leurs tests passent. Ce qu'il ne vérifie pas :
- Les modules hors de la branche. Par défaut, il n'installe que les vôtres, sans sous-modules. Dans les paramètres : installation complète (sous-modules et tous les modules standard, mais sans tests) ou une liste de noms techniques séparés par des virgules, qui est la plus utile.
- L'upgrade. Il installe à partir de zéro ; il n'exécute jamais
-usur une base qui a un historique. - Les données réelles. C'est le rôle du staging, qui n'exécute pas de tests.
C'est pourquoi la porte a deux battants : le build de développement exécute des tests qui installent, pas seulement des tests unitaires ; et la branche de staging exécute l'upgrade réel sur la copie de production, en lisant update.log jusqu'au bout. Regardez la ligne 0 failed, 0 error(s) of N tests avec N supérieur à zéro : un vert à zéro test est vide. Plus de causes dans un module Odoo 19 compile mais ne s'installe pas.
Staging avec données : ce que résout la copie et ce qu'elle ne résout pas
La neutralisation résout ce qui est dangereux : aucun e-mail ne part (ils s'affichent dans l'onglet Mails), les actions planifiées ne tournent pas, les IAP sont désactivés, transporteurs et passerelles passent en mode test, et neutralize.log indique ce qui a été désactivé. Ce qu'elle ne résout pas :
- L'anonymisation reste à votre charge. Elle arrête des processus, elle n'efface pas les données personnelles. Si l'équipe ne doit pas voir les données du client : Developer n'accède ni au staging ni à la production, Tester accède au staging et seul Admin accède à la production.
- Les identifiants des API externes voyagent dans la copie. Un connecteur en staging avec les clés de production parle à Amazon ou à Mirakl comme s'il était en production : activez son mode sandbox ou videz les clés.
- La base de staging ne se rafraîchit pas toute seule. Par défaut, la branche met à jour le build précédent et la base survit entre les pushs, avec les données déjà modifiées ; avec New build, chaque push part d'une copie fraîche. Les crons se déclenchent à la main, et les sauvegardes manuelles durent trois jours, avec un plafond de cinq par jour.
SSH et psql en production : ce qu'on touche et ce qu'on ne touche pas
Odoo.sh donne un shell en production. Nous y entrons pour lire (psql, lnav ~/logs/odoo.log), diagnostiquer avec odoo-bin shell et exécuter la suite de tests d'un module en mode transactionnel. Ce que nous ne faisons pas : un UPDATE à la main ni installer des modules en contournant le build. Des détails qui coûtent une après-midi : scp et sftp sont bloqués, le rôle Postgres ne peut pas créer de bases et les modules propres se trouvent sous ~/src/user. Un soulagement : odoo-bin shell fait un rollback à la sortie en 17, 18 et 19 (odoo/cli/shell.py).
Upgrade en production : noupdate, base.group_system et migrations
Un upgrade se déclenche en augmentant la version dans le manifest ; Odoo.sh effectue une sauvegarde marquée Update (aussi si requirements.txt change) et exécute le -u. C'est ici que se trouve le piège le plus coûteux que nous ayons rencontré. L'idiome habituel pour que l'administrateur hérite de votre groupe est :
<record id="base.group_system" model="res.groups">
<field name="implied_ids" eval="[(4, ref('group_mi_manager'))]"/>
</record>Il fonctionne sur une installation neuve et, lors d'un upgrade, il est ignoré en silence. La raison se trouve dans la base du client : noupdate vit dans la ligne de ir_model_data. Lors de la mise à jour, le chargeur ne réécrit que l'enregistrement if not (update and d_noupdate) (odoo/orm/models.py en 19, odoo/models.py en 17 et 18), et l'upsert qui maintient cette table rafraîchit le modèle et res_id mais jamais la colonne noupdate : une fois posée, elle ne s'enlève pas. Et elle ne se déduit pas de l'addon : dans les trois versions, le record de base.group_system se trouve dans un <data> sans noupdate et peut pourtant arriver marqué :
select name, noupdate from ir_model_data
where module='base' and name in ('group_system','group_user');Dans notre production sur Odoo.sh, il renvoie t pour les deux ; dans les 69 bases que notre banc d'essai a créées de zéro, group_user donne t et group_system, f. Le même XML, deux résultats.
Cela nous est arrivé avec notre connecteur Mirakl 16.15.0 : les identifiants sont passés dans un groupe « Mirakl Manager ». Sur les installations neuves, l'administrateur en héritait ; sur les installations mises à jour, le groupe est resté sans membres et personne ne pouvait toucher aux clés. Les tests étaient verts parce qu'une installation propre applique bien le record. La correction, en 16.15.1 : conserver le XML et ajouter migrations/19.0.16.15.1/post-migrate.py, qui écrit l'implication en SQL sur res_groups_implied_rel et res_groups_users_rel avec ON CONFLICT DO NOTHING, plus un test qui échoue si le groupe reste vide.
Les migrations : dossier migrations/<versión>/ avec des fichiers pre-*.py, post-*.py et end-*.py, chacun avec migrate(cr, version), où version est la version qui était installée. Odoo ne les exécute que lorsque le module est marqué pour mise à jour : sur une installation neuve, aucune ne s'exécute, c'est pourquoi le XML est nécessaire. Si la version majeure change, le processus est différent : erreurs de migration vers Odoo 19 et la checklist de go-live.
Les pièges qui ne figurent pas dans la documentation
- Des builds qui s'endorment. Un build de développement inutilisé hiberne et ses crons ne tournent pas. Si vous l'utilisez comme banc d'essai, gardez-le éveillé : nous avons un agent launchd qui, toutes les 240 secondes, fait
curl /web/healthetssh -n … truecontre chaque build. - Le build que vous validez peut être l'ancien. L'identifiant change à chaque push et le précédent met du temps à être recyclé : en SSH, deux coexistent. Avant de valider quoi que ce soit, faites
grepde ce que vous venez de modifier dans~/src/user. - La série du manifest échoue différemment selon le sens. En 19, un manifest
18.0.xou17.0.xne plante pas : le serveur avertit has an incompatible version, setting installable=False. À l'inverse, en 17 ou en 18, un19.0.x.y.zinterrompt la lecture avec invalid manifest.
Checklist de livraison au client
- Build vert (pas jaune) en développement, avec des tests qui installent et N supérieur à zéro.
- Staging reconstruit aujourd'hui à partir de la production ; identifiants externes en sandbox ou vides.
- Version augmentée dans le manifest et
update.loglu jusqu'au bout, migrations comprises. - Validation du client sur le staging, avec les crons à la main et les e-mails vérifiés dans Mails.
- Branche
production-pre-<cambio>-<fecha>à partir du commit qui fait tourner la production, et sauvegarde manuelle si des données sont touchées. - Fusion hors des heures de pointe puis
odoo.log, le groupe de permissions avec des membres et les crons actifs.
Nous proposons ce flux sous forme d'ingénierie Odoo pour cabinets de conseil et nous l'utilisons dans chaque implémentation et migration vers Odoo 19. Si vous êtes partner ou éditeur de logiciels, le programme de partners technologiques explique comment nous travaillons.
Si vous avez un ecommerce
Toucher à un connecteur de marketplace ou à une règle de stock en production, c'est jouer avec des commandes réelles : étiquettes en double, commandes importées deux fois, synchronisations à moitié faites. Le staging accueille les nouveaux modules, les changements de stock et les mises à jour de connecteurs (Amazon, Mirakl, ManoMano, SEUR, MRW, Correos Express), et là transporteurs et passerelles passent en mode test : c'est l'endroit où tester une étiquette sans que le camion parte.
Questions fréquentes
Odoo.sh exécute-t-il les tests en staging ou en production ?
Non. Uniquement dans les builds de développement, sur une base neuve avec démo. Le staging valide avec des données réelles sans tests ; la production ne charge pas la démo et ne teste pas.
Un build vert garantit-il que le module s'installe dans l'Odoo du client ?
Il garantit qu'il s'installe sur une base propre de cette version. Il ne garantit ni l'upgrade sur une base avec historique ni la cohabitation avec des modules étrangers à la branche : cela se couvre dans le staging du client.
Liens utiles chez FlexigoTech
Ce que nous faisons à ce sujet
Vous livrez des projets sur Odoo.sh et vous voulez un banc d'essai qui ne dépende pas de la chance ?
Nous mettons en place le flux de branches, le build comme porte et les migrations pour vos clients, ou nous révisons celui que vous avez déjà. Écrivez à comercial@flexigobe.com ou appelez le +34 616 809 504.

