From a5f7f2e88ca0119346df3922f1f4f7eb97d9fc67 Mon Sep 17 00:00:00 2001 From: "matthias.lotz" Date: Fri, 3 Oct 2025 20:52:24 +0200 Subject: [PATCH] merge 1.3.1 --- CHANGES.rst | 37 + CONTRIBUTORS.md | 2 + README.md | 951 +++++++++++++----- odoo_openupgrade_wizard/cli/cli.py | 70 +- odoo_openupgrade_wizard/cli/cli_copydb.py | 11 +- .../cli/cli_docker_build.py | 15 +- odoo_openupgrade_wizard/cli/cli_dumpdb.py | 24 +- .../cli/cli_estimate_workload.py | 22 +- .../cli/cli_execute_script_python.py | 22 +- .../cli/cli_execute_script_sql.py | 14 +- .../cli/cli_generate_module_analysis.py | 17 +- odoo_openupgrade_wizard/cli/cli_get_code.py | 8 +- .../cli/cli_guess_requirement.py | 17 +- odoo_openupgrade_wizard/cli/cli_init.py | 36 +- .../cli/cli_install_from_csv.py | 10 +- odoo_openupgrade_wizard/cli/cli_options.py | 14 +- odoo_openupgrade_wizard/cli/cli_psql.py | 23 +- .../cli/cli_pull_submodule.py | 10 +- odoo_openupgrade_wizard/cli/cli_restoredb.py | 23 +- odoo_openupgrade_wizard/cli/cli_run.py | 16 +- odoo_openupgrade_wizard/cli/cli_upgrade.py | 10 + .../configuration_version_dependant.py | 24 +- .../templates/odoo/13.0/Dockerfile | 3 + .../templates/odoo/14.0/Dockerfile | 3 + .../templates/odoo/15.0/Dockerfile | 3 + .../templates/odoo/16.0/Dockerfile | 3 + .../templates/scripts/post-migration.py.j2 | 2 +- .../tools/tools_click_odoo_contrib.py | 2 +- odoo_openupgrade_wizard/tools/tools_docker.py | 9 +- odoo_openupgrade_wizard/tools/tools_odoo.py | 34 +- .../tools/tools_odoo_instance.py | 4 +- .../tools/tools_odoo_module.py | 12 +- .../tools/tools_postgres.py | 18 +- odoo_openupgrade_wizard/tools/tools_system.py | 16 +- pyproject.toml | 3 +- tests/__init__.py | 2 +- 36 files changed, 1083 insertions(+), 407 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index ac2025f..e3c348c 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -6,6 +6,43 @@ This file compiles releases and changes made in .. towncrier release notes start +odoo-openupgrade-wizard 1.3.1 (2025-09-18) +========================================== + +Bugfixes +-------- + +- Fix BSD mkdir incompatibility on macOS by using single-character + flags for 'mode' and 'parents' for cross-platform folder creation (#39) +- Fix debian buster Dockerfile. It uses the old https://deb.debian.org + instead of https://archive.debian.org. +- Improve error handling for missing config file outside initialized + environment. +- Prevent creating a log file outside of an initialized directory. +- Set 'rm=True' when building Docker images, ensuring intermediate (i.e. + orphaned) containers are automatically removed after builds and keeping + local Docker environments clean. + + By default, the docker build CLI now sets --rm=true, but the SDK has + kept the old default of False to preserve backward compatibility. + + +Documentation +------------- + +- Many improvements/additions to README.md and help string, including missing + Command help, additional examples, a Quick Start Guide, standard technical + writing changes, etc. +- Remove obsolete ROADMAP file. Team now uses issues on gitlab. + + +Misc +---- + +- Do not set False to an argument that is hint typed as string. Using None + instead. + + odoo-openupgrade-wizard 1.3.0 (2025-05-04) ========================================== diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 903091e..5ddea90 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -11,6 +11,8 @@ * Boris GALLET, since September 2024 * Ahmet YIĞIT BUDAK, from [Altinkaya](https://www.altinkaya.com/fr), since October 2024 * Alexandre AUBIN, from [Coopaname](https://www.coopaname.coop/), since October 2024 +* Sergio Zanchetta, from [PNLug](https://www.pnlug.it/), since January 2025 +* Ken WOYCHESKO, since May 2025 # Reviewers diff --git a/README.md b/README.md index 63d2df4..084e327 100644 --- a/README.md +++ b/README.md @@ -7,187 +7,343 @@ ![GitLab last commit](https://img.shields.io/gitlab/last-commit/34780558) ![GitLab stars](https://img.shields.io/gitlab/stars/34780558?style=social) -# odoo-openupgrade-wizard +# Odoo OpenUpgrade Wizard -Odoo Openupgrade Wizard is a tool that helps developers to make major -upgrade of Odoo Community Edition. (formely OpenERP). -It works with Openupgrade OCA tools. (https://github.com/oca/openupgrade) +**Odoo OpenUpgrade Wizard** is a powerful tool designed to help developers perform major +upgrades of Odoo Community Edition (formerly OpenERP). -this tool is useful for complex migrations: -- migrate several versions -- take advantage of the migration to install / uninstall modules -- execute sql requests or odoo shell scripts between each migration -- analyse workload +Designed for complex migrations, Odoo OpenUpgrade Wizard integrates tightly with the +[OCA OpenUpgrade](https://github.com/oca/openupgrade) project to streamline and +automate the migration process. There is no need to download or install OCA OpenUpgrade +separately - Odoo OpenUpgrade Wizard handles the integration for you automatically! -It will create a migration environment (with all the code available) -and provides helpers to run (and replay) migrations until it works. +Key features include: +* **Multi-version upgrades:** Migrate sequentially across several Odoo versions in one + workflow. +* **Module installation control**: Install or uninstall modules as part of the migration + workflow. +* **Automation hooks:** Execute custom SQL queries or Odoo shell scripts before and + after each migration step. +* **Workload estimation:** Analyze and report on the migration effort and module +coverage. +* **Reproducible environments:** Automate Docker-based build and testing environments + for each upgrade step. +* **Automatic integration with OCA OpenUpgrade:** Automatic cloning and integration + with the powerful OCA OpenUpgrade project. -* To develop and contribute to the library, refer to the ``DEVELOP.md`` file. -* Refer to the ``ROADMAP.md`` file to see the current limitation, bugs, and task to do. -* See authors in the ``CONTRIBUTORS.md`` file. +Odoo OpenUpgrade Wizard sets up a dedicated migration environment, fetching all +necessary code and dependencies. It provides helpers to run, test, and replay migration +steps until your upgrade is successful. # Table of Contents -* [Installation](#installation) -* [Usage](#usage) - * [Command ``init``](#command-init) - * [Command ``pull-submodule``](#command-pull-submodule) - * [Command ``get-code``](#command-get-code) - * [Command ``guess-requirement``](#command-guess-requirement) - * [Command ``docker-build``](#command-docker-build) - * [Command ``run``](#command-run) - * [Command ``install-from-csv``](#command-install-from-csv) - * [Command ``upgrade``](#command-upgrade) - * [Command ``generate-module-analysis``](#command-generate-module-analysis) - * [Command ``estimate-workload``](#command-estimate-workload) - * [Command ``psql``](#command-psql) - * [Command ``copydb``](#command-copydb) - * [Command ``dropdb``](#command-dropdb) - * [Command ``dumpdb``](#command-dumpdb) +- [Odoo OpenUpgrade Wizard](#odoo-openupgrade-wizard) +- [Table of Contents](#table-of-contents) +- [Quick Start Guide](#quick-start-guide) +- [Installation](#installation) +- [Usage](#usage) + - [Command: ``init``](#command-init) + - [Command: ``pull-submodule``](#command-pull-submodule) + - [Command: ``get-code``](#command-get-code) + - [Command: ``guess-requirement``](#command-guess-requirement) + - [Command: ``docker-build``](#command-docker-build) + - [Command: ``run``](#command-run) + - [Command: ``install-from-csv``](#command-install-from-csv) + - [Command: ``upgrade``](#command-upgrade) + - [Command: ``generate-module-analysis``](#command-generate-module-analysis) + - [Command: ``estimate-workload``](#command-estimate-workload) + - [Command: ``psql``](#command-psql) + - [Command: ``copydb``](#command-copydb) + - [Command: ``dropdb``](#command-dropdb) + - [Command: ``dumpdb``](#command-dumpdb) + - [Command: ``restoredb``](#command-restoredb) + - [Command: ``execute-script-python``](#command-execute-script-python) + - [Command: ``execute-script-sql``](#command-execute-script-sql) +- [Project Roadmap \& Contributing](#project-roadmap--contributing) + + + +# Quick Start Guide + +1. Install Odoo OpenUpgrade Wizard via pipx: +```shell +pipx install odoo-openupgrade-wizard +``` + +2. Initialize your environment: +```shell +oow init +``` + +3. Get the code and start using the tool: +```shell +oow get-code +oow docker-build +oow run +``` +See below for complete command reference. # Installation -**Prerequites:** +**Prerequisites** -* The tools run on debian system -* You should have docker installed on your system -* Some features require extra packages. To have all the features available run: +* **Operating System:** Supported on Debian-based Linux and macOS. +* **Docker:** Must be installed for running migration environments. +* **Python:** 3.9, 3.10, 3.11, and 3.12 are supported. +* For full feature support, ensure system-level build tools and libraries are present +(see `DEVELOP.md` for details). -**Installation:** +**Install from PyPI** The library is available on [PyPI](https://pypi.org/project/odoo-openupgrade-wizard/). -To install it simply run : +The easiest way to install Odoo OpenUpgrade Wizard is with +[pipx](https://pypa.github.io/pipx/): -``pipx install odoo-openupgrade-wizard`` +```shell +pipx install odoo-openupgrade-wizard +``` -(See alternative installation in ``DEVELOP.md`` file.) +Alternatively, use pip in a virtual environment: + +```shell +python -m venv venv +source venv/bin/activate +pip install odoo-openupgrade-wizard +``` + +For development installation and advanced setup, see the ``DEVELOP.md`` file. # Usage -**Note:** +Once installed, the CLI tool is available as either ``odoo-openupgrade-wizard`` or +``oow``. -the term ``odoo-openupgrade-wizard`` can be replaced by ``oow`` +**Tips** + +* The term ``odoo-openupgrade-wizard`` can be replaced by ``oow`` in all the command lines below. +* All commands support --help for additional details, for example: + * ``odoo-openupgrade-wizard --help`` or ``oow --help`` + * ``odoo-openupgrade-wizard init --help`` or ``oow init --help`` + ## Command: ``init`` +**Prerequisites:** Current working directory is your desired project directory +(see **Tips** below) + +Initializes a new migration project. Creates the directory structure and configuration +files for your migration project inside the current directory, including per-version +environments, scripts, and settings. + +You can provide all options directly as command-line arguments, or simply run +the ``init`` command without them and you will be interactively prompted for any +required information. + ```shell odoo-openupgrade-wizard init\ - --initial-version=10.0\ - --final-version=12.0\ - --project-name=my-customer-10-12\ - --extra-repository=OCA/web,OCA/server-tools + --initial-version 11.0\ + --final-version 15.0\ + --project-name upg-customer-11-15\ + --extra-repository OCA/web,OCA/server-tools\ + --postgresql-version 12 ``` -Initialize a folder to make a migration from a 10.0 and a 12.0 database. -This will generate the following structure : +**Parameters** + +* ``--initial-version`` **(Required)** The current Odoo version that you are migrating + from. Example: 11.0 +* ``--final-version`` **(Required)** The desired final Odoo version that you are + migrating to. This may be several versions greater than the ``--initial-version``. + Example: 18.0 +* ``--project-name`` **(Required)** A user-friendly name to help identify the Docker + images. Must not contain spaces, special characters, or uppercase letters. + Example: my-customer-16-18 +* ``--extra-repository`` **(Required)** Comma-separated list of extra repositories to + use in the Odoo environment. + Example: OCA/web,OCA/server-tools,GRAP/grap-odoo-incubator +* ``--postgresql-version`` **(Required)** The version of PostgreSQL that will be used + to create the PostgreSQL container. Example: 10, 16, etc. + The version should be available in Docker hub (https://hub.docker.com/_/postgres). + Avoid the 'latest' version if you want a deterministic installation. + **Important:** If your current production server uses PostgreSQL version A and your + future production server will use PostgreSQL version B, you should select here a + version X, with A <= X <= B. + +**Example: Example command to initialize a project to upgrade from Odoo 10.0 to Odoo 12.0:** + +```shell +odoo-openupgrade-wizard init\ + --initial-version 10.0\ + --final-version 12.0\ + --project-name my-customer-10-12\ + --extra-repository OCA/web,OCA/server-tools\ + --postgresql-version 10 +``` +This will generate the following structure (some directories/files will only appear +after subsequent oow commands, such as ``run``, ``generate-module-analysis``, etc.) +but are provided here for context and clarity: ``` +config.yml +modules.csv filestore/ log/ 2022_03_25__23_12_41__init.log ... postgres_data/ scripts/ - step_1__update__10.0/ + step_01__regular__10.0/ pre-migration.sql post-migration.py - step_2__upgrade__11.0/ + step_02__openupgrade__11.0/ ... - step_3__upgrade__12.0/ + step_03__openupgrade__12.0/ ... - step_4__update__12.0/ + step_04__regular__12.0/ ... src/ env_10.0/ + addons_debian_requirements.txt + addons_python_requirements.txt extra_debian_requirements.txt + extra_python_requirements.txt Dockerfile odoo.conf - extra_python_requirements.txt repos.yml src/ env_11.0/ ... env_12.0/ ... -config.yml -modules.csv ``` -* ``config.yml`` is the main configuration file of your project. +**Key Files and Directories** -* ``modules.csv`` file is an optional file. You can fill it with the list - of your modules installed on your production. The first column of this - file should contain the technical name of the module. +* ``config.yml`` Main project configuration. Contains the options selected with the + `init` command plus other user-configurable settings. For example, country_code (used + by the ``install-from-csv`` command), and workload_settings (used by the + ``estimate-workload`` command). -* ``log`` folder will contains all the log of the ``odoo-openupgrade-wizard`` - and the logs of the odoo instance that will be executed. +* ``modules.csv`` (optional) Lists the modules installed on the production system to be + upgraded. The first column of this file should contain the technical name of the + module. -* ``filestore`` folder will contains the filestore of the odoo database(s). +* ``filestore/`` Odoo filestore(s) for each of the Odoo databases. This directory + is not created by the ``oow init`` command, but instead is generated by any of the + commands that create an Odoo database (e.g. ``oow run``, ``oow install-from-csv``, + etc.) -* ``postgres_data`` folder will be used by postgres docker image to store - database. +* ``log/`` Contains all logs generated by ``odoo-openupgrade-wizard`` during migration + steps and the logs of the Odoo instance. -* ``scripts`` folder contains a folder per migration step. In each step folder: - - ``pre-migration.sql`` can contains extra SQL queries you want to execute - before beginning the step. - - ``post-migration.py`` can contains extra python command to execute - after the execution of the step. - Script will be executed with ``odoo shell`` command. All the ORM is available - via the ``env`` variable. +* ``postgres_data/`` This directory is not created by the ``oow init`` command, but + is just a suggested location to store your database & filestore backups. This ensures + that the PostgreSQL Docker container has access to the files when required + (e.g. during commands such as ``oow restoredb``). -* ``src`` folder contains a folder per Odoo version. In each environment folder: +* ``scripts/`` Contains a subdirectory for each migration step + (e.g. ``step_01__regular__10.0``). In each ``step_xx`` subdirectory: + - ``pre-migration.sql`` Extra SQL queries to execute before beginning the step. + - ``post-migration.py`` Extra python commands to execute after the completion of the + step. Script will be executed with the ``odoo shell`` command. All the ORM is + available via the ``env`` variable. - - ``repos.yml`` enumerates the list of the repositories to use to run the odoo instance. - The syntax should respect the ``gitaggregate`` command. - (See : https://pypi.org/project/git-aggregator/) - Repo files are pre-generated. You can update them with your custom settings. - (custom branches, extra PRs, git shallow options, etc...) +* ``src/`` Contains a subdirectory for each Odoo version in the project + (e.g. ``env_10.0``) with source code and requirements for each Odoo version. In + each environment directory: - - ``extra_python_requirements.txt`` enumerates the list of extra python libraries - required to run the odoo instance. - The syntax should respect the ``pip install -r`` command. - (See : https://pip.pypa.io/en/stable/reference/requirements-file-format/) + - ``addons_debian_requirements.txt`` Lists Debian (system-level) packages that are + required by the Odoo addons (modules) specified in your migration. These packages + are automatically installed in the Docker environment to ensure your Odoo + instance has all necessary system dependencies. This file is autopopulated by + the ``oow guess-requirement`` command based on the addons listed in the + ``modules.csv`` file. - - ``extra_debian_requirements.txt`` enumerates the list of extra system libraries - required to run the odoo instance. + - ``addons_python_requirements.txt`` Similar to ``addons_debian_requirements.txt`` + but for Python packages (autopopulated by the ``oow guess-requirement`` command). - - ``odoo.conf`` file. Add here extra configuration required for your custom modules. - the classical keys (``db_host``, ``db_port``, etc...) are automatically - autogenerated. + - ``extra_debian_requirements.txt`` Allows you to specify any additional Debian + (system-level) packages needed beyond those detected for your modules. Use this + file to manually add system dependencies that are unique to your customizations + or specific project needs but were not automatically detected by the + ``oow guess-requirement`` command. -At this step, you should change the autogenerated files. For exemple: -- you can set ``update=False`` to prevents to run an update=all, in the 'regular' steps - (first and last steps). In that case, only SQL queries and python scripts - will be executed during this step. + - ``extra_python_requirements.txt`` Lets you list additional Python packages + required by your environment, beyond what is automatically detected for your + modules by the ``oow guess-requirement`` command. The syntax should respect + the ``pip install -r`` command + (see: https://pip.pypa.io/en/stable/reference/requirements-file-format/). -You can use default files, if you have a very simple odoo instance without custom code, -extra repositories, or dependencies... + - ``Dockerfile`` Used to build a custom Docker image tailored for each + step of the migration. The Dockerfile pulls a compatible Debian base image, + installs required system packages and Python dependencies (from the generated + requirements files), and applies any extra configuration. -**Note:** + - ``odoo.conf`` Add any non-standard configuration required for your custom modules. + This file can be left empty. Only list non-standard or special options not + included in the standard parameters. The Odoo OpenUpgrade Wizard code + automatically generates standard parameters such as addons paths, database + connection details, HTTP/XML ports, etc. -- In your repos.yml, preserve ``openupgrade`` and ``server-tools`` repositories - to have all the features of the libraries available. -- In your repos.yml file, the odoo project should be in ``./src/odoo`` - and the openupgrade project should be in ``./src/openupgrade/`` folder. + - ``repos.yml`` Defines which Git repositories (and which branches or pull requests) + should be cloned and included in the environment for a specific Odoo version + during your migration. The syntax should respect the ``gitaggregate`` command + (see: https://pypi.org/project/git-aggregator/). + This file is autopopulated based on the repositories included in the ``oow init`` + command, though you can update them with your custom settings (custom branches, + extra PRs, git shallow options, etc.) + +**Note** + +- In your ``repos.yml`` file, preserve the ``openupgrade`` repository to have all the + features of this library available. +- In your ``repos.yml`` file, the Odoo project should be in ``./src/odoo`` + and the openupgrade project should be in the ``./src/openupgrade/`` directory. + +**Tips** + +- A good habit is to always include ``--extra-repository OCA/server-tools`` + to ensure that the features this repo provides are available (required for running + some Odoo OpenUpgrade Wizard commands such as ``oow generate-module-analysis``). +- You can use the default generated files if you have a basic Odoo instance without + custom code, extra repositories, or dependencies, or you could edit the autogenerated + files as needed for your specific migration scenario. For example: + - In the ``config.yml`` file's 'regular' steps (i.e., first and last steps), you can + change the default ``update: True`` to ``update: False`` to prevent the system from + executing a time-consuming 'update=all' during the upgrade. In that case, only SQL + queries and python scripts will be executed during this step. + - In the ``config.yml`` file's ``odoo_default_company`` setting, you could change the + ``country_code`` from the default 'FR' to your desired setting. + +- This command builds the project scaffold inside the current directory. Therefore, +before running this command, create your project directory and `cd` to it: + +```shell +mkdir my-oow-upgrade-project +cd my-oow-upgrade-project +oow init +``` ## Command: ``pull-submodule`` -**Prerequites:** init + being in a git repository. (if not, you can simply run ``git init``) +**Prerequisites:** init + being in a git repository (if not, you can simply run ``git init``) -if you already have a repos.yml file on github / gitlab, it can be convenient to -synchronize the repository, instead of copy paste the ``repos.yml`` manually. +Optionally syncs a remote ``repos.yml`` file into your local migration project instead of +relying on providing an --extra-repository list to the ``oow init`` command or manually +copying/pasting from an already-existing ``repos.yml`` file. -In that case, you can add extra values, in the ``config.yml`` file in the section +To use a ``repos.yml`` file from your GitHub or GitLab repository, add the repository +configuration in the ``config.yml`` file for each Odoo version: ```yaml odoo_version_settings: @@ -197,35 +353,41 @@ odoo_version_settings: repo_file_path: repos.yml ``` -then run following command : +Then run: ```shell odoo-openupgrade-wizard pull-submodule ``` +**Tips** + +- Remember to always include the ``OCA/server-tools`` repo in your repos.yml file + to ensure that the features this repo provides are available (required for running + some Odoo OpenUpgrade Wizard commands such as ``oow generate-module-analysis``). ## Command: ``get-code`` -**Prerequites:** init +**Prerequisites:** init + +Downloads all required Odoo source code and dependencies for each version defined in +your migration (uses the ``gitaggregate`` tools internally). ```shell odoo-openupgrade-wizard get-code ``` -This command will simply get all the Odoo code required to run all the steps -for your migration with the ``gitaggregate`` tools. - -The code is defined in the ``repos.yml`` of each environment folders. (or in the -directory ``repo_submodule`` if you use ``pull-submodule`` feature.) +The required repositories are defined in the ``repos.yml`` file of each environment +directory (or in the ``repo_submodule`` directory if you used the ``pull-submodule`` +feature.) **Note** -* This step could take a big while ! +* This step could take a long time! -**Optional arguments** +**Optional Arguments** -if you want to update the code of some given versions, you can provide an extra parameter: +You can limit code updates to specific versions using the --versions parameter. ```shell odoo-openupgrade-wizard get-code --versions 10.0,11.0 @@ -235,19 +397,24 @@ odoo-openupgrade-wizard get-code --versions 10.0,11.0 ## Command: ``guess-requirement`` -**Prerequites:** init + get-code +**Prerequisites:** init + get-code + +Analyzes the list of modules defined in your ``modules.csv`` file to generate the +required Python and Debian package dependencies per environment. ```shell odoo-openupgrade-wizard guess-requirement ``` -Analyze the list of the modules defined in your ``modules.csv`` file. For each module and each version, this command tries to parse the -according ``__manifest__.py`` file (and, if possible the according ``setup.py`` file). -Finally, it overwrite the requirements.txt files present in each env folder. (python and debian requirements). +corresponding ``__manifest__.py`` file (and, if present, the ``setup.py`` +file). It then appends any discovered requirements to the appropriate +``addons_debian_requirements.txt`` and +``addons_python_requirements.txt`` files present in each env directory. -For example, here is the content of the ``addons_python_requirements.txt`` file, -when ``barcodes_generator_abstract`` and ``l10n_fr_siret`` are installed (for V16). +For example, here is the content of the ``addons_python_requirements.txt`` file +when ``barcodes_generator_abstract`` and ``l10n_fr_siret`` are listed in the +``modules.csv`` file (for v16). ``` # Required by the module(s): barcodes_generator_abstract @@ -261,16 +428,16 @@ python-stdnum>=1.18 ## Command: ``docker-build`` -**Prerequites:** init + get-code +**Prerequisites:** init + get-code + +Builds Docker images for each Odoo version/environment in your migration pipeline. ```shell odoo-openupgrade-wizard docker-build ``` -This will build local docker images that will be used in the following steps. - -At the end of this step executing the following command should show a docker image per version. - +After the command has finished, the following command should show a Docker image per +version: ```shell docker images --filter "reference=odoo-openupgrade-wizard-*" @@ -282,151 +449,188 @@ odoo-openupgrade-wizard-image---my-customer-10-12---11.0 latest 24e283fe4ae odoo-openupgrade-wizard-image---my-customer-10-12---10.0 latest 9d94dce2bd4e 2 weeks ago 924MB ``` -**Optional arguments** - -* if you want to (re)build an image for some given versions, you can provide - an extra parameter: ``--versions 10.0,12.0`` - **Note** -* This step could take a big while also ! +* This step could also take a long time! +**Optional Arguments** + +You can limit image builds to specific versions using the --versions parameter. + +```shell +odoo-openupgrade-wizard docker-build --versions 10.0,12.0 +``` ## Command: ``run`` -**Prerequites:** init + get-code + build +**Prerequisites:** init + get-code + docker-build + +Launches an Odoo instance for a specific migration step. ```shell odoo-openupgrade-wizard run\ --step 1\ - --database DB_NAME + --database mydb ``` -Run an Odoo instance with the environment defined by the step argument. +The database will be created if it doesn't already exist. -The database will be created, if it doesn't exists. +Unless the ``stop-after-init`` flag is used, the Odoo instance will be available +on your host at the following URL: http://localhost:9069 +(port depends on the ``host_odoo_xmlrpc_port`` setting in your ``config.yml`` file). -if ``stop-after-init`` is disabled, the odoo instance will be available -at your host, at the following url : http://localhost:9069 -(Port depends on your ``host_odoo_xmlrpc_port`` setting of your ``config.yml`` file) +**Optional Arguments** -**Optional arguments** +* You can install modules using the --init-modules parameter +(e.g. ``--init-modules base,purchase,sale``). -* You can add ``--init-modules=purchase,sale`` to install modules. - -* You can add ``stop-after-init`` flag to turn off the process at the end +* You can add the ``stop-after-init`` flag to turn off the process at the end of the installation. - ## Command: ``install-from-csv`` -**Prerequites:** init + get-code + build +**Prerequisites:** init + get-code + docker-build + +Installs all modules listed in the ``modules.csv`` file into the specified database. ```shell odoo-openupgrade-wizard install-from-csv\ - --database DB_NAME + --database mydb ``` -Install the list of the modules defined in your ``modules.csv`` files on the -given database. +The database will be created if it doesn't exist. -The database will be created, if it doesn't exists. - -To get a correct ``modules.csv`` file, the following query can be used: +To generate a proper ``modules.csv`` file, the following query can be used: ```shell psql -c "copy (select name, shortdesc from ir_module_module where state = 'installed' order by 1) to stdout csv" coopiteasy ``` - ## Command: ``upgrade`` -**Prerequites:** init + get-code + build +**Prerequisites:** init + get-code + docker-build + +Performs the full database migration across all defined steps. ```shell odoo-openupgrade-wizard upgrade\ - --database DB_NAME + --database mydb ``` -Realize an upgrade of the database from the initial version to -the final version, following the different steps. +For each step, this will: -For each step, it will : +1. Run ``pre-migration.sql`` scripts. +2. Apply "update all" (in an upgrade or update context). +3. Run ``post-migration.py`` scripts via XML-RPC/Odoo shell (via ``odoorpc``). -1. Execute the ``pre-migration.sql`` of the step. -2. Realize an "update all" (in an upgrade or update context) -3. Execute the scripts via XML-RPC (via ``odoorpc``) defined in - the ``post-migration.py`` file. +**Optional Arguments** -**Optional arguments** - -* You can add ``--first-step=2`` to start at the second step. - -* You can add ``--last-step=3`` to end at the third step. +* You can add ``--first-step 2`` to start at the second step. +* You can add ``--last-step 3`` to end at the third step. ## Command: ``generate-module-analysis`` -**Prerequites:** init + get-code + build +**Prerequisites:** init + get-code + docker-build + OCA/server-tools in repos.yml + +Performs an analysis between the target version (represented by the step parameter) +and the previous version to indicate how the data model and module data have +changed between the two versions (uses the OCA/server-tools ``upgrade_analysis`` tool +internally). ```shell odoo-openupgrade-wizard generate-module-analysis\ - --database DB_NAME - --step 2 - --modules MODULE_LIST + --database mydb\ + --step 2\ + --modules custom_module_name1,custom_module_name2 ``` -Realize an analysis between the target version (in parameter via the step argument) -and the previous version. It will generate analysis_file.txt files present -in OpenUpgrade project. -You can also use this function to analyze differences for custom / OCA modules -between several versions, in case of refactoring. +This tool will generate analysis files (e.g. ``upgrade_analysis.txt``, +``noupdate_changes.xml``, etc.) depending on the following: +- In the case of core Odoo modules, the analysis files will be located in the project's + ``src/env_xx.0/src/openupgrade/openupgrade_scripts/scripts/{module_name}/{module_version}`` + directory. +- In the case of third-party modules (e.g. OCA or your own custom modules), the + analysis files will be located modules' ``migrations/{module_version}`` directory + (e.g. + ``src/env_xx.0/src/{organization}/{repo}/{module_name}/migrations/{module_version}``). + +**Notes** + +This command requires the ``upgrade_analysis`` module from the ``OCA/server-tools`` repository. +Be sure this repo is included in your ``repos.yml`` and pulled via ``oow get-code``. + +**Tips** + +- You can also use this function to analyze differences for custom & OCA modules + between several versions (e.g. in case of refactoring). +- If you get an error running this command, you may not have included + ``--extra-repository OCA/server-tools`` in your ``oow init`` command (and thus the + repo is not listed in your ``repos.yml`` file). ## Command: ``estimate-workload`` -**Prerequites:** init + get-code +**Prerequisites:** init + get-code + +Generates an HTML report (``analysis.html``) with all the information regarding +the work to do for the migration for the modules listed in ``modules.csv`` (or passed +via the command-line arguments). ```shell odoo-openupgrade-wizard estimate-workload ``` -Generate an HTML file name ``analysis.html`` with all the information regarding -the work to do for the migration. -- checks that the modules are present in each version. (by managing the +Features: +- Checks that the modules are present in each version (by managing the renaming or merging of modules) -- check that the analysis and migration have been done for the official - modules present in odoo/odoo +- Checks that the analysis and migration have been done for the official + modules present in odoo/odoo) + +**Optional Arguments** + +You can override the modules in ``modules.csv`` by passing a comma-separated list +using the --extra-modules parameter: + +```shell +odoo-openupgrade-wizard estimate-workload --extra-modules account,product,base +``` ## Command: ``psql`` -**Prerequites:** init +**Prerequisites:** init + get-code + docker-build + +Runs arbitrary SQL commands against the target database. ```shell -odoo-openupgrade-wizard psql - --database DB_NAME - --command "SQL_REQUEST" +odoo-openupgrade-wizard psql\ + --database mydb\ + --command "SELECT count(*) FROM res_partner;" ``` -Execute an SQL Request on the target database. +Ensure that the ``command`` parameter contains a string with a valid psql statement +(including the statement terminator ";") or meta-command (e.g. \l, \dt). -**Optional arguments** +**Optional Arguments** -* If no ``database`` is provided, default ``postgres`` database will be used. example: +**Database:** If no ``database`` is provided, the default ``postgres`` database can +be used by pressing Enter when prompted. For example: ```shell -odoo-openupgrade-wizard psql --command "\l"; +odoo-openupgrade-wizard psql --command "\l" ``` +You will be prompted to use the default database (i.e. [posgres]). Simply press Enter. + Result: ``` List of databases @@ -441,18 +645,19 @@ Result: ``` -* if you execute request that return long result, you can choose to select ``pager`` or ``-no-pager`` - option to display the result via the click function ``echo_via_pager``. - (see : https://click.palletsprojects.com/en/8.1.x/utils/#pager-support) +**--pager/--no-pager:** To allow scrolling through long results, the "pager" option +is enabled by default via the click function ``echo_via_pager`` +(see https://click.palletsprojects.com/en/8.1.x/utils/#pager-support). +Disable the pager feature by passing ``--no-pager``. -Note : Pager is enabled by default. - - -* you can pass extra psql arguments inline. +**Extra psql arguments:** You can pass extra psql arguments inline. All remaining +text after the known options are collected and passed unprocessed (i.e., they won’t +be parsed or validated by Click). These arguments are then appended directly to the +psql command line run inside the Docker container. ```shell -odoo-openupgrade-wizard psql - --database=test_psql +odoo-openupgrade-wizard psql\ + --database test_psql\ --command "select id, name from res_partner where name ilike '%admin%';" -H ``` @@ -470,84 +675,364 @@ Result:

(1 row)

- ``` -See all the options here https://www.postgresql.org/docs/current/app-psql.html +For the complete list of extra psql argument options, see: https://www.postgresql.org/docs/current/app-psql.html
## Command: ``copydb`` -**Prerequites:** init +**Prerequisites:** init + get-code + docker-build + +Creates an Odoo database (including filestore) by copying an existing one. ```shell -odoo-openupgrade-wizard copydb - --source DB_NAME - --dest NEW_DB_NAME +odoo-openupgrade-wizard copydb\ + --source my_current_db\ + --dest my_new_db ``` -Create an Odoo database by copying an existing one. - -This script copies using postgres CREATEDB WITH TEMPLATE. It also copies +This script copies using postgres' CREATEDB WITH TEMPLATE. It also copies the filestore. ## Command: ``dropdb`` -**Prerequites:** init +**Prerequisites:** init + get-code + docker-build + +Deletes an Odoo database and its filestore. ```shell -odoo-openupgrade-wizard dropdb - --database DB_NAME +odoo-openupgrade-wizard dropdb\ + --database mydb ``` -Delete an Odoo database and its filestore. - -This command will always success even if DB_NAME does not exists. +An exception will occur if the database does not exist. ## Command: ``dumpdb`` -**Prerequites:** init +Backs up a database and filestore, with options for output format. + +**Prerequisites:** init + get-code + docker-build ```shell -odoo-openupgrade-wizard dumpdb - --database DB_NAME - --database-path DATABASE_PATH - --filestore-path FILESTORE_PATH +odoo-openupgrade-wizard dumpdb\ + --database mydb\ + --database-path ./postgres_data\ + --filestore-path /path/to/myproject/postgres_data ``` -Dump the database DB_NAME to DATABASE_PATH and export the filestore -related to DB_NAME into FILESTORE_PATH. To choose the format of the -backup files look at the `--database-format` and `--filestore-format`. +Dumps the database mydb to ``--database-path`` and exports the filestore +related to mydb into ``--filestore-path``. -*WARNING*: DATABASE_PATH should be a sub directory of the project path -in orter to have the postgresql container able to write the dump file. -For example, the project path is `/path/to/myproject` (where you run the -`init` command), then DATABASE_PATH can be any of the subdirectory of -`/path/to/myproject`. +*WARNING*: The PostgreSQL Docker container must have access to the directories in the +``--database-path`` and ``--filestore-path`` parameters, therefore they must be inside +the project directory (as initialized by ``oow init``) using either an absolute path +or path relative to the project directory. -**Optional arguments** +To choose the format of the backup files, see `--database-format` and +`--filestore-format` in Optional Arguments below. + +**Optional Arguments** * To choose the database format use `--database-format`. Format can be - one of the following: - - `p` for plain sql text - - `c` for custom compressed backup of `pg_dump` - - `d` for directory structure - - `t` for a tar version of the directory structure - See also https://www.postgresql.org/docs/current/app-pgdump.html - The default database format is `c`. + one of the following (for more information on formats, see: + https://www.postgresql.org/docs/current/app-pgdump.html): + - `p` for plain sql text + - `c` (default format) for custom compressed backup of `pg_dump` + - `d` for directory structure + - `t` for a tar version of the directory structure * To choose the filestore format use `--filestore-format`. Format can be one of the following: - - `d` copy of the directory structure - - `t` tar version of the directory structure (not compressed) - - `tgz` tar version of the directory structure compressed with gzip. - The default filestore format is `tgz`. + - `d` copy of the directory structure + - `t` tar version of the directory structure (not compressed) + - `tgz` (default format) tar version of the directory structure compressed with gzip -* By default, if database file or filestore file already exists, the +* By default, if the database file or filestore already exists, the command will fail, preserving the existing dump. If you need to overwrite the existing files, the `--force` option can be used. + + + +## Command: ``restoredb`` + +Restores an Odoo database and its associated filestore from a previously created +backup. This command complements the dumpdb command and is useful when preparing +a fresh migration environment or recovering a snapshot. + +**Prerequisites:** init + get-code + docker-build + +```shell +odoo-openupgrade-wizard restoredb\ + --database mydb\ + --database-path ./postgres_data/db_backup\ + --database-format d\ + --filestore-path /path/to/myproject/postgres_data/filestore_backup + --filestore-format d +``` + +**Parameters** + +* ``--database`` **(Required)** Name of the database to restore. If it doesn’t exist, + it will be created. +* ``--database-path`` **(Required)** Path to the database backup file or directory + (must be inside your project path). +* ``--database-format`` Format of the database backup. One of: c (custom), + d (directory), t (tar), p (plain SQL). +* ``--filestore-path`` **(Required)** Path to the filestore archive or directory. +* ``--filestore-format`` Format of the filestore backup. One of: d (directory), + t (tar), tgz (gzipped tar). + +*WARNING*: The PostgreSQL Docker container must have access to the directories in the +``--database-path`` and ``--filestore-path`` parameters, therefore they must be inside +the project directory (as initialized by ``oow init``) using either an absolute path +or path relative to the project directory. + +**Supported Database Formats** + +* `c` (default format) Custom format created by pg_dump -Fc (default format of oow dumpdb) +* `d` Directory format (pg_dump -Fd) +* `t` Tar format (pg_dump -Ft) +* `p` Plain SQL (pg_dump without -F) + +**Supported Filestore Formats** + +* `d` A regular uncompressed directory +* `t` A tar archive +* `tgz` (default format) A tar archive compressed with gzip + +**Example: Restoring a custom dump with gzipped filestore:** + +```shell +odoo-openupgrade-wizard restoredb\ + --database myproject_v14\ + --database-path my_project/backups/db/myproject_v14.dump\ + --database-format c\ + --filestore-path my_project/backups/filestore/myproject_v14.tgz\ + --filestore-format tgz +``` + +This command: +1. Creates (or recreates) the myproject_v14 database. +2. Restores its contents from the compressed .dump file. +3. Restores its filestore from a .tgz archive into the filestore/filestore/myproject_v14/ + directory inside your migration environment. + + + +## Command: ``execute-script-python`` + +Executes one or more custom Python scripts in the context of a specific migration +step, using the Odoo shell (with full ORM access). This command allows you to manually +run Python logic outside of the default post-migration.py file for a given step. + +**Prerequisites:** init + get-code + docker-build + +```shell +odoo-openupgrade-wizard execute-script-python\ + --database mydb\ + --step 2\ + --script-file-path ./scripts/custom/my_script1.py,/path/to/myproject/scripts/custom/my_script2.py +``` +Or: +```shell +odoo-openupgrade-wizard execute-script-python\ + --database mydb\ + --step 2\ + --script-file-path ./scripts/custom/my_script1.py\ + --script-file-path /path/to/myproject/scripts/custom/my_script2.py +``` + +**Parameters** + +* ``--database`` **(Required)** Name of the database to operate on. +* ``--step`` **(Required)** The migration step (e.g. 1, 2, etc.), used to identify + the environment. +* ``--script-file-path`` **(Optional, repeatable)** One or more paths to Python + files within the project directory structure that you wish to execute. Each file + will be run in the order listed. Overrides the default + post-migration.py file in the step directory. The Docker container must have access + to the directory/files, therefore the ``--script-file-path`` must be + inside the project directory (as initialized by ``oow init``) using either an + absolute path or path relative to the project directory. + +**What It Does** + +* Supplements the default post-migration.py logic. +* Executes each specified script within the Dockerized Odoo shell for the given + migration step. +* You have full access to the Odoo environment (env object) inside each script, just + like in odoo shell. + +**Use Cases** + +* Run custom ORM-based data transformations outside the full migration process. +* Test individual migration scripts before placing them into the step directory. +* Apply hotfixes without modifying the default post-migration.py. + +**Script Example (fix_data.py)** + +```python +# This will execute inside the Odoo shell context with 'env' available +partners = env["res.partner"].search([("customer_rank", ">", 0)]) +for partner in partners: + partner.comment = "Migrated customer" +``` + +**Notes** + +* If multiple --script-file-path options are provided, they will be executed in + the order given. +* All script paths must be located within the project directory structure initialized + by ``oow init``. This is necessary so Docker has access to the files. +* This command is useful for debugging or running ad-hoc scripts, especially before + committing them to the official step directory. + +**Tips** +Store your custom Python scripts in a subdirectory under the standard ``scripts/`` +directory for improved organization and version control (e.g. ``scripts/custom``, +``scripts/debug``, etc.) + +**Example: Run a specific script manually** + +```shell +odoo-openupgrade-wizard execute-script-python\ + --database my_database\ + --step 3\ + --script-file-path scripts/custom/fix_project.py +``` + +**Example: Using absolute and relative paths to the `my-oow-project`:** +```shell +odoo-openupgrade-wizard execute-script-python\ + --script-file-path /home/myhome/my-oow-project/scripts/custom/script1.py\ + --script-file-path scripts/custom/script2.py +``` + +**Example: Executing all scripts within a directory (the scripts will be run +alphabetically):** +```shell +odoo-openupgrade-wizard execute-script-python\ + --script-file-path scripts/custom/*.py +``` + + + +## Command: ``execute-script-sql`` + +Executes one or more custom SQL scripts against the specified database using the +PostgreSQL Docker container. This command allows you to manually run SQL scripts, +allowing you to test or apply SQL changes in the context of a specific migration +step — outside the automatic oow upgrade process. + +**Prerequisites:** init + get-code + docker-build + +```shell +odoo-openupgrade-wizard execute-script-sql\ + --database mydb\ + --step 2\ + --script-file-path ./scripts/custom/my_script1.sql,/path/to/myproject/scripts/custom/my_script2.sql +``` +Or: +```shell +odoo-openupgrade-wizard execute-script-sql\ + --database mydb\ + --step 2\ + --script-file-path ./scripts/custom/my_script1.sql\ + --script-file-path /path/to/myproject/scripts/custom/my_script2.sql +``` + +**Parameters** + +* ``--database`` **(Required)** Name of the database to operate on. +* ``--step`` **(Required)** The migration step (e.g. 1, 2, etc.), used to identify + the environment. +* ``--script-file-path`` **(Optional, repeatable)** One or more paths to .sql script + files within the project directory structure that you wish to execute. Each file + will be run in the order listed. Overrides the default + pre-migration.sql file in the step directory. The Docker container must have access + to the directory/files, therefore the ``--script-file-path`` must be + inside the project directory (as initialized by ``oow init``) using either an + absolute path or path relative to the project directory. + +**What It Does** + +* Runs one or more SQL files. +* If no --script-file-path is provided, it looks for all .sql files in the current + step’s script directory (e.g. scripts/step_02__openupgrade__17.0/) and runs them + in sorted order. +* Executes scripts using psql inside the Dockerized PostgreSQL container. + +**Use Cases** + +* Clean up or transform data before upgrading modules. +* Add or drop constraints, indexes, or columns before the ORM makes structural changes. +* Debug or experiment with SQL commands outside the full migration process. + +**Notes** + +* If multiple --script-file-path options are provided, they will be executed in + the order given. +* All script paths must be located within the project directory structure initialized + by ``oow init``. This is necessary so Docker has access to the files. +* This command is useful for debugging or running ad-hoc scripts, especially before + committing them to the official step directory. +* Each SQL script is executed directly in the Postgres container using the + psql CLI with full database access. + +**Tips** +Store your custom SQL scripts in a subdirectory under the standard ``scripts/`` +directory for improved organization and version control (e.g. ``scripts/custom``, +``scripts/debug``, etc.) + +**Example: Run all .sql scripts in the step directory (sorted alphabetically)** + +```shell +odoo-openupgrade-wizard execute-script-sql\ + --database my_database\ + --step 1 +``` + +**Example: Run a specific script manually** + +```shell +odoo-openupgrade-wizard execute-script-sql\ + --database my_database\ + --step 3\ + --script-file-path scripts/custom/fix_currency.sql +``` + +**Example: Using absolute and relative paths to the `my-oow-project`:** +```shell +odoo-openupgrade-wizard execute-script-sql\ + --script-file-path /home/myhome/my-oow-project/scripts/custom/script1.sql\ + --script-file-path scripts/custom/script2.sql +``` + +**Example: Executing all scripts within a directory (the scripts will be run +alphabetically):** +```shell +odoo-openupgrade-wizard execute-script-sql\ + --script-file-path scripts/custom/*.sql +``` + + + +# Project Roadmap & Contributing + +We welcome your contributions! + +* Please see `DEVELOP.md` for development setup, coding guidelines, and instructions + on how to submit merge requests. +* Current limitations, known issues, and future features are tracked in the project's + GitLab Issues: https://gitlab.com/odoo-openupgrade-wizard/odoo-openupgrade-wizard/-/issues +* The full list of contributors is available in `CONTRIBUTORS.md`. + +_For additional details, troubleshooting, or to report issues, please visit our +[GitLab repository](https://gitlab.com/odoo-openupgrade-wizard/odoo-openupgrade-wizard) +or open a ticket._ diff --git a/odoo_openupgrade_wizard/cli/cli.py b/odoo_openupgrade_wizard/cli/cli.py index 304f9c4..c0113aa 100644 --- a/odoo_openupgrade_wizard/cli/cli.py +++ b/odoo_openupgrade_wizard/cli/cli.py @@ -56,9 +56,9 @@ DEFAULT_MODULES_FILE = "modules.csv" writable=True, resolve_path=True, ), - help="Folder that will contains all the configuration of the wizard" - " and all the Odoo code required to make the migrations. Let empty to" - " use current folder (./).", + help="Directory that will contain all the configuration of the wizard " + "and all the Odoo code required to perform the migrations. Leave " + "empty to use current directory (./).", ) @click.option( "-c", @@ -69,7 +69,7 @@ DEFAULT_MODULES_FILE = "modules.csv" ), help=( f"Configuration file to use. By default, a file named " - f'"{DEFAULT_CONFIG_FILE}" in the environment folder will be used.' + f'"{DEFAULT_CONFIG_FILE}" in the environment directory will be used.' ), ) @click.option( @@ -80,7 +80,7 @@ DEFAULT_MODULES_FILE = "modules.csv" ), help=( f"Modules file to use. By default, a file named " - f'"{DEFAULT_MODULES_FILE}" in the environment folder will be used.' + f'"{DEFAULT_MODULES_FILE}" in the environment directory will be used.' ), ) @click.option( @@ -88,22 +88,28 @@ DEFAULT_MODULES_FILE = "modules.csv" type=click.Path( exists=True, file_okay=False, writable=True, resolve_path=True ), - help="Folder that contains the Odoo filestore of the database(s)" - " to migrate. Let empty to use the subfolder 'filestore' of the" - " environment folder.", + help="Directory that contains the Odoo filestore of the database(s) to " + "migrate. Leave empty to use the subdirectory 'filestore' of the " + "environment directory.", ) @click.option("-l", "--log-level", type=LogLevel(), default=logging.INFO) @click.pass_context def main( ctx, env_folder, config_file, modules_file, filestore_folder, log_level ): - """ - Provides a command set to perform odoo Community Edition migrations. + """Provides a command set to perform Odoo Community Edition migrations. + + Instructions are provided in the README.md file, or see the + help provided for each 'Command' listed below. For + example, to learn more about the `init` command, + run: + + `oow init --help` """ date_begin = datetime.datetime.now() logger.remove() logger.add(sys.stderr, level=log_level) - logger.debug(f"Beginning script '{ctx.invoked_subcommand}' ...") + logger.debug(f"Beginning script '{ctx.invoked_subcommand}'...") if not isinstance(ctx.obj, dict): ctx.obj = {} @@ -118,16 +124,6 @@ def main( script_folder_path = env_folder_path / Path("./scripts/") log_folder_path = env_folder_path / Path("./log/") - # ensure log folder exists - ensure_folder_exists(log_folder_path, git_ignore_content=True) - - # Create log file - log_prefix = "{}__{}".format( - date_begin.strftime("%Y_%m_%d__%H_%M_%S"), ctx.invoked_subcommand - ) - log_file_path = log_folder_path / Path(log_prefix + ".log") - logger.add(log_file_path) - if config_file: config_file_path = Path(config_file) else: @@ -138,24 +134,38 @@ def main( else: module_file_path = env_folder_path / Path(DEFAULT_MODULES_FILE) + if config_file_path.exists(): + # Load the main configuration file + with open(config_file_path) as file: + config = yaml.safe_load(file) + ctx.obj["config"] = config + + # ensure log folder exists + ensure_folder_exists(log_folder_path, git_ignore_content=True) + + # Create log file + log_prefix = "{}__{}".format( + date_begin.strftime("%Y_%m_%d__%H_%M_%S"), ctx.invoked_subcommand + ) + log_file_path = log_folder_path / Path(log_prefix + ".log") + logger.add(log_file_path) + + ctx.obj["log_prefix"] = log_prefix + elif ctx.invoked_subcommand not in ("init", None): + ctx.fail( + f"Environment not initialized. " + f"Expected config file at: {config_file_path}", + ) + # Add all global values in the context ctx.obj["env_folder_path"] = env_folder_path ctx.obj["src_folder_path"] = src_folder_path ctx.obj["filestore_folder_path"] = filestore_folder_path ctx.obj["script_folder_path"] = script_folder_path ctx.obj["log_folder_path"] = log_folder_path - ctx.obj["log_prefix"] = log_prefix ctx.obj["config_file_path"] = config_file_path ctx.obj["module_file_path"] = module_file_path - # Load the main configuration file - if config_file_path.exists(): - with open(config_file_path) as file: - config = yaml.safe_load(file) - ctx.obj["config"] = config - elif ctx.invoked_subcommand != "init": - raise - main.add_command(copydb) main.add_command(restoredb) diff --git a/odoo_openupgrade_wizard/cli/cli_copydb.py b/odoo_openupgrade_wizard/cli/cli_copydb.py index a73b7bc..7f1ffd2 100644 --- a/odoo_openupgrade_wizard/cli/cli_copydb.py +++ b/odoo_openupgrade_wizard/cli/cli_copydb.py @@ -10,17 +10,20 @@ from odoo_openupgrade_wizard.tools import ( "-s", "--source", type=str, - help="Name of the database to copy", + help="Name of the source database to copy.", ) @click.option( "-d", "--dest", type=str, - help="Name of the new database", + help="Name of the destination database to create.", ) @click.pass_context def copydb(ctx, source, dest): - """Create an Odoo database by copying an existing one. - it will copy the postgres database and the filestore. + """Create a new Odoo database by copying another. + + This command duplicates both the PostgreSQL database and its associated + filestore. + """ click_odoo_contrib.copydb(ctx, source, dest) diff --git a/odoo_openupgrade_wizard/cli/cli_docker_build.py b/odoo_openupgrade_wizard/cli/cli_docker_build.py index 05d16e3..6fb6036 100644 --- a/odoo_openupgrade_wizard/cli/cli_docker_build.py +++ b/odoo_openupgrade_wizard/cli/cli_docker_build.py @@ -17,11 +17,16 @@ from odoo_openupgrade_wizard.tools.tools_system import get_local_user_id @versions_options @click.pass_context def docker_build(ctx, versions): - """Build Odoo Docker Images and pull Postgres image""" + """Build Docker images and pull PostgreSQL image. + + This command prepares the Docker environment needed for running migration + steps. Make sure to run `oow get-code` first to ensure all required code + and requirements files are available for each version. + """ # Pull DB image logger.info( - "Pulling the postgresql docker image. This can take a while..." + "Pulling the PostgreSQL Docker image. This can take a while..." ) pull_image(ctx.obj["config"]["postgres_image_name"]) @@ -32,16 +37,16 @@ def docker_build(ctx, versions): ) if not odoo_requirement_file_path.exists(): logger.error( - "Building Odoo docker image for version {odoo_version}, " + "Cannot build Odoo Docker image for version {odoo_version}, " "because file {odoo_requirement_file_path} cannot be found. " - "Have your run the get-code command ?", + "Have you run the get-code command?", odoo_version=odoo_version, odoo_requirement_file_path=odoo_requirement_file_path, ) continue logger.info( - f"Building Odoo docker image for version '{odoo_version}'." + f"Building Odoo Docker image for version '{odoo_version}'." " This can take a while..." ) image = build_image( diff --git a/odoo_openupgrade_wizard/cli/cli_dumpdb.py b/odoo_openupgrade_wizard/cli/cli_dumpdb.py index edb9bfb..d247e32 100644 --- a/odoo_openupgrade_wizard/cli/cli_dumpdb.py +++ b/odoo_openupgrade_wizard/cli/cli_dumpdb.py @@ -17,33 +17,34 @@ from odoo_openupgrade_wizard.tools.tools_system import dump_filestore "--database-path", type=click.Path(writable=True, resolve_path=True), required=True, - help="Path to the database dump relative project folder.", + help="Destination path for the database dump relative to the project " + "directory.", ) @click.option( "--database-format", type=click.Choice(("p", "c", "d", "t")), default="c", - help="Database format (see pg_dump options): plain sql text (p), " - "custom format compressed (c), directory (d), tar file (t).", + help="Database format (see pg_dump options): plain SQL (p), " + "custom format compressed (c), directory (d), or tar file (t).", ) @click.option( "--filestore-path", type=click.Path(writable=True, resolve_path=True), required=True, - help="Path to the filestore backup.", + help="Destination path for the filestore backup.", ) @click.option( "--filestore-format", type=click.Choice(("d", "t", "tgz")), default="tgz", help="Filestore format: directory (d), tar file (t), " - "tar file compressed with gzip (tgz)", + "or tar file compressed with gzip (tgz)", ) @click.option( "--force", is_flag=True, default=False, - help="Overwrite file if they already exists.", + help="Overwrite files if they already exist.", ) @click.pass_context def dumpdb( @@ -55,7 +56,14 @@ def dumpdb( filestore_format, force, ): - """Create an dump of an Odoo database and its filestore.""" + """Create a dump of an Odoo database and filestore. + + Creates a backup of the selected Odoo database and + its associated filestore. Both output locations must + reside inside the project directory. Existing files + will be overwritten if --force is specified. + """ + database_path = pathlib.Path(database_path) filestore_path = pathlib.Path(filestore_path) @@ -67,7 +75,7 @@ def dumpdb( ): ctx.fail( "database-path should be inside the project path to allow " - "postgresql to write to it." + "PostgreSQL to write to it." ) # Fail if dumps already exists and force argument not given diff --git a/odoo_openupgrade_wizard/cli/cli_estimate_workload.py b/odoo_openupgrade_wizard/cli/cli_estimate_workload.py index 8a2f93c..58cfb53 100644 --- a/odoo_openupgrade_wizard/cli/cli_estimate_workload.py +++ b/odoo_openupgrade_wizard/cli/cli_estimate_workload.py @@ -17,35 +17,43 @@ from odoo_openupgrade_wizard.tools.tools_system import ( dir_okay=False, ), default="./analysis.html", + help="Path where the HTML analysis report will be saved. " + "Default is './analysis.html'", ) @click.option( "--extra-modules", "extra_modules_list", # TODO, add a callback to check the quality of the argument - help="Coma separated modules to analyse. If not set, the modules.csv" - " file will be used to define the list of module to analyse." - "Ex: 'account,product,base'", + help="Comma-separated list of modules to analyze. If not set, " + "modules.csv will be used. Example: 'account,product,base'.", ) @click.option( "--time-unit", type=click.Choice(["hour", "minute", "separator"]), default="separator", show_default=True, - help="Select unit to display time in the report. " + help="Format to use for displaying time in the report. " "*separator* display time as `HHHMM`, " "*hour* display time as decimal hour, " - "*min* display time as minute (rounded).", + "*min* display time as minutes (rounded).", ) @click.option( "--time-separator", default=":", - help="Specify time separator, if time-unit is separator. " - "Default to `:` (it will produce time like this HHH:MM).", + help="Character to use as a separator in time output. " + "Used only if --time-unit=separator. Default is ':' (e.g. HHH:MM).", ) @click.pass_context def estimate_workload( ctx, analysis_file_path, extra_modules_list, time_unit, time_separator ): + """Estimate workload and create an analysis report. + + This command estimates the workload required for an Odoo + migration based on the module set provided. The output is + an HTML report showing time estimations for each module. + """ + # Analyse analysis = Analysis(ctx) diff --git a/odoo_openupgrade_wizard/cli/cli_execute_script_python.py b/odoo_openupgrade_wizard/cli/cli_execute_script_python.py index e50134c..61e0315 100644 --- a/odoo_openupgrade_wizard/cli/cli_execute_script_python.py +++ b/odoo_openupgrade_wizard/cli/cli_execute_script_python.py @@ -22,11 +22,29 @@ from odoo_openupgrade_wizard.tools.tools_odoo import ( exists=True, dir_okay=False, ), - help="List of python files that will be executed, replacing the default" - " scripts placed in the migration step folder.", + help="""List of Python files to execute, with either an absolute path + or path relative to the project directory. With either method, the + path must be located inside the project directory so that the + Docker container can access it. + + Files will be executed in + the order listed. If no files are specified, all Python (.py) files + in the `step` directory will be sorted alphabetically and then + executed in order. + + See README.md for more information and examples.""", ) @click.pass_context def execute_script_python(ctx, step, database, script_file_path): + """Execute Python scripts for a migration step. + + Executes one or more custom Python scripts in the context of a specific + migration step, using the Odoo shell (with full ORM access). This command + allows you to manually run Python logic outside of the default + post-migration.py file for a given step. It allows fine-tuning + of migration behavior by manually specifying logic. + """ + migration_step = get_migration_step_from_options(ctx, step) execute_click_odoo_python_files( diff --git a/odoo_openupgrade_wizard/cli/cli_execute_script_sql.py b/odoo_openupgrade_wizard/cli/cli_execute_script_sql.py index 39471d2..9c8092b 100644 --- a/odoo_openupgrade_wizard/cli/cli_execute_script_sql.py +++ b/odoo_openupgrade_wizard/cli/cli_execute_script_sql.py @@ -22,11 +22,21 @@ from odoo_openupgrade_wizard.tools.tools_postgres import ( exists=True, dir_okay=False, ), - help="List of SQL files that will be executed, replacing the default" - " scripts placed in the migration step folder.", + help="List of SQL files to execute. Files will be executed in the order " + "listed. If no files are specified, all SQL files (.sql) in the " + "step's directory will be sorted alphabetically and then executed " + "in order.", ) @click.pass_context def execute_script_sql(ctx, step, database, script_file_path): + """Execute SQL scripts for a migration step. + + Executes one or more custom SQL scripts against the specified database, + using the PostgreSQL Docker container. This command allows you to manually + run SQL logic, allowing you to test or apply SQL changes in the context + of a specific migration step — outside the automatic oow upgrade process. + """ + migration_step = get_migration_step_from_options(ctx, step) execute_sql_files_pre_migration( diff --git a/odoo_openupgrade_wizard/cli/cli_generate_module_analysis.py b/odoo_openupgrade_wizard/cli/cli_generate_module_analysis.py index ac37a84..b2c1d45 100644 --- a/odoo_openupgrade_wizard/cli/cli_generate_module_analysis.py +++ b/odoo_openupgrade_wizard/cli/cli_generate_module_analysis.py @@ -28,11 +28,24 @@ from odoo_openupgrade_wizard.tools.tools_system import ensure_folder_writable "-m", "--modules", type=str, - help="Coma-separated list of modules to analysis." - " Let empty to analyse all the Odoo modules.", + help="Comma-separated list of modules to analyse." + " Leave empty to analyse all the Odoo modules.", ) @click.pass_context def generate_module_analysis(ctx, step, database, modules): + """Analyzes changes in data model & module data. + + Performs an analysis between the target version (represented by the step + parameter) and the previous version to indicate how the data model and + module data have changed between the two versions (uses the + OCA/server-tools `upgrade_analysis` tool internally). + + You can also use this function to analyze differences for custom & OCA + modules between several versions (e.g. in case of refactoring). + + See the README.md for more information, including the location of the + resultant analysis files. + """ migration_steps = get_migration_steps_from_options(ctx, step - 1, step) initial_step = migration_steps[0].copy() diff --git a/odoo_openupgrade_wizard/cli/cli_get_code.py b/odoo_openupgrade_wizard/cli/cli_get_code.py index 01ba5c5..3361019 100644 --- a/odoo_openupgrade_wizard/cli/cli_get_code.py +++ b/odoo_openupgrade_wizard/cli/cli_get_code.py @@ -19,11 +19,15 @@ from odoo_openupgrade_wizard.tools.tools_system import git_aggregate type=int, default=10, help="Jobs used to call the git-aggregate command." - " reasonably set to 10 by default.", + " Reasonably set to 10 by default.", ) @click.pass_context def get_code(ctx, versions, jobs): - """Get code by running gitaggregate command for each version""" + """Get all required source code for each version. + + Downloads all required Odoo source code and dependencies for each version + defined in your migration (uses the `gitaggregate` tools internally). + """ for odoo_version in get_odoo_versions_from_options(ctx, versions): folder_path = get_odoo_env_path(ctx, odoo_version) diff --git a/odoo_openupgrade_wizard/cli/cli_guess_requirement.py b/odoo_openupgrade_wizard/cli/cli_guess_requirement.py index ea9d719..c8b6b72 100644 --- a/odoo_openupgrade_wizard/cli/cli_guess_requirement.py +++ b/odoo_openupgrade_wizard/cli/cli_guess_requirement.py @@ -17,12 +17,23 @@ from odoo_openupgrade_wizard.tools.tools_system import ( "--extra-modules", "extra_modules_list", # TODO, add a callback to check the quality of the argument - help="Coma separated modules to analyse. If not set, the modules.csv" - " file will be used to define the list of module to analyse." - "Ex: 'account,product,base'", + help="Comma-separated list of modules to analyze. If not set, " + "modules.csv will be used. Example: 'account,product,base'.", ) @click.pass_context def guess_requirement(ctx, extra_modules_list): + """Guess system & Python requirements for modules. + + Analyzes the list of modules defined in your modules.csv file + to generate the required Python and Debian package dependencies per + environment. + + For each module and each version, this command tries to parse the + corresponding __manifest__.py file (and, if present, the setup.py + file). It then appends any discovered requirements to the appropriate + addons_debian_requirements.txt and addons_python_requirements.txt files + present in each env directory. + """ # Analyse analysis = Analysis(ctx) diff --git a/odoo_openupgrade_wizard/cli/cli_init.py b/odoo_openupgrade_wizard/cli/cli_init.py index 8587000..a7329a3 100644 --- a/odoo_openupgrade_wizard/cli/cli_init.py +++ b/odoo_openupgrade_wizard/cli/cli_init.py @@ -19,42 +19,44 @@ from odoo_openupgrade_wizard.tools.tools_system import ( required=True, prompt=True, type=str, - help="Name of your project without spaces neither special" - " chars or uppercases. exemple 'my-customer-9-12'." - " This will be used to tag with a friendly" - " name the odoo docker images.", + help="Name of your project without spaces, special" + " characters, or uppercases. Example: 'my-customer-9-12'." + " This will be used to tag the Odoo Docker images " + " with a friendly name.", ) @click.option( "--initial-version", required=True, prompt=True, type=click.Choice(get_version_options("initial")), + help="Initial Odoo version to migrate from.", ) @click.option( "--final-version", required=True, prompt=True, type=click.Choice(get_version_options("final")), + help="Target Odoo version to migrate to.", ) @click.option( "--postgresql-version", required=True, prompt=True, - help="The version of postgresql that will be used" - " to create the postgresql container.Ex : '9.1', '16', ..." - " The version should be available in docker hub." - " (https://hub.docker.com/_/postgres)" - " avoid the 'latest' version if you want a deterministic installation." - " Key Point: If your current production server uses Postgresql version A" - " and if your future production server usees Postgresql version B," - " you should select here a version X, with A <= X <= B.", + help="""The version of PostgreSQL that will be used + to create the PostgreSQL container. Example: '9.1', '16', etc. + The version should be available in Docker hub. + (https://hub.docker.com/_/postgres) + Avoid the 'latest' version if you want a deterministic installation. + Key Point: If your current production server uses PostgreSQL version A + and your future production server will use PostgreSQL version B, + you should select here a version X, with A <= X <= B.""", ) @click.option( "--extra-repository", "extra_repository_list", # TODO, add a callback to check the quality of the argument - help="Coma separated extra repositories to use in the odoo environment." - "Ex: 'OCA/web,OCA/server-tools,GRAP/grap-odoo-incubator'", + help="Comma-separated extra repositories to use in the Odoo environment." + "Example: 'OCA/web,OCA/server-tools,GRAP/grap-odoo-incubator'", ) @click.pass_context def init( @@ -65,8 +67,10 @@ def init( postgresql_version, extra_repository_list, ): - """Initialize OOW Environment based on the initial and - the final version of Odoo you want to migrate. + """Initialize the OOW project environment. + + This command sets up the project folder structure, configuration + files, and default templates needed to begin an Odoo migration. """ # Handle arguments diff --git a/odoo_openupgrade_wizard/cli/cli_install_from_csv.py b/odoo_openupgrade_wizard/cli/cli_install_from_csv.py index 5003cf5..34542d3 100644 --- a/odoo_openupgrade_wizard/cli/cli_install_from_csv.py +++ b/odoo_openupgrade_wizard/cli/cli_install_from_csv.py @@ -20,6 +20,12 @@ from odoo_openupgrade_wizard.tools.tools_postgres import ensure_database @demo_option @click.pass_context def install_from_csv(ctx, database, with_demo): + """Install modules from a CSV file. + + This command reads the modules.csv file and installs the + modules listed for a specific Odoo version. The database will be + created if it doesn't exist. + """ migration_step = get_migration_step_from_options(ctx, 1) ensure_database(ctx, database, state="present") @@ -30,7 +36,7 @@ def install_from_csv(ctx, database, with_demo): logger.debug(module_names) try: - logger.info(f"Install 'base' module on {database} database ...") + logger.info(f"Install 'base' module on {database} database...") run_odoo( ctx, migration_step, @@ -58,7 +64,7 @@ def install_from_csv(ctx, database, with_demo): raise Exception( f"Unable to find a country, based on the" f" code {odoo_default_company['country_code']}." - f" Countries found :" + f" Countries found:" f" {', '.join([x.name for x in countries])}" ) vals = { diff --git a/odoo_openupgrade_wizard/cli/cli_options.py b/odoo_openupgrade_wizard/cli/cli_options.py index 76f7df8..fb7bc1c 100644 --- a/odoo_openupgrade_wizard/cli/cli_options.py +++ b/odoo_openupgrade_wizard/cli/cli_options.py @@ -6,10 +6,8 @@ def versions_options(function): "-v", "--versions", type=str, - help="Coma-separated values of odoo versions for which" - " you want to perform the operation." - " Let empty to perform the operation on all the versions" - " of the project", + help="Comma-separated Odoo versions to target. Leave empty to " + "perform the operation on all versions in the project", )(function) return function @@ -30,7 +28,7 @@ def first_step_option(function): function = click.option( "--first-step", type=int, - help="First step for which to perform the operation", + help="First step to include in the operation.", )(function) return function @@ -39,7 +37,7 @@ def last_step_option(function): function = click.option( "--last-step", type=int, - help="Last step for which to perform the operation", + help="Last step to include in the operation.", )(function) return function @@ -48,7 +46,7 @@ def demo_option(function): function = click.option( "--with-demo/--without-demo", default=False, - help="Create database with or without demo data.", + help="Whether to include demo data when creating the database.", )(function) return function @@ -61,7 +59,7 @@ def database_option_required(function): prompt=True, default="postgres", type=str, - help="Odoo Database for which you want to perform the operation.", + help="Name of the Odoo database to operate on. Default is 'postgres'.", )(function) return function diff --git a/odoo_openupgrade_wizard/cli/cli_psql.py b/odoo_openupgrade_wizard/cli/cli_psql.py index 0ec2576..b36fc76 100644 --- a/odoo_openupgrade_wizard/cli/cli_psql.py +++ b/odoo_openupgrade_wizard/cli/cli_psql.py @@ -6,14 +6,29 @@ from odoo_openupgrade_wizard.tools.tools_postgres import execute_psql_command @click.command(context_settings={"ignore_unknown_options": True}) @database_option_required -@click.option("-c", "--command", "request") -@click.option("--pager/--no-pager", default=True) +@click.option( + "-c", + "--command", + "request", + help="SQL command to execute inside the container.", +) +@click.option( + "--pager/--no-pager", + default=True, + help="Enable or disable pager when displaying output.", +) @click.argument("psql_args", nargs=-1, type=click.UNPROCESSED) @click.pass_context def psql(ctx, request, database, pager, psql_args): - """Run psql in the postgres container. Fill any parameters of psql - as PSQLARGS. + """Run a SQL command in the PostgreSQL container. + + This command executes the provided SQL command using `psql` + within the database container. Use --command for inline SQL + or pass additional arguments directly to psql via PSQLARGS. + + See the README.md for more information. """ + result = execute_psql_command(ctx, request, database, psql_args) if pager: click.echo_via_pager(result) diff --git a/odoo_openupgrade_wizard/cli/cli_pull_submodule.py b/odoo_openupgrade_wizard/cli/cli_pull_submodule.py index e5aaa24..eefe344 100644 --- a/odoo_openupgrade_wizard/cli/cli_pull_submodule.py +++ b/odoo_openupgrade_wizard/cli/cli_pull_submodule.py @@ -13,8 +13,12 @@ from odoo_openupgrade_wizard.tools.tools_system import execute_check_output @versions_options @click.pass_context def pull_submodule(ctx, versions): - """Pull submodule that contains repos.yml file, if define in config.yml""" + """Pull the repos.yml file from a Git repository. + This command runs `git submodule update --init --recursive` + for the submodule that contains your `repos.yml` file. + This ensures all nested submodules are also fetched. + """ for odoo_version in get_odoo_versions_from_options(ctx, versions): version_cfg = ( ctx.obj["config"]["odoo_version_settings"][odoo_version] or {} @@ -22,7 +26,7 @@ def pull_submodule(ctx, versions): if version_cfg.get("repo_url"): logger.info( f"Pull repos.yml from git repository" - f" for version {odoo_version} ..." + f" for version {odoo_version}..." ) submodule_path = ( get_odoo_env_path(ctx, odoo_version) / "repo_submodule" @@ -53,5 +57,5 @@ def pull_submodule(ctx, versions): else: logger.warning( f"No submodule configuration found" - f" for version {odoo_version} ..." + f" for version {odoo_version}..." ) diff --git a/odoo_openupgrade_wizard/cli/cli_restoredb.py b/odoo_openupgrade_wizard/cli/cli_restoredb.py index 5d474ec..e769c5e 100644 --- a/odoo_openupgrade_wizard/cli/cli_restoredb.py +++ b/odoo_openupgrade_wizard/cli/cli_restoredb.py @@ -13,30 +13,29 @@ from odoo_openupgrade_wizard.tools.tools_system import restore_filestore "--database-path", required=True, type=click.Path(readable=True, resolve_path=True, exists=True), - help="Path to the database dump relative project folder.", + help="Path to the database dump (inside the environment folder).", ) @click.option( "--database-format", required=True, type=click.Choice(("c", "d", "t", "p")), default="c", - help="Database format (see pg_dump options): " - "custom format compressed (c), directory (d), tar file (t)," - " plain sql text (p).", + help="Format of the database dump: custom (c), directory (d), tar (t), " + "or plain SQL (p).", ) @click.option( "--filestore-path", required=True, type=click.Path(readable=True, resolve_path=True, exists=True), - help="Path to the filestore backup.", + help="Path to the filestore backup (inside the environment folder).", ) @click.option( "--filestore-format", required=True, type=click.Choice(("d", "t", "tgz")), default="tgz", - help="Filestore format: directory (d), tar file (t), " - "tar file compressed with gzip (tgz)", + help="Format of the filestore: directory (d), tar (t), or gzip-compressed " + "tar (tgz).", ) @click.pass_context def restoredb( @@ -47,7 +46,13 @@ def restoredb( filestore_path, filestore_format, ): - """Restore an Odoo database and associated filestore.""" + """Restore a database and its associated filestore. + + This command restores a PostgreSQL database and its matching Odoo + filestore into the current OOW environment. The filestore and + database dump must be accessible from within the environment directory + so that the Docker container can read them during restore. + """ database_path = Path(database_path) filestore_path = Path(filestore_path) @@ -57,7 +62,7 @@ def restoredb( if not str(database_path).startswith(str(absolute_env_folder_path)): ctx.fail( "database-path should be inside the project path to allow " - "postgresql to read to it." + "PostgreSQL to read it." ) # Restore the database diff --git a/odoo_openupgrade_wizard/cli/cli_run.py b/odoo_openupgrade_wizard/cli/cli_run.py index 56e36c9..9964563 100644 --- a/odoo_openupgrade_wizard/cli/cli_run.py +++ b/odoo_openupgrade_wizard/cli/cli_run.py @@ -27,13 +27,13 @@ from odoo_openupgrade_wizard.tools.tools_postgres import ensure_database "-i", "--init-modules", type=str, - help="List of modules to install. Equivalent to -i odoo options.", + help="List of modules to install. Equivalent to -i Odoo options.", ) @click.option( "-u", "--update-modules", type=str, - help="List of modules to update. Equivalent to -u odoo options.", + help="List of modules to update. Equivalent to -u Odoo options.", ) @click.option( "-e", @@ -41,7 +41,7 @@ from odoo_openupgrade_wizard.tools.tools_postgres import ensure_database type=click.Choice(["regular", "openupgrade"]), help="Force to use an openupgrade (OCA/openupgrade)" " or a regular (odoo/odoo or OCA/OCB) base code when running odoo." - " Let empty to use the defaut execution of the migration step.", + " Leave empty to use the default execution of the migration step.", ) @click.pass_context def run( @@ -54,6 +54,14 @@ def run( update_modules, execution_context, ): + """Run Odoo for a specific migration step. + + The database will be created if it doesn't already exist. Unless the + `stop-after-init` flag is used, the Odoo instance will be available + on your host at the following URL: http://localhost:9069 + (port depends on the `host_odoo_xmlrpc_port` setting in your + `config.yml` file). + """ migration_step = get_migration_step_from_options(ctx, step) ensure_database(ctx, database, state="present") try: @@ -74,7 +82,7 @@ def run( "Odoo is available on your host at http://localhost:" f"{ctx.obj['config']['odoo_host_xmlrpc_port']}" ) - input("Press 'Enter' to kill the odoo container and exit ...") + input("Press 'Enter' to kill the odoo container and exit...") except (KeyboardInterrupt, SystemExit): logger.info("Received Keyboard Interrupt or System Exiting...") finally: diff --git a/odoo_openupgrade_wizard/cli/cli_upgrade.py b/odoo_openupgrade_wizard/cli/cli_upgrade.py index a7e06c0..a5c1427 100644 --- a/odoo_openupgrade_wizard/cli/cli_upgrade.py +++ b/odoo_openupgrade_wizard/cli/cli_upgrade.py @@ -25,6 +25,16 @@ from odoo_openupgrade_wizard.tools.tools_postgres import ( @demo_option @click.pass_context def upgrade(ctx, first_step, last_step, database, with_demo): + """Performs the full db migration across all steps. + + For each step, this will: + + 1. Run `pre-migration.sql` scripts. + + 2. Apply "update all" (in an upgrade or update context). + + 3. Run `post-migration.py` scripts via XML-RPC/Odoo shell (via `odoorpc`). + """ migration_steps = get_migration_steps_from_options( ctx, first_step, last_step ) diff --git a/odoo_openupgrade_wizard/configuration_version_dependant.py b/odoo_openupgrade_wizard/configuration_version_dependant.py index fc3f90b..eec31af 100644 --- a/odoo_openupgrade_wizard/configuration_version_dependant.py +++ b/odoo_openupgrade_wizard/configuration_version_dependant.py @@ -51,7 +51,7 @@ def get_odoo_run_command(migration_step: dict) -> str: def get_odoo_folder( - migration_step: dict, execution_context: str = False + migration_step: dict, execution_context: str = None ) -> str: """return the main odoo folder, depending on the migration step. (./src/odoo, ./src/openupgrade, ...)""" @@ -100,7 +100,7 @@ def skip_addon_path(migration_step: dict, path: Path) -> bool: def get_server_wide_modules_upgrade( - migration_step: dict, execution_context: str = False + migration_step: dict, execution_context: str = None ) -> list: """return a list of modules to load, depending on the migration step.""" if ( @@ -125,8 +125,8 @@ def get_upgrade_analysis_module(migration_step: dict) -> str: def generate_records(odoo_instance, migration_step: dict): logger.info( - "Generate Records in version %s ..." - " (It can take a while)" % (migration_step["version"]) + "Generate Records in version %s..." + " (This may take a while)" % (migration_step["version"]) ) if migration_step["version"] < 14.0: wizard = odoo_instance.browse_by_create( @@ -165,7 +165,7 @@ def generate_analysis_files( ): logger.info( "Generate analysis files for" - " the modules installed on %s ..." % (initial_database) + " the modules installed on %s..." % (initial_database) ) proxy_vals = { "name": "Proxy to Previous version", @@ -176,12 +176,12 @@ def generate_analysis_files( "password": "admin", } if final_step["version"] < 14.0: - logger.info("> Create proxy ...") + logger.info("> Create proxy...") proxy = final_odoo_instance.browse_by_create( "openupgrade.comparison.config", proxy_vals ) - logger.info("> Create wizard ...") + logger.info("> Create wizard...") wizard = final_odoo_instance.browse_by_create( "openupgrade.analysis.wizard", { @@ -189,16 +189,16 @@ def generate_analysis_files( "write_files": True, }, ) - logger.info("> Launch analysis. This can take a while ...") + logger.info("> Launch analysis. This can take a while...") wizard.get_communication() else: - logger.info("> Create proxy ...") + logger.info("> Create proxy...") proxy = final_odoo_instance.browse_by_create( "upgrade.comparison.config", proxy_vals ) - logger.info("> Create wizard ...") + logger.info("> Create wizard...") analysis = final_odoo_instance.browse_by_create( "upgrade.analysis", { @@ -206,7 +206,7 @@ def generate_analysis_files( }, ) - logger.info("> Launch analysis. This can take a while ...") + logger.info("> Launch analysis. This can take a while...") analysis.analyze() @@ -267,6 +267,6 @@ def get_openupgrade_analysis_files( module_name = file.parent.parent.name result[module_name] = file logger.debug( - "Version %s : %d analysis files found." % (version, len(result)) + "Version %s: %d analysis files found." % (version, len(result)) ) return result diff --git a/odoo_openupgrade_wizard/templates/odoo/13.0/Dockerfile b/odoo_openupgrade_wizard/templates/odoo/13.0/Dockerfile index db919b7..8a1edc6 100644 --- a/odoo_openupgrade_wizard/templates/odoo/13.0/Dockerfile +++ b/odoo_openupgrade_wizard/templates/odoo/13.0/Dockerfile @@ -1,6 +1,9 @@ # : Copy of https://github.com/odoo/odoo/blob/13.0/setup/package.dfsrc FROM debian:buster +RUN sed -i -- 's/security.debian.org/archive.debian.org/g' /etc/apt/**.list +RUN sed -i -- 's/deb.debian.org/archive.debian.org/g' /etc/apt/**.list + RUN apt-get update && \ apt-get install -y locales && \ rm -rf /var/lib/apt/lists/* diff --git a/odoo_openupgrade_wizard/templates/odoo/14.0/Dockerfile b/odoo_openupgrade_wizard/templates/odoo/14.0/Dockerfile index c49fa10..9c97364 100644 --- a/odoo_openupgrade_wizard/templates/odoo/14.0/Dockerfile +++ b/odoo_openupgrade_wizard/templates/odoo/14.0/Dockerfile @@ -1,6 +1,9 @@ # : Copy of https://github.com/odoo/odoo/blob/14.0/setup/package.dfsrc FROM debian:buster +RUN sed -i -- 's/security.debian.org/archive.debian.org/g' /etc/apt/**.list +RUN sed -i -- 's/deb.debian.org/archive.debian.org/g' /etc/apt/**.list + RUN apt-get update && \ apt-get install -y locales && \ rm -rf /var/lib/apt/lists/* diff --git a/odoo_openupgrade_wizard/templates/odoo/15.0/Dockerfile b/odoo_openupgrade_wizard/templates/odoo/15.0/Dockerfile index f568cd1..9e831e5 100644 --- a/odoo_openupgrade_wizard/templates/odoo/15.0/Dockerfile +++ b/odoo_openupgrade_wizard/templates/odoo/15.0/Dockerfile @@ -1,6 +1,9 @@ # : Copy of https://github.com/odoo/odoo/blob/15.0/setup/package.dfsrc FROM debian:buster +RUN sed -i -- 's/security.debian.org/archive.debian.org/g' /etc/apt/**.list +RUN sed -i -- 's/deb.debian.org/archive.debian.org/g' /etc/apt/**.list + RUN apt-get update && \ apt-get install -y locales && \ rm -rf /var/lib/apt/lists/* diff --git a/odoo_openupgrade_wizard/templates/odoo/16.0/Dockerfile b/odoo_openupgrade_wizard/templates/odoo/16.0/Dockerfile index edffb97..636f620 100644 --- a/odoo_openupgrade_wizard/templates/odoo/16.0/Dockerfile +++ b/odoo_openupgrade_wizard/templates/odoo/16.0/Dockerfile @@ -1,6 +1,9 @@ # : Copy of https://github.com/odoo/odoo/blob/16.0/setup/package.dfsrc FROM debian:buster +RUN sed -i -- 's/security.debian.org/archive.debian.org/g' /etc/apt/**.list +RUN sed -i -- 's/deb.debian.org/archive.debian.org/g' /etc/apt/**.list + RUN apt-get update && \ apt-get install -y locales && \ rm -rf /var/lib/apt/lists/* diff --git a/odoo_openupgrade_wizard/templates/scripts/post-migration.py.j2 b/odoo_openupgrade_wizard/templates/scripts/post-migration.py.j2 index a4b3aa5..71d5f2e 100644 --- a/odoo_openupgrade_wizard/templates/scripts/post-migration.py.j2 +++ b/odoo_openupgrade_wizard/templates/scripts/post-migration.py.j2 @@ -1,7 +1,7 @@ import logging _logger = logging.getLogger(__name__) -_logger.info("Executing post-migration.py script ...") +_logger.info("Executing post-migration.py script...") env = env # noqa: F821 diff --git a/odoo_openupgrade_wizard/tools/tools_click_odoo_contrib.py b/odoo_openupgrade_wizard/tools/tools_click_odoo_contrib.py index 0478b05..1e9e0a1 100644 --- a/odoo_openupgrade_wizard/tools/tools_click_odoo_contrib.py +++ b/odoo_openupgrade_wizard/tools/tools_click_odoo_contrib.py @@ -27,7 +27,7 @@ def copydb(ctx, source, dest): shutil.rmtree(dest_path, ignore_errors=True) # Copy Filestore - logger.info(f"Copy filestore of '{source}' into '{dest}' folder ...") + logger.info(f"Copy filestore of '{source}' into '{dest}' directory...") shutil.copytree(source_path, dest_path) diff --git a/odoo_openupgrade_wizard/tools/tools_docker.py b/odoo_openupgrade_wizard/tools/tools_docker.py index dadfcd0..0787010 100644 --- a/odoo_openupgrade_wizard/tools/tools_docker.py +++ b/odoo_openupgrade_wizard/tools/tools_docker.py @@ -16,7 +16,7 @@ def pull_image(image_name): def build_image(path, tag, buildargs={}): logger.debug( f"Building image named based on {path}/Dockerfile." - " This can take a big while ..." + " This can take a long time..." ) debug_docker_command = f"docker build {path} --tag {tag}" for arg_name, arg_value in buildargs.items(): @@ -30,6 +30,7 @@ def build_image(path, tag, buildargs={}): path=str(path), tag=tag, buildargs=buildargs, + rm=True, ) logger.debug("Image build done.") except docker.errors.BuildError as buildError: @@ -58,7 +59,7 @@ def run_container( " Did you run 'odoo-openupgrade-wizard docker-build' ?" ) - logger.debug(f"Launching Docker container named {image_name} ...") + logger.debug(f"Launching Docker container named {image_name}...") debug_docker_command = f"docker run --name {container_name}\\\n" for k, v in ports.items(): @@ -105,8 +106,8 @@ def exec_container(container, command): if docker_result.exit_code != 0: raise Exception( f"The command failed in the container {container.name}.\n" - f"- Command : {command}\n" - f"- Exit Code : {docker_result.exit_code}\n" + f"- Command: {command}\n" + f"- Exit Code: {docker_result.exit_code}\n" f"- Output: {docker_result.output}" ) return docker_result diff --git a/odoo_openupgrade_wizard/tools/tools_odoo.py b/odoo_openupgrade_wizard/tools/tools_odoo.py index 71a658f..badb8df 100644 --- a/odoo_openupgrade_wizard/tools/tools_odoo.py +++ b/odoo_openupgrade_wizard/tools/tools_odoo.py @@ -52,7 +52,7 @@ def get_odoo_addons_path( ctx, odoo_env_path: Path, migration_step: dict, - execution_context: str = False, + execution_context: str = None, ) -> str: """Return - addons_path: a list of Path of that contains odoo module @@ -146,12 +146,12 @@ def generate_odoo_command_options( execution_context: str, database: str, demo: bool = False, - update: str = False, - init: str = False, + update: str = None, + init: str = None, stop_after_init: bool = False, ) -> list: """ - Generate Odoo command options as a list of strings to append to any command. + Generate Odoo command options as a list of string to append to any command. """ odoo_env_path = get_odoo_env_path(ctx, migration_step["version"]) @@ -230,8 +230,8 @@ def generate_odoo_command( execution_context: str, database: str, demo: bool = False, - update: str = False, - init: str = False, + update: str = None, + init: str = None, stop_after_init: bool = False, shell: bool = False, ) -> str: @@ -267,13 +267,13 @@ def run_odoo( ctx, migration_step: dict, detached_container: bool = False, - database: str = False, - update: str = False, - init: str = False, + database: str = None, + update: str = None, + init: str = None, stop_after_init: bool = False, shell: bool = False, demo: bool = False, - execution_context: str = False, + execution_context: str = None, alternative_xml_rpc_port: int = False, links: dict = {}, publish_ports: bool = False, @@ -290,8 +290,8 @@ def run_odoo( or migration_step["execution_context"], demo_text=demo and "enabled" or "disabled", stop_text=stop_after_init and " (stop-after-init)" or "", - init_text=init and " (Init : %s)" % init or "", - update_text=update and " (Update : %s)" % update or "", + init_text=init and " (Init: %s)" % init or "", + update_text=update and " (Update: %s)" % update or "", ) ) @@ -325,9 +325,9 @@ def run_container_odoo( migration_step: dict, command: str, detached_container: bool = False, - database: str = False, + database: str = None, alternative_xml_rpc_port: int = False, - execution_context: str = False, + execution_context: str = None, links: dict = {}, publish_ports: bool = False, ): @@ -371,7 +371,7 @@ def execute_click_odoo_python_files( database: str, migration_step: dict, python_files: list = [], - execution_context: str = False, + execution_context: str = None, ): if not python_files: # Get post-migration python scripts to execute @@ -397,7 +397,7 @@ def execute_click_odoo_python_files( try: logger.info( f"Step {migration_step['complete_name']}." - f" Executing script {python_file} ..." + f" Executing script {python_file}..." ) run_container_odoo( ctx, @@ -419,7 +419,7 @@ def execute_click_odoo_python_files( def get_odoo_modules_from_csv(module_file_path: Path) -> list: - logger.debug(f"Reading '{module_file_path}' file ...") + logger.debug(f"Reading '{module_file_path}' file...") module_names = [] csvfile = open(module_file_path, "r") spamreader = csv.reader(csvfile, delimiter=",", quotechar='"') diff --git a/odoo_openupgrade_wizard/tools/tools_odoo_instance.py b/odoo_openupgrade_wizard/tools/tools_odoo_instance.py index 0211be9..bd16a71 100644 --- a/odoo_openupgrade_wizard/tools/tools_odoo_instance.py +++ b/odoo_openupgrade_wizard/tools/tools_odoo_instance.py @@ -39,7 +39,7 @@ class OdooInstance: logger.debug( f"{x}/{_ODOO_RPC_MAX_TRY}" " Unable to connect to the server." - " Retrying in 1 second ..." + " Retrying in 1 second..." ) time.sleep(1) else: @@ -96,7 +96,7 @@ class OdooInstance: while installed is False: try_qty += 1 try_qty_text = f" (try #{try_qty})" if try_qty != 1 else "" - logger.info(f"{log_prefix}': Installing ...{try_qty_text}") + logger.info(f"{log_prefix}': Installing... {try_qty_text}") try: module.button_immediate_install() installed = True diff --git a/odoo_openupgrade_wizard/tools/tools_odoo_module.py b/odoo_openupgrade_wizard/tools/tools_odoo_module.py index 87e62bb..5b04faf 100644 --- a/odoo_openupgrade_wizard/tools/tools_odoo_module.py +++ b/odoo_openupgrade_wizard/tools/tools_odoo_module.py @@ -106,13 +106,13 @@ class Analysis(object): last_module_version.analyse_missing_module() def estimate_workload(self, ctx): - logger.info("Estimate workload ...") + logger.info("Estimate workload...") for odoo_module in self.modules: for module_version in odoo_module.module_versions.values(): module_version.estimate_workload(ctx) def get_requirements(self, ctx): - logger.info("Get requirements ...") + logger.info("Get requirements...") result = {x: {"python": {}, "bin": {}} for x in self.all_versions} for odoo_module in self.modules: @@ -201,14 +201,14 @@ class Analysis(object): state = "renamed" new_module_name = renamed_modules[odoo_module.name] logger.debug( - f"{previous_version} -> {current_version} :" + f"{previous_version} -> {current_version}:" f" {odoo_module.name} renamed into {new_module_name}" ) elif odoo_module.name in merged_modules: state = "merged" new_module_name = merged_modules[odoo_module.name] logger.debug( - f"{previous_version} -> {current_version} :" + f"{previous_version} -> {current_version}:" f" {odoo_module.name} merged into {new_module_name}" ) @@ -349,7 +349,7 @@ class OdooModule(object): return res def get_odoo_apps_url(self): - logger.info(f"Searching {self.name} in the Odoo appstore ...") + logger.info(f"Searching {self.name} in the Odoo appstore...") url = ( f"https://apps.odoo.com/apps/modules/" f"{self.analyse.initial_version}/{self.name}/" @@ -364,7 +364,7 @@ class OdooModule(object): return False def get_odoo_code_search_url(self): - logger.info(f"Searching {self.name} in Odoo-Code-Search ...") + logger.info(f"Searching {self.name} in Odoo-Code-Search...") url = ( f"https://odoo-code-search.com/ocs/search?" f"q=name%3A%3D{self.name}+version%3A{self.analyse.initial_version}" diff --git a/odoo_openupgrade_wizard/tools/tools_postgres.py b/odoo_openupgrade_wizard/tools/tools_postgres.py index 522c48f..735dd6a 100644 --- a/odoo_openupgrade_wizard/tools/tools_postgres.py +++ b/odoo_openupgrade_wizard/tools/tools_postgres.py @@ -42,7 +42,7 @@ def get_postgres_container(ctx): # Check if volume exists try: client.volumes.get(volume_name) - logger.debug(f"Recovering existing postgres volume: {volume_name}") + logger.debug(f"Recovering existing PostgreSQL volume: {volume_name}") except docker.errors.NotFound: logger.info(f"Creating Postgres volume: {volume_name}") client.volumes.create(volume_name) @@ -53,7 +53,7 @@ def get_postgres_container(ctx): for key, value in postgres_extra_settings.items(): command += f" -c {key}={value}" - logger.info(f"Launching Postgres Container. (Image {image_name})") + logger.info(f"Launching PostgreSQL Container. (Image {image_name})") # base environement variables environments = { @@ -69,7 +69,7 @@ def get_postgres_container(ctx): postgres_version = float(image_name.split(":")[1]) except ValueError: raise Exception( - "Unable to extract postgres version " + "Unable to extract PostgreSQL version " f"from image name {image_name}. " "Define version in the image name is mandatory." ) @@ -120,8 +120,8 @@ def execute_sql_file(ctx, database, sql_file): if str(ctx.obj["env_folder_path"]) not in str(sql_file): raise Exception( f"The SQL file {sql_file} is not in the" - f" main folder {ctx.obj['env_folder_path']} available" - " in the postgres container." + f" main directory {ctx.obj['env_folder_path']} available" + " in the PostgreSQL container." ) relative_path = Path( str(sql_file).replace(str(ctx.obj["env_folder_path"]), ".") @@ -132,7 +132,7 @@ def execute_sql_file(ctx, database, sql_file): "psql --username=odoo --dbname={database} --file {file_path}" ).format(database=database, file_path=container_path) logger.info( - f"Executing the script '{relative_path}' in postgres container" + f"Executing the script '{relative_path}' in PostgreSQL container" f" on database {database}" ) exec_container(container, command) @@ -163,7 +163,7 @@ def execute_psql_command( f" {' '.join(psql_args)}" ) logger.debug( - f"Executing the following command in postgres container\n{command}" + f"Executing the following command in PostgreSQL container\n{command}" ) docker_result = exec_container(container, command) return docker_result.output.decode("utf-8") @@ -241,7 +241,7 @@ def chown_to_local_user(ctx, filepath: os.PathLike): uid=user_uid, filepath=filepath ) logger.debug( - f"Executing the following command in postgres container:\n{command}" + f"Executing the following command in PostgreSQL container:\n{command}" ) chown_result = exec_container(container, command) return chown_result.output.decode("utf8") @@ -277,7 +277,7 @@ def execute_pg_dump( pg_dump_args=pg_dump_args, ) logger.debug( - f"Executing the following command in postgres container:\n{command}" + f"Executing the following command in PostgreSQL container:\n{command}" ) pg_dump_result = exec_container(container, command) diff --git a/odoo_openupgrade_wizard/tools/tools_system.py b/odoo_openupgrade_wizard/tools/tools_system.py index 5918197..764e9f4 100644 --- a/odoo_openupgrade_wizard/tools/tools_system.py +++ b/odoo_openupgrade_wizard/tools/tools_system.py @@ -19,7 +19,7 @@ def get_script_folder(ctx, migration_step: dict) -> Path: def ensure_folder_writable(folder_path: Path): - logger.info(f"Make writable the folder '{folder_path}'") + logger.info(f"Make writable the directory '{folder_path}'") try: chmod(["--silent", "--recursive", "o+w", str(folder_path)]) except ProcessExecutionError: @@ -35,9 +35,9 @@ def ensure_folder_exists( - a log is done at INFO level. """ if not folder_path.exists(): - cmd = ["--parents", folder_path] - cmd = ["--mode", mode] + cmd - logger.info(f"Creating folder '{folder_path}' ...") + cmd = ["-p", folder_path] + cmd = ["-m", mode] + cmd + logger.info(f"Creating directory '{folder_path}'...") mkdir(cmd) if git_ignore_content: @@ -74,9 +74,9 @@ def ensure_file_exists_from_template( if data == output: return - log_text = f"Updating file '{file_path}' from template ..." + log_text = f"Updating file '{file_path}' from template..." else: - log_text = f"Creating file '{file_path}' from template ..." + log_text = f"Creating file '{file_path}' from template..." with open(file_path, "w") as f: logger.info(log_text) @@ -90,7 +90,7 @@ def git_aggregate(folder_path: Path, config_path: Path, jobs: int): jobs=jobs, dirmatch=None, do_push=False, - expand_env=True, + expand_env=False, env_file=None, force=True, ) @@ -98,7 +98,7 @@ def git_aggregate(folder_path: Path, config_path: Path, jobs: int): os.chdir(folder_path) logger.info( f"Gitaggregate source code for {config_path}." - " This can take a while ..." + " This can take a while..." ) gitaggregate_cmd.run(args) diff --git a/pyproject.toml b/pyproject.toml index 2772efe..bbb493a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "odoo-openupgrade-wizard" -version = "1.3.0" +version = "1.3.1" description = "CLI tool to manage Odoo Major Upgrades" authors = [ {name = "Sylvain LE GAL", email = "sylvain.legal@grap.coop"}, @@ -64,7 +64,6 @@ pylint = "*" tox = "*" towncrier = "*" - [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" diff --git a/tests/__init__.py b/tests/__init__.py index b6de448..54116b7 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -25,7 +25,7 @@ def move_to_test_folder(): if os.getcwd().endswith("tests/data/output"): return test_folder_path = Path("tests/data/output") - mkdir([test_folder_path, "--parents"]) + mkdir(["-p", test_folder_path]) os.chdir(test_folder_path)