Skip to content
bemadePublic

About

Odoo development CLI tool

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

odoo-dev

A CLI tool for managing Odoo development environments. Handles local Python setup, Docker containers, database operations, and more.

It is the successor to the older odoo-deploy shell scripts — if you have notes for odoo-deploy, the rough mapping is: odoo-dev docker start/stop/build replaces the old odoo-dev.sh start/stop/build, and odoo-dev run/test/shell give you a local (venv-based) workflow that odoo-deploy didn't.

Installation

# Install with uv (recommended) — installs the published package from PyPI
uv tool install odoo-dev

# Or with pip
pip install odoo-dev

Then make sure the install location is on your PATH (uv prints the path; usually ~/.local/bin):

uv tool update-shell   # or: export PATH="$HOME/.local/bin:$PATH"

Quick Start

# In your Odoo project directory
cd my-odoo-project

# Full setup: clone Odoo repos, create venv, install deps, configure VSCode
odoo-dev setup

# Or for community edition only
odoo-dev setup --community

setup reads ODOO_VERSION / PYTHON_VERSION from a .env in the project root (or prompts for them and offers to save). It then clones the Odoo repos, builds a .venv, installs system dependencies, and generates conf/odoo.conf. It will offer to set up Docker at the end — answer "no" if you only want the local venv workflow.

Database setup (read this before your first run/test)

The generated conf/odoo.conf connects as PostgreSQL user odoo over the local socket. A running PostgreSQL server is a prerequisite you provide yourself — on every platform. setup installs only the PostgreSQL client and build dependencies (macOS: libpq; Linux: postgresql-client + libpq-dev); it never installs, starts, or configures a server, and never creates the odoo role. So on a fresh machine, install a server, start it, and create the role once:

macOS (Homebrew):

brew install postgresql@18                  # install a server (pick your version)
brew services start postgresql@18           # start it
createuser -s odoo                          # create the role odoo.conf expects
# Homebrew's versioned postgres is keg-only; add its bin to PATH if psql/createuser aren't found:
#   export PATH="$(brew --prefix postgresql@18)/bin:$PATH"

Debian/Ubuntu:

sudo apt-get install postgresql     # install a server if you don't already have one
sudo systemctl start postgresql
sudo -u postgres createuser -s odoo

Using a different / remote / Docker PostgreSQL: set DB_HOST, DB_PORT, DB_USER, DB_PASSWORD in .env before running setup (it writes them into conf/odoo.conf), or edit conf/odoo.conf directly. With no DB_HOST, odoo-dev connects over the local socket as the odoo role.

Before launching, run/test/shell/update run a quick connection preflight: if the server is unreachable, the role is missing, or authentication fails, you get a specific one-line fix instead of a stack trace.

Commands

Local Development (default)

odoo-dev run                          # Start Odoo locally (default port 8069)
odoo-dev run -d mydb -p 8070          # Pick a database and HTTP port
odoo-dev run -d mydb -i base          # Initialize module(s) on start
odoo-dev run -d mydb --dev reload     # With hot reload
odoo-dev run --debug                  # With debugpy (VSCode attach on 5678)
odoo-dev shell mydb                   # Open an Odoo shell
odoo-dev update base -d mydb          # Update modules
odoo-dev test my_module               # Run a module's tests (coverage on by default)
odoo-dev test my_module --test-tags my_module --no-coverage
odoo-dev test                         # Auto-discover & test all addons in addons/ + vendored/
odoo-dev scaffold my_module           # Create a new module

Note: the HTTP port flag is -p / --port (not --http-port).

Database Operations

odoo-dev db list                      # List databases
odoo-dev db restore backup.zip        # Restore from backup (neutralized by default)
odoo-dev db restore backup.zip mydb --no-neutralize
odoo-dev db drop mydb                  # Drop database
odoo-dev db neutralize mydb            # Disable emails/crons

Docker (optional)

odoo-dev docker start                 # Start containers
odoo-dev docker stop                  # Stop containers
odoo-dev docker restart               # Restart containers
odoo-dev docker logs                  # View logs
odoo-dev docker build                 # Rebuild image
odoo-dev docker shell mydb            # Shell in container
odoo-dev docker psql                  # PostgreSQL shell

Setup Commands

odoo-dev setup                        # Full setup (interactive; offers Docker)
odoo-dev setup --community            # Community edition only
odoo-dev setup --no-docker --yes      # Headless/agentic: clone + venv + conf, no Docker, no prompts
odoo-dev setup-venv                   # Just create the venv (no repo clone)
odoo-dev vscode                       # Configure VSCode debugging

Vendored Addons

Shared addons can be vendored — materialized as real committed directories under vendored/, pinned per-addon by addons.lock — instead of pulled in as .repos/ git submodules. This makes each promotion a normal, reviewable file diff and deploys as plain files (what Odoo.sh needs). vendored/ and addons/ are both on the addons path.

odoo-dev vendor migrate               # Convert .repos submodule+symlink addons -> vendored/
odoo-dev vendor migrate --dry-run     # Preview the pins without changing anything
odoo-dev vendor sync                  # Materialize vendored/ from addons.lock
odoo-dev vendor check                 # CI gate: verify vendored/ byte-matches the pins
odoo-dev vendor add fsm --source github.com/bemade/bemade-addons --version 18.0.1.3.2
odoo-dev vendor bump fsm --version 18.0.1.4.0   # Move a pin and re-materialize
odoo-dev vendor bump fsm --branch 18.0-fix-x    # Track a branch, pin its head
odoo-dev vendor check --mainline 18.0           # Production gate: pins must be merged upstream
odoo-dev vendor update                # Pull newest upstream for all tracked addons
odoo-dev vendor update fsm --dry-run  # Show what would update, change nothing
odoo-dev vendor develop fsm           # Edit fsm against a live source clone
odoo-dev vendor develop fsm --stop    # Leave develop mode (keeps the clone)
odoo-dev vendor status                # Show vendored pins, symlinks, develop mode

Because vendored/<addon> is a materialized copy (re-sync clobbers it), you don't edit it in place. vendor develop <addon> clones the addon's source repo into a git-ignored .vendor-dev/, checks out a work branch at the pinned commit, and prepends an overlay to your local conf/odoo.conf addons_path so Odoo loads the live tree instead of the vendored copy (first path wins). vendored/ stays byte-for-byte pristine and only the local conf is touched, so nothing dev-only can leak into a commit or into CI/prod. Edit in the clone, run/test in this project's Odoo, commit + push upstream, then vendor bump once the new version is tagged. --branch NAME names the work branch; --base REF bases it on something other than the current pin.

vendor check verifies, per addon: the vendored files byte-match the pinned commit; a version tag (if set) still resolves to that commit; every manifest external_dependencies['python'] is named in requirements.txt; no addon name collides between addons/ and vendored/; and no file under vendored/ is gitignored. Python bytecode (__pycache__/, *.pyc) is excluded from the byte comparison, so running the test suite doesn't turn the check red.

vendor check --mainline <branch> (for merge requests to production) also fails any pin whose commit is not in the history of that branch of its source — an upstream change still under test on a feature branch. A client can pin a feature branch while the change is tested on its staging (vendor bump <addon> --branch <feature>), but production only takes it once it is merged upstream and re-pinned. An entry that is meant to live on a branch (a long-lived fork) opts out with allow_unmerged: true in addons.lock.

That last assertion catches a trap specific to migration: repo-wide ignore rules (node_modules, package.json, …) are harmless while shared addons live in submodules, but they start applying the moment those addons become real files under vendored/ — and git add then skips the matching files without a word, so the committed tree is incomplete while everything looks fine locally. vendor migrate appends a !vendored/** negation to .gitignore when it detects the situation. Pins themselves come from the gitlink the branch records, not from whatever the submodule happens to be checked out at; migrate refuses to run against uninitialized submodules.

vendor update is the pull side: each client owns its pins. For every addon that tracks upstream — a version (bump to the newest <addon>/<version> tag) or a branch (bump to its HEAD) — it moves the pin forward and re-materializes. Addons pinned to a bare commit are left alone. Run it on a schedule (a client's own CI, its own token, opening a vendor-bump/… MR) so shared-addon changes propagate without any per-source push/fan-out machinery.

Project Structure

odoo-dev expects this project structure:

my-odoo-project/
├── .env                 # Optional: ODOO_VERSION, PYTHON_VERSION
├── addons/              # Your custom addons
├── vendored/            # Vendored shared addons (real files, pinned by addons.lock)
├── addons.lock          # Per-addon pins for vendored/ (see `vendor`)
├── requirements.txt     # Project-specific Python deps
├── odoo/                # Cloned by setup
├── enterprise/          # Cloned by setup (unless --community)
├── design-themes/       # Cloned by setup
├── .venv/               # Created by setup
└── conf/
    └── odoo.conf        # Created by setup

vendored/ and addons.lock are only present once a project adopts vendoring (odoo-dev vendor migrate); submodule-based projects use .repos/ + symlinks into addons/ instead.

Configuration

Create a .env file in your project root:

ODOO_VERSION=19.0
PYTHON_VERSION=3.12

# Optional — DB connection, written into conf/odoo.conf by `setup`.
# Omit DB_HOST/DB_PORT to use the local socket (the default). Set these to
# point at a remote / Docker / non-default PostgreSQL:
# DB_HOST=localhost
# DB_PORT=5432
# DB_USER=odoo
# DB_PASSWORD=odoo

# Optional — Odoo master password, written into conf/odoo.conf by `setup`.
# Defaults to "admin".
# ADMIN_PASSWD=admin

setup also points data_dir at a project-local .odoo-data/ (git-ignored) rather than the shared ~/.local/share/Odoo, so filestores, sessions and the addons cache stay scoped to the checkout they belong to.

Python packages declared in your addons' manifests — external_dependencies and the OCA test_external_dependencies convention, across both addons/ and vendored/ — are installed into the venv by setup.

Requirements

  • Python 3.12+
  • uv (recommended) or pip
  • Git
  • PostgreSQL (for local development — server + an odoo role; see "Database setup")
  • Docker (optional, for containerized development)

Development

# Clone and install for development
git clone git@github.com:bemade/odoo-dev.git
cd odoo-dev
uv sync

# Run tests
uv run pytest                 # All tests
uv run pytest -m "not slow"   # Fast tests only

# Build
uv build

License

LGPL-3. For complete license terms, visit https://www.gnu.org/licenses/lgpl-3.0.en.html

About

Odoo development CLI tool

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages