🎯 Ce que cet article apprend
- Structurer un script Bash robuste pour Odoo : shebang portable, mode strict, gestion d'erreurs via
trap, helpers réutilisables - Automatiser les opérations de base Odoo : démarrage configuré, restore complet (zip+custom), dump horodaté avec filestore
- Industrialiser l'installation suivie des tests d'un module et la mise à jour groupée de tous les dépôts OCA
Cet article est l'épisode 3/5 de la série S01 — Boîte à outils Linux du dev Odoo. L'épisode précédent a couvert Git/GitHub pour la gestion des addons et submodules OCA. La présente section bascule sur Bash : cinq scripts opérationnels, validés syntaxiquement (bash -n), prêts à coller dans ~/bin/ et à appeler en une frappe depuis le terminal.
1. Hygiène d'un script Bash propre — les fondations
Avant les cinq scripts métier, un squelette commun s'impose. Tout script Bash destiné à manipuler une base Odoo ou un filestore doit fail fast au premier signe d'anomalie. Trois lignes en tête de fichier suffisent à transformer un script fragile en outil de production.
#!/usr/bin/env bash
set -euo pipefail
trap 'echo "ERREUR ligne $LINENO"; exit 1' ERR
# Convention : variables d'environnement en UPPERCASE
ODOO_HOME="$HOME/odoo-dev"
DB_USER="odoo"
# Fonctions en snake_case
usage() {
echo "Usage: $0 <arg1> <arg2>"
exit 1
}
# Guard d'arguments — quitter proprement si appel incorrect
[ $# -lt 2 ] && usage
# Corps du script ici…
echo "[script] Démarrage avec $1 et $2"
Le shebang #!/usr/bin/env bash est préféré à #!/bin/bash : il résout l'interpréteur via le PATH, ce qui rend le script portable entre Ubuntu (Bash dans /usr/bin/bash) et macOS (souvent /opt/homebrew/bin/bash pour une version récente). Le trap sur le signal ERR intercepte toute commande qui retourne un code non nul et imprime la ligne fautive — précieux quand le script enchaîne dix appels et que l'un d'eux échoue silencieusement.
📖 Définition — set -euo pipefail
-e (errexit) interrompt le script au premier code retour non nul. -u (nounset) lève une erreur si une variable non définie est référencée — fin des typos silencieuses du type $HOM au lieu de $HOME. -o pipefail propage l'erreur dans les pipes : sans cette option, cmd1 | cmd2 retourne uniquement le code de cmd2 et masque un échec de cmd1. Le combo des trois constitue le mode strict standard de tout script de production, recommandé par le Google Shell Style Guide.
🛠 Créer et exécuter ces scripts
Chaque script présenté dans la suite de l'article se met en place en trois temps. Créer le fichier avec un éditeur en ligne de commande :
nano ~/bin/start-odoo.sh
Coller le contenu du script, enregistrer (Ctrl+O puis Entrée) et quitter (Ctrl+X). Rendre ensuite le fichier exécutable, puis le lancer par son chemin :
chmod +x ~/bin/start-odoo.sh # une seule fois, à la création
~/bin/start-odoo.sh # exécution
La section 7 de cet article détaille comment regrouper ces fichiers dans ~/bin/, les rendre accessibles depuis n'importe quel répertoire via le PATH, et versionner sa boîte à outils.
2. start-odoo.sh — démarrer la sandbox avec la bonne config
Lancer Odoo en mode dev demande systématiquement la même séquence : activer le virtualenv Python, se placer dans le répertoire des sources, pointer le bon fichier de configuration, rediriger les logs vers un fichier horodaté pour analyse post-mortem. Un script de quinze lignes encapsule la routine.
#!/usr/bin/env bash
set -euo pipefail
trap 'echo "ERREUR ligne $LINENO"; exit 1' ERR
ODOO_HOME="$HOME/odoo-dev"
VENV="$ODOO_HOME/venv"
CONFIG="$ODOO_HOME/odoo.conf"
LOG="$HOME/odoo-logs/odoo-$(date +%Y%m%d-%H%M).log"
mkdir -p "$(dirname "$LOG")"
source "$VENV/bin/activate"
cd "$ODOO_HOME/odoo"
echo "[start-odoo] Lancement Odoo 19 — log: $LOG"
./odoo-bin -c "$CONFIG" --logfile "$LOG" --workers=0
L'instruction source "$VENV/bin/activate" active l'environnement Python isolé : toutes les dépendances Odoo (psycopg2, lxml, reportlab) sont prises depuis le venv et non depuis le Python système — protection indispensable contre la pollution de paquets. L'option --workers=0 force le mode multi-thread : pratique en dev pour conserver un seul processus Python et garder le contrôle PID. Dès que --workers dépasse zéro, Odoo bascule en multi-process WSGI, comportement réservé à la production.
start-odoo.sh sur une sandbox Ubuntu 24.04. Le script active le venv, se place dans le répertoire des sources et lance odoo-bin avec config et log horodaté. Les lignes INFO tracent le chargement des modules, suivies de l'écoute HTTP sur le port 8069. Le log complet reste consultable a posteriori dans ~/odoo-logs/.3. restore-db.sh — drop + create + restore multiformat
Le développeur Odoo restaure quotidiennement des bases : copie d'une démo client pour reproduire un bug, repartage d'une base de test entre collègues, retour à un point de référence après un test destructif. Le script doit accepter les deux formats coexistants : le zip natif Odoo (dump.sql + filestore/ + manifest.json) et le format custom pg_dump -Fc.
#!/usr/bin/env bash
set -euo pipefail
trap 'echo "ERREUR ligne $LINENO"; exit 1' ERR
usage() { echo "Usage: $0 <dump.dump|dump.zip> <db_target>"; exit 1; }
[ $# -lt 2 ] && usage
DUMP="$1"
DB_TARGET="$2"
FILESTORE_DIR="$HOME/.local/share/Odoo/filestore/$DB_TARGET"
# Drop si existe puis recréation
psql -U odoo -h localhost -d postgres -c "DROP DATABASE IF EXISTS \"$DB_TARGET\";"
psql -U odoo -h localhost -d postgres -c "CREATE DATABASE \"$DB_TARGET\";"
# Restore selon format du fichier source
case "$DUMP" in
*.dump)
pg_restore --no-owner -d "$DB_TARGET" "$DUMP"
;;
*.zip)
TMPDIR=$(mktemp -d)
unzip -q "$DUMP" -d "$TMPDIR"
psql -U odoo -h localhost -d "$DB_TARGET" -f "$TMPDIR/dump.sql"
rm -rf "$FILESTORE_DIR"
mv "$TMPDIR/filestore" "$FILESTORE_DIR" 2>/dev/null || true
rm -rf "$TMPDIR"
;;
*)
echo "Format non supporté: $DUMP"
exit 2
;;
esac
echo "[restore-db] $DB_TARGET restauré depuis $DUMP"
Le case Bash branche selon l'extension. Pour un fichier .dump (format custom), pg_restore --no-owner rejoue la structure et les données sans tenter de restaurer le propriétaire des objets (utile quand l'utilisateur PostgreSQL du poste dev diffère de celui de la source). Pour un fichier .zip Odoo, l'archive est extraite dans un répertoire temporaire, le dump.sql rejoué via psql -f, puis le sous-répertoire filestore/ déplacé dans ~/.local/share/Odoo/filestore/<db>/. La restauration n'est jamais complète sans le filestore — la base seule perd toutes les pièces jointes binaires.
4. dump-and-clean.sh — pg_dump custom + tarball filestore
Le pendant du restore : produire un dump exploitable à coller dans une archive, transférer vers un VPS de staging, ou déposer dans un bucket S3 quotidien. Le script combine pg_dump -Fc (base) et tar czf (filestore) en deux fichiers horodatés, ce qui accélère la suite — le restore est plus rapide en deux fichiers séparés qu'en un zip monolithique.
#!/usr/bin/env bash
set -euo pipefail
trap 'echo "ERREUR ligne $LINENO"; exit 1' ERR
DB="${1:-}"
[ -z "$DB" ] && { echo "Usage: $0 <db_name>"; exit 1; }
STAMP=$(date +%Y%m%d-%H%M)
OUTDIR="$HOME/odoo-dumps/$DB"
mkdir -p "$OUTDIR"
echo "[dump] pg_dump -Fc sur $DB..."
pg_dump -Fc --no-owner -f "$OUTDIR/${DB}-${STAMP}.dump" "$DB"
echo "[dump] Tarball filestore..."
FS="$HOME/.local/share/Odoo/filestore/$DB"
[ -d "$FS" ] && tar czf "$OUTDIR/${DB}-filestore-${STAMP}.tgz" -C "$(dirname "$FS")" "$DB"
echo "[vacuum] VACUUM ANALYZE (optionnel)..."
psql -U odoo -h localhost -d "$DB" -c "VACUUM ANALYZE;" || true
echo "[dump-and-clean] terminé → $OUTDIR/"
ls -lah "$OUTDIR/" | tail -5
Le flag -Fc de pg_dump produit un fichier binaire compressé (typiquement 5 à 10 fois plus compact qu'un dump SQL plain), restaurable uniquement via pg_restore. L'option -C de tar change le répertoire de travail avant d'archiver, ce qui évite que le chemin absolu /home/user/.local/share/Odoo/filestore/ n'apparaisse dans l'archive — le tarball reste relocalisable sur n'importe quel poste. Le VACUUM ANALYZE final rafraîchit les statistiques de l'optimiseur PostgreSQL après le dump ; le || true empêche un échec ponctuel (lock concurrent) d'interrompre le script.
🔧 Nouveauté v19 — Python 3.10-3.13 et PostgreSQL 13 minimum
Odoo 19 supporte Python 3.10 à 3.13 (constantes MIN_PY_VERSION et MAX_PY_VERSION dans odoo/release.py). Ubuntu 24.04 LTS livre Python 3.12 par défaut, parfaitement dans la plage recommandée. Côté base, la version minimale de PostgreSQL est PG 13 (MIN_PG_VERSION = 13, même fichier). Ubuntu 24.04 livre PG 16, également compatible. Les scripts ci-dessus n'ont donc aucune adaptation à prévoir sur une sandbox Ubuntu 24.04 récente — le combo Python 3.12 + PG 16 est nativement supporté.
5. install-and-test.sh — installer un module + tests + stop
La boucle TDD Odoo se résume à trois étapes répétées : créer une base de test fraîche, installer le module avec --test-enable, vérifier le code retour. Manuellement, c'est trois commandes psql et une commande odoo-bin longue à retaper. Le script encapsule le tout en une frappe : install-and-test.sh adi_smt_elevator.
#!/usr/bin/env bash
set -euo pipefail
trap 'echo "ERREUR ligne $LINENO"; exit 1' ERR
MODULE="${1:-}"
DB="${2:-test_$(date +%s)}"
[ -z "$MODULE" ] && { echo "Usage: $0 <module> [db_test]"; exit 1; }
ODOO_HOME="$HOME/odoo-dev"
CONFIG="$ODOO_HOME/odoo.conf"
source "$ODOO_HOME/venv/bin/activate"
cd "$ODOO_HOME/odoo"
echo "[install-and-test] Module: $MODULE · Base: $DB"
# Création base si absente
psql -U odoo -h localhost -d postgres -c "CREATE DATABASE \"$DB\";" || true
# Install + test ciblé + stop after init
./odoo-bin -c "$CONFIG" \
-d "$DB" \
-i "$MODULE" \
--test-enable \
--test-tags="/$MODULE" \
--stop-after-init \
--workers=0 \
2>&1 | tee "/tmp/test-${MODULE}-$(date +%s).log"
echo "[install-and-test] terminé"
Le triplet --test-enable --test-tags="/$MODULE" --stop-after-init est le pattern Odoo 19 officiel pour piloter les tests en CLI. L'option --test-tags accepte une syntaxe complète [-][tag][/module][:class][.method], mais la forme /MODULE filtre suffisamment pour cibler le module visé sans relancer les tests des dépendances déjà testées en amont. Le tee double la sortie : affichage temps réel sur le terminal pour suivre l'exécution, plus archivage dans /tmp/ pour grep ultérieur sur les FAIL ou ERROR.
⚠️ Piège — --test-enable sans --test-tags
L'enchaînement --stop-after-init + --test-enable seul (sans --test-tags) lance tous les tests de tous les modules installés dans la base, pas uniquement le module visé. Sur une base avec quarante modules custom, l'exécution peut dépasser vingt minutes. Préciser --test-tags="/MODULE" est obligatoire pour cibler. Deuxième piège : si une dépendance du module n'est pas installée, l'exécution échoue silencieusement avec un WARN dans la sortie, sans code retour non nul. Toujours grepper la sortie sur WARN.*test avant de conclure « tests passés ».
6. update-all-addons.sh — git pull groupé sur tous les dépôts OCA
Une sandbox dev Odoo héberge typiquement dix à trente dépôts OCA en submodules ou en clones plats. Mettre à jour chacun à la main devient vite une corvée. Le script balaie le répertoire parent, détecte les dépôts Git, et lance un git pull --rebase --autostash sur chacun.
#!/usr/bin/env bash
set -euo pipefail
trap 'echo "ERREUR ligne $LINENO"; exit 1' ERR
ADDONS_BASE="$HOME/odoo-dev/addons-oca"
echo "[update-all-addons] Sweep $ADDONS_BASE"
for repo in "$ADDONS_BASE"/*/; do
if [ -d "$repo/.git" ]; then
cd "$repo"
branch=$(git rev-parse --abbrev-ref HEAD)
echo ""
echo "▶ $(basename "$repo") (branche: $branch)"
git pull --rebase --autostash || echo " ⚠ pull échoué"
fi
done
echo ""
echo "[update-all-addons] Tous les dépôts traités"
Le drapeau --rebase remplace le merge par défaut : la branche locale est reposée linéairement par-dessus la branche distante, sans commit de merge parasite qui polluerait l'historique. Le drapeau --autostash remise automatiquement les modifications non commitées avant le rebase, puis les restaure après — fin des refus de pull pour cause de working tree dirty. Le || echo en fin de ligne empêche un échec sur un dépôt isolé (conflit non résolu, branche supprimée upstream) d'arrêter la sweep complète. La sortie est silencieuse en cas de succès, verbeuse en cas d'avertissement — exactement ce qu'il faut pour passer en cron quotidien.
💡 Astuce — Code retour de odoo-bin et pipefail
Le code retour de ./odoo-bin --test-enable --stop-after-init reflète bien le résultat global des tests : 0 si tous passent, non-zéro sinon. Mais dès que la sortie est pipée vers tee ou grep, le code retour devient celui du dernier élément du pipe (tee retourne presque toujours 0). Sans set -o pipefail, le script ignore complètement l'échec d'odoo-bin. Le mode strict set -euo pipefail activé en tête du script install-and-test.sh garantit que le code retour réel d'odoo-bin est bien propagé jusqu'à l'appelant et que la CI s'arrête en rouge sur le moindre FAIL.
7. Où ranger ces scripts et comment versionner sa toolbox
Cinq scripts orphelins dans /tmp/ finissent toujours par disparaître. La convention Linux standard place les scripts personnels dans ~/bin/, ajouté au PATH via .bashrc. Toute commande devient alors invocable depuis n'importe quel répertoire.
# Une fois dans ~/.bashrc, après reload (source ~/.bashrc)
export PATH="$HOME/bin:$PATH"
# Trois alias raccourcis pour les scripts les plus fréquents
alias startodoo='~/bin/start-odoo.sh'
alias dumpit='~/bin/dump-and-clean.sh'
alias testmod='~/bin/install-and-test.sh'
# Versionner la toolbox dans un repo dotfiles dédié
mkdir -p ~/dotfiles/bin
mv ~/bin/*.sh ~/dotfiles/bin/
ln -s ~/dotfiles/bin ~/bin
# Initialiser le repo Git de la toolbox
cd ~/dotfiles
git init && git add . && git commit -m "Initial toolbox Odoo"
Le pattern dotfiles + lien symbolique sépare la toolbox de l'historique shell : les scripts vivent dans ~/dotfiles/bin/ sous contrôle Git, et ~/bin n'est qu'un lien symbolique vers ce répertoire. Un git push sur un dépôt privé (GitHub, Codeberg) et la toolbox suit le développeur sur tout nouveau poste en deux commandes : git clone + ln -s. L'épisode S04 de la série utilise les mêmes scripts comme préalable à l'exploration de odoo-bin shell.
~/bin/, listée par tree -L 2. Les cinq scripts (start-odoo.sh, restore-db.sh, dump-and-clean.sh, install-and-test.sh, update-all-addons.sh) apparaissent avec leurs permissions rwxr-xr-x. Le répertoire ~/bin est un lien symbolique vers ~/dotfiles/bin/ versionné Git.8. Les 5 scripts en synthèse
La table ci-dessous récapitule les cinq scripts couverts par l'article, avec leur rôle, leur commande type et le gain de temps estimé sur une journée de développement Odoo standard (cinq cycles install/test, deux restaurations, un dump quotidien, une mise à jour OCA matinale).
| # | Script | Rôle | Commande type | Gain estimé |
|---|---|---|---|---|
| 1 | start-odoo.sh | Lancer Odoo avec venv + config + log horodaté | startodoo | ~5 min/jour |
| 2 | restore-db.sh | Drop + create + restore multiformat (zip/custom) | restore-db.sh demo.zip test_db | ~10 min/restore |
| 3 | dump-and-clean.sh | pg_dump custom + tarball filestore horodaté | dumpit ma_base | ~5 min/dump |
| 4 | install-and-test.sh | CREATE DB + install + tests ciblés + stop | testmod adi_smt_elevator | ~8 min/cycle (×5 = 40 min) |
| 5 | update-all-addons.sh | Sweep git pull --rebase --autostash sur dépôts OCA | update-all-addons.sh | ~10 min/matin |
Cumul théorique sur une journée type : environ une heure récupérée, dont 40 minutes sur le seul cycle install+test du module en développement actif. Le retour sur investissement (temps d'écriture des cinq scripts ≈ une heure) est atteint dès la première journée de production. À adapter au contexte réel : le gain dépend de la fréquence de chaque opération.
Voir aussi dans la série
S01 — Linux : 30 commandes pour la sandbox
logs, processus, ports, permissions, systemd, alias .bashrc.
S02 — Git & GitHub : 20 commandes pour cloner, brancher, contribuer
clone shallow, submodules OCA, workflow feature-branch, PR via gh.
S03 — Bash : 5 scripts qui font gagner 1 heure par jour
start-odoo.sh, restore-db.sh, dump-and-clean.sh, install-and-test.sh, update-all-addons.sh.
S04 — odoo-bin shell : 15 patterns ORM essentiels
env, search_fetch v19, Domain, flush_model / invalidate_model.
S05 — PostgreSQL : psql, SELECT, dump propre
Requêtes psql, EXPLAIN ANALYZE, garde-fous UPDATE / DELETE, CTA E3.
Articles complémentaires
#54 — Configurer l'environnement de développement Odoo 19
Environnement Python + addons-path — base technique des scripts présentés.
#57 — Gestion des bases de données Odoo 19
Création, restauration, sauvegarde — théorie complémentaire aux scripts dump/restore.