Compare commits
56 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 94a718457b | |||
| a5f7f2e88c | |||
| bf07bc1865 | |||
| e41abfc928 | |||
| a34d880721 | |||
| a362783e6d | |||
|
|
6bb379d92b | ||
|
|
e8da97fca7 | ||
|
|
7b8f9f828a | ||
|
|
3c5a589cd8 | ||
|
|
32cde3f0e7 | ||
|
|
2e2799c612 | ||
|
|
43370fae23 | ||
|
|
8bf6dd385a | ||
|
|
42bf4f4379 | ||
|
|
bfde1ddc1f | ||
|
|
9687e8656a | ||
|
|
65e7e2c57e | ||
|
|
4fc7056932 | ||
|
|
ca53f46248 | ||
|
|
7d1183b140 | ||
|
|
a00ee58b62 | ||
|
|
2abf4ee896 | ||
|
|
c66789dc71 | ||
|
|
026cae6f5e | ||
|
|
a960ddc83c | ||
|
|
95f58f3a9f | ||
|
|
d595c6584c | ||
|
|
eec7068628 | ||
|
|
a3015e579a | ||
|
|
8003a86bc1 | ||
|
|
c4f0214cc7 | ||
|
|
f965f867ec | ||
|
|
6c069dbffd | ||
|
|
188744be2e | ||
|
|
88b2789f9b | ||
|
|
86b59fe127 | ||
|
|
429a1da9b1 | ||
|
|
4a44369d84 | ||
|
|
09347959fe | ||
|
|
4b4ec890b2 | ||
|
|
5178bbc8ff | ||
|
|
0bfacbd133 | ||
|
|
68bfe19acd | ||
|
|
3b3d652756 | ||
|
|
8791a883f9 | ||
|
|
2d4a7d6917 | ||
|
|
c0b8be6b20 | ||
|
|
1f079e088e | ||
|
|
0785c31825 | ||
|
|
684b1b1d3e | ||
|
|
1b201a52d4 | ||
|
|
02cf5f2d51 | ||
|
|
4bf0a1c055 | ||
|
|
f500cbc6aa | ||
|
|
ab513187f5 |
|
|
@ -77,9 +77,7 @@ pytest:
|
||||||
matrix:
|
matrix:
|
||||||
- PYTHON_VERSION:
|
- PYTHON_VERSION:
|
||||||
- "3.9"
|
- "3.9"
|
||||||
- "3.10"
|
- "3.13"
|
||||||
- "3.11"
|
|
||||||
- "3.12"
|
|
||||||
|
|
||||||
build:
|
build:
|
||||||
stage: build
|
stage: build
|
||||||
|
|
|
||||||
23
.vscode/launch.json
vendored
Normal file
23
.vscode/launch.json
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
// Verwendet IntelliSense zum Ermitteln möglicher Attribute.
|
||||||
|
// Zeigen Sie auf vorhandene Attribute, um die zugehörigen Beschreibungen anzuzeigen.
|
||||||
|
// Weitere Informationen finden Sie unter https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Python-Debugger: Remoteanfügung",
|
||||||
|
"type": "debugpy",
|
||||||
|
"request": "attach",
|
||||||
|
"connect": {
|
||||||
|
"host": "localhost",
|
||||||
|
"port": 5678
|
||||||
|
},
|
||||||
|
"pathMappings": [
|
||||||
|
{
|
||||||
|
"localRoot": "${workspaceFolder}",
|
||||||
|
"remoteRoot": "/home/lotzm/odoo-openupgrade-wizard"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"python.defaultInterpreterPath": "/home/lotzm/.local/share/pipx/venvs/odoo-openupgrade-wizard/bin/python"
|
||||||
|
}
|
||||||
106
CHANGES.rst
106
CHANGES.rst
|
|
@ -6,6 +6,112 @@ This file compiles releases and changes made in
|
||||||
|
|
||||||
.. towncrier release notes start
|
.. 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)
|
||||||
|
==========================================
|
||||||
|
|
||||||
|
Features
|
||||||
|
--------
|
||||||
|
|
||||||
|
- Disable default Odoo memory limit (of 2560 MiB) by default.
|
||||||
|
This can be adjusted in the `odoo.conf` file for each version.
|
||||||
|
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
-------------
|
||||||
|
|
||||||
|
- Improve release documentation for developpers.
|
||||||
|
|
||||||
|
|
||||||
|
Misc
|
||||||
|
----
|
||||||
|
|
||||||
|
- set a default 'postgres' database in ``oow psql`` command, to avoid
|
||||||
|
force user to set a database, in case of dbless command.
|
||||||
|
|
||||||
|
|
||||||
|
odoo-openupgrade-wizard 1.2.0 (2025-04-12)
|
||||||
|
==========================================
|
||||||
|
|
||||||
|
Features
|
||||||
|
--------
|
||||||
|
|
||||||
|
- Add an option ``update`` in the configuration file at migration_step level.
|
||||||
|
If disabled, the update=all step will be skipped during this step.
|
||||||
|
That can be interesting to save time, during the first and the last steps of the migration
|
||||||
|
process (when ``execution_context='regular'``).
|
||||||
|
- Improve workload analysis file with button to hide done module.
|
||||||
|
|
||||||
|
Bugfixes
|
||||||
|
--------
|
||||||
|
|
||||||
|
- Handles the case where the filestore data provided in the source is in a "filestore" subfolder.
|
||||||
|
|
||||||
|
Misc
|
||||||
|
----
|
||||||
|
|
||||||
|
- restoredb: Use builtins click feature to check if provided paths exist
|
||||||
|
- Refactoring of the function tools.tools_odoo.generate_odoo_command.
|
||||||
|
|
||||||
|
odoo-openupgrade-wizard 1.1.0 (2024-11-07)
|
||||||
|
==========================================
|
||||||
|
|
||||||
|
Features
|
||||||
|
--------
|
||||||
|
|
||||||
|
- Support 17.0 serie.
|
||||||
|
- Support 18.0 serie.
|
||||||
|
- add a new command ``odoo-openupgrade-wizard guess-requirement`` that
|
||||||
|
initialize the python and bin requirements files, based on the odoo
|
||||||
|
modules present in the modules.csv file, and analyzing code.
|
||||||
|
(``__manifest__.py`` and ``setup.py`` files)
|
||||||
|
|
||||||
|
|
||||||
|
Misc
|
||||||
|
----
|
||||||
|
|
||||||
|
- Add support of python 3.13.
|
||||||
|
- Test only on the first and the last supported python version. (python3.9 and
|
||||||
|
python3.13).
|
||||||
|
This change allow to save time and resources on CI execution.
|
||||||
|
|
||||||
|
|
||||||
odoo-openupgrade-wizard 1.0.3 (2024-10-09)
|
odoo-openupgrade-wizard 1.0.3 (2024-10-09)
|
||||||
==========================================
|
==========================================
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@
|
||||||
* Boris GALLET, since September 2024
|
* Boris GALLET, since September 2024
|
||||||
* Ahmet YIĞIT BUDAK, from [Altinkaya](https://www.altinkaya.com/fr), since October 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
|
* 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
|
# Reviewers
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,14 @@ release, if it is a major, minor or patch release. For alpha, beta, etc
|
||||||
release information will be published with the next major, minor or
|
release information will be published with the next major, minor or
|
||||||
patch release.
|
patch release.
|
||||||
|
|
||||||
|
To generate the `CHANGES.rst`, run the towncrier tool:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
towncrier build
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `--draft` option to preview the result.
|
||||||
|
|
||||||
Then push a commit with the version and the changlog updated on the main
|
Then push a commit with the version and the changlog updated on the main
|
||||||
branch.
|
branch.
|
||||||
|
|
||||||
|
|
|
||||||
19
PATCH.md
Normal file
19
PATCH.md
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Loakale Entwicklung an oow
|
||||||
|
Das geht am einfachsten mit **pipx** im "editable mode" (`--editable`), sodass Änderungen im Arbeitsverzeichnis sofort wirksam sind.
|
||||||
|
|
||||||
|
Angenommen, dein Arbeitsverzeichnis ist odoo-openupgrade-wizard, dann führe im Terminal aus:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pipx install --editable /home/lotzm/gitea.hobbyhimmel/odoo-openupgrade-wizard
|
||||||
|
```
|
||||||
|
|
||||||
|
Dadurch wird ein Symlink auf dein Arbeitsverzeichnis erstellt und du kannst direkt am Code arbeiten.
|
||||||
|
Das Kommando `oow` ist dann wie gewohnt verfügbar, aber nutzt immer den aktuellen Stand deines Codes.
|
||||||
|
|
||||||
|
**Hinweis:**
|
||||||
|
Falls du vorher schon eine pipx-Installation hattest, führe vorher aus:
|
||||||
|
```bash
|
||||||
|
pipx uninstall odoo-openupgrade-wizard
|
||||||
|
```
|
||||||
|
|
||||||
|
Danach kannst du Änderungen im Arbeitsverzeichnis machen und direkt testen!
|
||||||
|
|
@ -1,3 +1,10 @@
|
||||||
|
#import debugpy
|
||||||
|
#debugpy.listen(("0.0.0.0", 5678))
|
||||||
|
#print("⏳ Warten auf Debugger-Anbindung (VS Code: Python: Remote Attach)...")
|
||||||
|
#debugpy.wait_for_client()
|
||||||
|
#print("✅ Debugger verbunden!")
|
||||||
|
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
|
|
@ -24,6 +31,7 @@ from odoo_openupgrade_wizard.cli.cli_generate_module_analysis import (
|
||||||
generate_module_analysis,
|
generate_module_analysis,
|
||||||
)
|
)
|
||||||
from odoo_openupgrade_wizard.cli.cli_get_code import get_code
|
from odoo_openupgrade_wizard.cli.cli_get_code import get_code
|
||||||
|
from odoo_openupgrade_wizard.cli.cli_guess_requirement import guess_requirement
|
||||||
from odoo_openupgrade_wizard.cli.cli_init import init
|
from odoo_openupgrade_wizard.cli.cli_init import init
|
||||||
from odoo_openupgrade_wizard.cli.cli_install_from_csv import install_from_csv
|
from odoo_openupgrade_wizard.cli.cli_install_from_csv import install_from_csv
|
||||||
from odoo_openupgrade_wizard.cli.cli_psql import psql
|
from odoo_openupgrade_wizard.cli.cli_psql import psql
|
||||||
|
|
@ -48,9 +56,9 @@ DEFAULT_MODULES_FILE = "modules.csv"
|
||||||
writable=True,
|
writable=True,
|
||||||
resolve_path=True,
|
resolve_path=True,
|
||||||
),
|
),
|
||||||
help="Folder that will contains all the configuration of the wizard"
|
help="Directory that will contain all the configuration of the wizard "
|
||||||
" and all the Odoo code required to make the migrations. Let empty to"
|
"and all the Odoo code required to perform the migrations. Leave "
|
||||||
" use current folder (./).",
|
"empty to use current directory (./).",
|
||||||
)
|
)
|
||||||
@click.option(
|
@click.option(
|
||||||
"-c",
|
"-c",
|
||||||
|
|
@ -61,7 +69,7 @@ DEFAULT_MODULES_FILE = "modules.csv"
|
||||||
),
|
),
|
||||||
help=(
|
help=(
|
||||||
f"Configuration file to use. By default, a file named "
|
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(
|
@click.option(
|
||||||
|
|
@ -72,7 +80,7 @@ DEFAULT_MODULES_FILE = "modules.csv"
|
||||||
),
|
),
|
||||||
help=(
|
help=(
|
||||||
f"Modules file to use. By default, a file named "
|
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(
|
@click.option(
|
||||||
|
|
@ -80,22 +88,28 @@ DEFAULT_MODULES_FILE = "modules.csv"
|
||||||
type=click.Path(
|
type=click.Path(
|
||||||
exists=True, file_okay=False, writable=True, resolve_path=True
|
exists=True, file_okay=False, writable=True, resolve_path=True
|
||||||
),
|
),
|
||||||
help="Folder that contains the Odoo filestore of the database(s)"
|
help="Directory that contains the Odoo filestore of the database(s) to "
|
||||||
" to migrate. Let empty to use the subfolder 'filestore' of the"
|
"migrate. Leave empty to use the subdirectory 'filestore' of the "
|
||||||
" environment folder.",
|
"environment directory.",
|
||||||
)
|
)
|
||||||
@click.option("-l", "--log-level", type=LogLevel(), default=logging.INFO)
|
@click.option("-l", "--log-level", type=LogLevel(), default=logging.INFO)
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def main(
|
def main(
|
||||||
ctx, env_folder, config_file, modules_file, filestore_folder, log_level
|
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()
|
date_begin = datetime.datetime.now()
|
||||||
logger.remove()
|
logger.remove()
|
||||||
logger.add(sys.stderr, level=log_level)
|
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):
|
if not isinstance(ctx.obj, dict):
|
||||||
ctx.obj = {}
|
ctx.obj = {}
|
||||||
|
|
||||||
|
|
@ -110,16 +124,6 @@ def main(
|
||||||
script_folder_path = env_folder_path / Path("./scripts/")
|
script_folder_path = env_folder_path / Path("./scripts/")
|
||||||
log_folder_path = env_folder_path / Path("./log/")
|
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:
|
if config_file:
|
||||||
config_file_path = Path(config_file)
|
config_file_path = Path(config_file)
|
||||||
else:
|
else:
|
||||||
|
|
@ -130,24 +134,38 @@ def main(
|
||||||
else:
|
else:
|
||||||
module_file_path = env_folder_path / Path(DEFAULT_MODULES_FILE)
|
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
|
# Add all global values in the context
|
||||||
ctx.obj["env_folder_path"] = env_folder_path
|
ctx.obj["env_folder_path"] = env_folder_path
|
||||||
ctx.obj["src_folder_path"] = src_folder_path
|
ctx.obj["src_folder_path"] = src_folder_path
|
||||||
ctx.obj["filestore_folder_path"] = filestore_folder_path
|
ctx.obj["filestore_folder_path"] = filestore_folder_path
|
||||||
ctx.obj["script_folder_path"] = script_folder_path
|
ctx.obj["script_folder_path"] = script_folder_path
|
||||||
ctx.obj["log_folder_path"] = log_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["config_file_path"] = config_file_path
|
||||||
ctx.obj["module_file_path"] = module_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(copydb)
|
||||||
main.add_command(restoredb)
|
main.add_command(restoredb)
|
||||||
|
|
@ -158,6 +176,7 @@ main.add_command(estimate_workload)
|
||||||
main.add_command(execute_script_python)
|
main.add_command(execute_script_python)
|
||||||
main.add_command(execute_script_sql)
|
main.add_command(execute_script_sql)
|
||||||
main.add_command(generate_module_analysis)
|
main.add_command(generate_module_analysis)
|
||||||
|
main.add_command(guess_requirement)
|
||||||
main.add_command(get_code)
|
main.add_command(get_code)
|
||||||
main.add_command(init)
|
main.add_command(init)
|
||||||
main.add_command(install_from_csv)
|
main.add_command(install_from_csv)
|
||||||
|
|
|
||||||
|
|
@ -10,17 +10,20 @@ from odoo_openupgrade_wizard.tools import (
|
||||||
"-s",
|
"-s",
|
||||||
"--source",
|
"--source",
|
||||||
type=str,
|
type=str,
|
||||||
help="Name of the database to copy",
|
help="Name of the source database to copy.",
|
||||||
)
|
)
|
||||||
@click.option(
|
@click.option(
|
||||||
"-d",
|
"-d",
|
||||||
"--dest",
|
"--dest",
|
||||||
type=str,
|
type=str,
|
||||||
help="Name of the new database",
|
help="Name of the destination database to create.",
|
||||||
)
|
)
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def copydb(ctx, source, dest):
|
def copydb(ctx, source, dest):
|
||||||
"""Create an Odoo database by copying an existing one.
|
"""Create a new Odoo database by copying another.
|
||||||
it will copy the postgres database and the filestore.
|
|
||||||
|
This command duplicates both the PostgreSQL database and its associated
|
||||||
|
filestore.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
click_odoo_contrib.copydb(ctx, source, dest)
|
click_odoo_contrib.copydb(ctx, source, dest)
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,16 @@ from odoo_openupgrade_wizard.tools.tools_system import get_local_user_id
|
||||||
@versions_options
|
@versions_options
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def docker_build(ctx, versions):
|
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
|
# Pull DB image
|
||||||
logger.info(
|
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"])
|
pull_image(ctx.obj["config"]["postgres_image_name"])
|
||||||
|
|
||||||
|
|
@ -32,16 +37,16 @@ def docker_build(ctx, versions):
|
||||||
)
|
)
|
||||||
if not odoo_requirement_file_path.exists():
|
if not odoo_requirement_file_path.exists():
|
||||||
logger.error(
|
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. "
|
"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_version=odoo_version,
|
||||||
odoo_requirement_file_path=odoo_requirement_file_path,
|
odoo_requirement_file_path=odoo_requirement_file_path,
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
logger.info(
|
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..."
|
" This can take a while..."
|
||||||
)
|
)
|
||||||
image = build_image(
|
image = build_image(
|
||||||
|
|
|
||||||
|
|
@ -17,33 +17,34 @@ from odoo_openupgrade_wizard.tools.tools_system import dump_filestore
|
||||||
"--database-path",
|
"--database-path",
|
||||||
type=click.Path(writable=True, resolve_path=True),
|
type=click.Path(writable=True, resolve_path=True),
|
||||||
required=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(
|
@click.option(
|
||||||
"--database-format",
|
"--database-format",
|
||||||
type=click.Choice(("p", "c", "d", "t")),
|
type=click.Choice(("p", "c", "d", "t")),
|
||||||
default="c",
|
default="c",
|
||||||
help="Database format (see pg_dump options): plain sql text (p), "
|
help="Database format (see pg_dump options): plain SQL (p), "
|
||||||
"custom format compressed (c), directory (d), tar file (t).",
|
"custom format compressed (c), directory (d), or tar file (t).",
|
||||||
)
|
)
|
||||||
@click.option(
|
@click.option(
|
||||||
"--filestore-path",
|
"--filestore-path",
|
||||||
type=click.Path(writable=True, resolve_path=True),
|
type=click.Path(writable=True, resolve_path=True),
|
||||||
required=True,
|
required=True,
|
||||||
help="Path to the filestore backup.",
|
help="Destination path for the filestore backup.",
|
||||||
)
|
)
|
||||||
@click.option(
|
@click.option(
|
||||||
"--filestore-format",
|
"--filestore-format",
|
||||||
type=click.Choice(("d", "t", "tgz")),
|
type=click.Choice(("d", "t", "tgz")),
|
||||||
default="tgz",
|
default="tgz",
|
||||||
help="Filestore format: directory (d), tar file (t), "
|
help="Filestore format: directory (d), tar file (t), "
|
||||||
"tar file compressed with gzip (tgz)",
|
"or tar file compressed with gzip (tgz)",
|
||||||
)
|
)
|
||||||
@click.option(
|
@click.option(
|
||||||
"--force",
|
"--force",
|
||||||
is_flag=True,
|
is_flag=True,
|
||||||
default=False,
|
default=False,
|
||||||
help="Overwrite file if they already exists.",
|
help="Overwrite files if they already exist.",
|
||||||
)
|
)
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def dumpdb(
|
def dumpdb(
|
||||||
|
|
@ -55,7 +56,14 @@ def dumpdb(
|
||||||
filestore_format,
|
filestore_format,
|
||||||
force,
|
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)
|
database_path = pathlib.Path(database_path)
|
||||||
filestore_path = pathlib.Path(filestore_path)
|
filestore_path = pathlib.Path(filestore_path)
|
||||||
|
|
||||||
|
|
@ -67,7 +75,7 @@ def dumpdb(
|
||||||
):
|
):
|
||||||
ctx.fail(
|
ctx.fail(
|
||||||
"database-path should be inside the project path to allow "
|
"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
|
# Fail if dumps already exists and force argument not given
|
||||||
|
|
|
||||||
|
|
@ -17,35 +17,43 @@ from odoo_openupgrade_wizard.tools.tools_system import (
|
||||||
dir_okay=False,
|
dir_okay=False,
|
||||||
),
|
),
|
||||||
default="./analysis.html",
|
default="./analysis.html",
|
||||||
|
help="Path where the HTML analysis report will be saved. "
|
||||||
|
"Default is './analysis.html'",
|
||||||
)
|
)
|
||||||
@click.option(
|
@click.option(
|
||||||
"--extra-modules",
|
"--extra-modules",
|
||||||
"extra_modules_list",
|
"extra_modules_list",
|
||||||
# TODO, add a callback to check the quality of the argument
|
# TODO, add a callback to check the quality of the argument
|
||||||
help="Coma separated modules to analyse. If not set, the modules.csv"
|
help="Comma-separated list of modules to analyze. If not set, "
|
||||||
" file will be used to define the list of module to analyse."
|
"modules.csv will be used. Example: 'account,product,base'.",
|
||||||
"Ex: 'account,product,base'",
|
|
||||||
)
|
)
|
||||||
@click.option(
|
@click.option(
|
||||||
"--time-unit",
|
"--time-unit",
|
||||||
type=click.Choice(["hour", "minute", "separator"]),
|
type=click.Choice(["hour", "minute", "separator"]),
|
||||||
default="separator",
|
default="separator",
|
||||||
show_default=True,
|
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 `HHH<sep>MM`, "
|
"*separator* display time as `HHH<sep>MM`, "
|
||||||
"*hour* display time as decimal hour, "
|
"*hour* display time as decimal hour, "
|
||||||
"*min* display time as minute (rounded).",
|
"*min* display time as minutes (rounded).",
|
||||||
)
|
)
|
||||||
@click.option(
|
@click.option(
|
||||||
"--time-separator",
|
"--time-separator",
|
||||||
default=":",
|
default=":",
|
||||||
help="Specify time separator, if time-unit is separator. "
|
help="Character to use as a separator in time output. "
|
||||||
"Default to `:` (it will produce time like this HHH:MM).",
|
"Used only if --time-unit=separator. Default is ':' (e.g. HHH:MM).",
|
||||||
)
|
)
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def estimate_workload(
|
def estimate_workload(
|
||||||
ctx, analysis_file_path, extra_modules_list, time_unit, time_separator
|
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
|
# Analyse
|
||||||
analysis = Analysis(ctx)
|
analysis = Analysis(ctx)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,11 +22,29 @@ from odoo_openupgrade_wizard.tools.tools_odoo import (
|
||||||
exists=True,
|
exists=True,
|
||||||
dir_okay=False,
|
dir_okay=False,
|
||||||
),
|
),
|
||||||
help="List of python files that will be executed, replacing the default"
|
help="""List of Python files to execute, with either an absolute path
|
||||||
" scripts placed in the migration step folder.",
|
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
|
@click.pass_context
|
||||||
def execute_script_python(ctx, step, database, script_file_path):
|
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)
|
migration_step = get_migration_step_from_options(ctx, step)
|
||||||
|
|
||||||
execute_click_odoo_python_files(
|
execute_click_odoo_python_files(
|
||||||
|
|
|
||||||
|
|
@ -22,11 +22,21 @@ from odoo_openupgrade_wizard.tools.tools_postgres import (
|
||||||
exists=True,
|
exists=True,
|
||||||
dir_okay=False,
|
dir_okay=False,
|
||||||
),
|
),
|
||||||
help="List of SQL files that will be executed, replacing the default"
|
help="List of SQL files to execute. Files will be executed in the order "
|
||||||
" scripts placed in the migration step folder.",
|
"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
|
@click.pass_context
|
||||||
def execute_script_sql(ctx, step, database, script_file_path):
|
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)
|
migration_step = get_migration_step_from_options(ctx, step)
|
||||||
|
|
||||||
execute_sql_files_pre_migration(
|
execute_sql_files_pre_migration(
|
||||||
|
|
|
||||||
|
|
@ -28,11 +28,24 @@ from odoo_openupgrade_wizard.tools.tools_system import ensure_folder_writable
|
||||||
"-m",
|
"-m",
|
||||||
"--modules",
|
"--modules",
|
||||||
type=str,
|
type=str,
|
||||||
help="Coma-separated list of modules to analysis."
|
help="Comma-separated list of modules to analyse."
|
||||||
" Let empty to analyse all the Odoo modules.",
|
" Leave empty to analyse all the Odoo modules.",
|
||||||
)
|
)
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def generate_module_analysis(ctx, step, database, modules):
|
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)
|
migration_steps = get_migration_steps_from_options(ctx, step - 1, step)
|
||||||
|
|
||||||
initial_step = migration_steps[0].copy()
|
initial_step = migration_steps[0].copy()
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,15 @@ from odoo_openupgrade_wizard.tools.tools_system import git_aggregate
|
||||||
type=int,
|
type=int,
|
||||||
default=10,
|
default=10,
|
||||||
help="Jobs used to call the git-aggregate command."
|
help="Jobs used to call the git-aggregate command."
|
||||||
" reasonably set to 10 by default.",
|
" Reasonably set to 10 by default.",
|
||||||
)
|
)
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def get_code(ctx, versions, jobs):
|
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):
|
for odoo_version in get_odoo_versions_from_options(ctx, versions):
|
||||||
folder_path = get_odoo_env_path(ctx, odoo_version)
|
folder_path = get_odoo_env_path(ctx, odoo_version)
|
||||||
|
|
|
||||||
61
odoo_openupgrade_wizard/cli/cli_guess_requirement.py
Normal file
61
odoo_openupgrade_wizard/cli/cli_guess_requirement.py
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
from odoo_openupgrade_wizard.tools.tools_odoo import (
|
||||||
|
get_odoo_env_path,
|
||||||
|
get_odoo_modules_from_csv,
|
||||||
|
)
|
||||||
|
from odoo_openupgrade_wizard.tools.tools_odoo_module import Analysis
|
||||||
|
from odoo_openupgrade_wizard.tools.tools_system import (
|
||||||
|
ensure_file_exists_from_template,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command()
|
||||||
|
@click.option(
|
||||||
|
"--extra-modules",
|
||||||
|
"extra_modules_list",
|
||||||
|
# TODO, add a callback to check the quality of the argument
|
||||||
|
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)
|
||||||
|
|
||||||
|
if extra_modules_list:
|
||||||
|
module_list = extra_modules_list.split(",")
|
||||||
|
else:
|
||||||
|
module_list = get_odoo_modules_from_csv(ctx.obj["module_file_path"])
|
||||||
|
|
||||||
|
analysis.analyse_module_version(ctx, module_list)
|
||||||
|
analysis.analyse_missing_module()
|
||||||
|
result = analysis.get_requirements(ctx)
|
||||||
|
|
||||||
|
for odoo_version in [x for x in ctx.obj["config"]["odoo_versions"]]:
|
||||||
|
path_version = get_odoo_env_path(ctx, odoo_version)
|
||||||
|
ensure_file_exists_from_template(
|
||||||
|
path_version / Path("addons_python_requirements.txt"),
|
||||||
|
"odoo/addons_python_requirements.txt.j2",
|
||||||
|
dependencies=result[odoo_version]["python"],
|
||||||
|
)
|
||||||
|
|
||||||
|
ensure_file_exists_from_template(
|
||||||
|
path_version / Path("addons_debian_requirements.txt"),
|
||||||
|
"odoo/addons_debian_requirements.txt.j2",
|
||||||
|
dependencies=result[odoo_version]["bin"],
|
||||||
|
)
|
||||||
|
|
@ -19,42 +19,44 @@ from odoo_openupgrade_wizard.tools.tools_system import (
|
||||||
required=True,
|
required=True,
|
||||||
prompt=True,
|
prompt=True,
|
||||||
type=str,
|
type=str,
|
||||||
help="Name of your project without spaces neither special"
|
help="Name of your project without spaces, special"
|
||||||
" chars or uppercases. exemple 'my-customer-9-12'."
|
" characters, or uppercases. Example: 'my-customer-9-12'."
|
||||||
" This will be used to tag with a friendly"
|
" This will be used to tag the Odoo Docker images "
|
||||||
" name the odoo docker images.",
|
" with a friendly name.",
|
||||||
)
|
)
|
||||||
@click.option(
|
@click.option(
|
||||||
"--initial-version",
|
"--initial-version",
|
||||||
required=True,
|
required=True,
|
||||||
prompt=True,
|
prompt=True,
|
||||||
type=click.Choice(get_version_options("initial")),
|
type=click.Choice(get_version_options("initial")),
|
||||||
|
help="Initial Odoo version to migrate from.",
|
||||||
)
|
)
|
||||||
@click.option(
|
@click.option(
|
||||||
"--final-version",
|
"--final-version",
|
||||||
required=True,
|
required=True,
|
||||||
prompt=True,
|
prompt=True,
|
||||||
type=click.Choice(get_version_options("final")),
|
type=click.Choice(get_version_options("final")),
|
||||||
|
help="Target Odoo version to migrate to.",
|
||||||
)
|
)
|
||||||
@click.option(
|
@click.option(
|
||||||
"--postgresql-version",
|
"--postgresql-version",
|
||||||
required=True,
|
required=True,
|
||||||
prompt=True,
|
prompt=True,
|
||||||
help="The version of postgresql that will be used"
|
help="""The version of PostgreSQL that will be used
|
||||||
" to create the postgresql container.Ex : '9.1', '16', ..."
|
to create the PostgreSQL container. Example: '9.1', '16', etc.
|
||||||
" The version should be available in docker hub."
|
The version should be available in Docker hub.
|
||||||
" (https://hub.docker.com/_/postgres)"
|
(https://hub.docker.com/_/postgres)
|
||||||
" avoid the 'latest' version if you want a deterministic installation."
|
Avoid the 'latest' version if you want a deterministic installation.
|
||||||
" Key Point: If your current production server uses Postgresql version A"
|
Key Point: If your current production server uses PostgreSQL version A
|
||||||
" and if your future production server usees Postgresql version B,"
|
and your future production server will use PostgreSQL version B,
|
||||||
" you should select here a version X, with A <= X <= B.",
|
you should select here a version X, with A <= X <= B.""",
|
||||||
)
|
)
|
||||||
@click.option(
|
@click.option(
|
||||||
"--extra-repository",
|
"--extra-repository",
|
||||||
"extra_repository_list",
|
"extra_repository_list",
|
||||||
# TODO, add a callback to check the quality of the argument
|
# TODO, add a callback to check the quality of the argument
|
||||||
help="Coma separated extra repositories to use in the odoo environment."
|
help="Comma-separated extra repositories to use in the Odoo environment."
|
||||||
"Ex: 'OCA/web,OCA/server-tools,GRAP/grap-odoo-incubator'",
|
"Example: 'OCA/web,OCA/server-tools,GRAP/grap-odoo-incubator'",
|
||||||
)
|
)
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def init(
|
def init(
|
||||||
|
|
@ -65,8 +67,10 @@ def init(
|
||||||
postgresql_version,
|
postgresql_version,
|
||||||
extra_repository_list,
|
extra_repository_list,
|
||||||
):
|
):
|
||||||
"""Initialize OOW Environment based on the initial and
|
"""Initialize the OOW project environment.
|
||||||
the final version of Odoo you want to migrate.
|
|
||||||
|
This command sets up the project folder structure, configuration
|
||||||
|
files, and default templates needed to begin an Odoo migration.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Handle arguments
|
# Handle arguments
|
||||||
|
|
@ -152,18 +156,30 @@ def init(
|
||||||
path_version = get_odoo_env_path(ctx, odoo_version)
|
path_version = get_odoo_env_path(ctx, odoo_version)
|
||||||
ensure_folder_exists(path_version)
|
ensure_folder_exists(path_version)
|
||||||
|
|
||||||
# Create python requirements file
|
# Create python requirements files
|
||||||
ensure_file_exists_from_template(
|
ensure_file_exists_from_template(
|
||||||
path_version / Path("extra_python_requirements.txt"),
|
path_version / Path("extra_python_requirements.txt"),
|
||||||
"odoo/extra_python_requirements.txt.j2",
|
"odoo/extra_python_requirements.txt.j2",
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create debian requirements file
|
ensure_file_exists_from_template(
|
||||||
|
path_version / Path("addons_python_requirements.txt"),
|
||||||
|
"odoo/addons_python_requirements.txt.j2",
|
||||||
|
dependencies={},
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create debian requirements files
|
||||||
ensure_file_exists_from_template(
|
ensure_file_exists_from_template(
|
||||||
path_version / Path("extra_debian_requirements.txt"),
|
path_version / Path("extra_debian_requirements.txt"),
|
||||||
"odoo/extra_debian_requirements.txt.j2",
|
"odoo/extra_debian_requirements.txt.j2",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ensure_file_exists_from_template(
|
||||||
|
path_version / Path("addons_debian_requirements.txt"),
|
||||||
|
"odoo/addons_debian_requirements.txt.j2",
|
||||||
|
dependencies={},
|
||||||
|
)
|
||||||
|
|
||||||
# Create odoo config file
|
# Create odoo config file
|
||||||
ensure_file_exists_from_template(
|
ensure_file_exists_from_template(
|
||||||
path_version / Path("odoo.conf"),
|
path_version / Path("odoo.conf"),
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,12 @@ from odoo_openupgrade_wizard.tools.tools_postgres import ensure_database
|
||||||
@demo_option
|
@demo_option
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def install_from_csv(ctx, database, with_demo):
|
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)
|
migration_step = get_migration_step_from_options(ctx, 1)
|
||||||
ensure_database(ctx, database, state="present")
|
ensure_database(ctx, database, state="present")
|
||||||
|
|
||||||
|
|
@ -30,7 +36,7 @@ def install_from_csv(ctx, database, with_demo):
|
||||||
logger.debug(module_names)
|
logger.debug(module_names)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
logger.info(f"Install 'base' module on {database} database ...")
|
logger.info(f"Install 'base' module on {database} database...")
|
||||||
run_odoo(
|
run_odoo(
|
||||||
ctx,
|
ctx,
|
||||||
migration_step,
|
migration_step,
|
||||||
|
|
@ -58,7 +64,7 @@ def install_from_csv(ctx, database, with_demo):
|
||||||
raise Exception(
|
raise Exception(
|
||||||
f"Unable to find a country, based on the"
|
f"Unable to find a country, based on the"
|
||||||
f" code {odoo_default_company['country_code']}."
|
f" code {odoo_default_company['country_code']}."
|
||||||
f" Countries found :"
|
f" Countries found:"
|
||||||
f" {', '.join([x.name for x in countries])}"
|
f" {', '.join([x.name for x in countries])}"
|
||||||
)
|
)
|
||||||
vals = {
|
vals = {
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,8 @@ def versions_options(function):
|
||||||
"-v",
|
"-v",
|
||||||
"--versions",
|
"--versions",
|
||||||
type=str,
|
type=str,
|
||||||
help="Coma-separated values of odoo versions for which"
|
help="Comma-separated Odoo versions to target. Leave empty to "
|
||||||
" you want to perform the operation."
|
"perform the operation on all versions in the project",
|
||||||
" Let empty to perform the operation on all the versions"
|
|
||||||
" of the project",
|
|
||||||
)(function)
|
)(function)
|
||||||
return function
|
return function
|
||||||
|
|
||||||
|
|
@ -30,7 +28,7 @@ def first_step_option(function):
|
||||||
function = click.option(
|
function = click.option(
|
||||||
"--first-step",
|
"--first-step",
|
||||||
type=int,
|
type=int,
|
||||||
help="First step for which to perform the operation",
|
help="First step to include in the operation.",
|
||||||
)(function)
|
)(function)
|
||||||
return function
|
return function
|
||||||
|
|
||||||
|
|
@ -39,7 +37,7 @@ def last_step_option(function):
|
||||||
function = click.option(
|
function = click.option(
|
||||||
"--last-step",
|
"--last-step",
|
||||||
type=int,
|
type=int,
|
||||||
help="Last step for which to perform the operation",
|
help="Last step to include in the operation.",
|
||||||
)(function)
|
)(function)
|
||||||
return function
|
return function
|
||||||
|
|
||||||
|
|
@ -48,7 +46,7 @@ def demo_option(function):
|
||||||
function = click.option(
|
function = click.option(
|
||||||
"--with-demo/--without-demo",
|
"--with-demo/--without-demo",
|
||||||
default=False,
|
default=False,
|
||||||
help="Create database with or without demo data.",
|
help="Whether to include demo data when creating the database.",
|
||||||
)(function)
|
)(function)
|
||||||
return function
|
return function
|
||||||
|
|
||||||
|
|
@ -59,8 +57,9 @@ def database_option_required(function):
|
||||||
"--database",
|
"--database",
|
||||||
required=True,
|
required=True,
|
||||||
prompt=True,
|
prompt=True,
|
||||||
|
default="postgres",
|
||||||
type=str,
|
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)
|
)(function)
|
||||||
return function
|
return function
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,14 +6,29 @@ from odoo_openupgrade_wizard.tools.tools_postgres import execute_psql_command
|
||||||
|
|
||||||
@click.command(context_settings={"ignore_unknown_options": True})
|
@click.command(context_settings={"ignore_unknown_options": True})
|
||||||
@database_option_required
|
@database_option_required
|
||||||
@click.option("-c", "--command", "request")
|
@click.option(
|
||||||
@click.option("--pager/--no-pager", default=True)
|
"-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.argument("psql_args", nargs=-1, type=click.UNPROCESSED)
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def psql(ctx, request, database, pager, psql_args):
|
def psql(ctx, request, database, pager, psql_args):
|
||||||
"""Run psql in the postgres container. Fill any parameters of psql
|
"""Run a SQL command in the PostgreSQL container.
|
||||||
as PSQLARGS.
|
|
||||||
|
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)
|
result = execute_psql_command(ctx, request, database, psql_args)
|
||||||
if pager:
|
if pager:
|
||||||
click.echo_via_pager(result)
|
click.echo_via_pager(result)
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,12 @@ from odoo_openupgrade_wizard.tools.tools_system import execute_check_output
|
||||||
@versions_options
|
@versions_options
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def pull_submodule(ctx, versions):
|
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):
|
for odoo_version in get_odoo_versions_from_options(ctx, versions):
|
||||||
version_cfg = (
|
version_cfg = (
|
||||||
ctx.obj["config"]["odoo_version_settings"][odoo_version] or {}
|
ctx.obj["config"]["odoo_version_settings"][odoo_version] or {}
|
||||||
|
|
@ -22,7 +26,7 @@ def pull_submodule(ctx, versions):
|
||||||
if version_cfg.get("repo_url"):
|
if version_cfg.get("repo_url"):
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Pull repos.yml from git repository"
|
f"Pull repos.yml from git repository"
|
||||||
f" for version {odoo_version} ..."
|
f" for version {odoo_version}..."
|
||||||
)
|
)
|
||||||
submodule_path = (
|
submodule_path = (
|
||||||
get_odoo_env_path(ctx, odoo_version) / "repo_submodule"
|
get_odoo_env_path(ctx, odoo_version) / "repo_submodule"
|
||||||
|
|
@ -53,5 +57,5 @@ def pull_submodule(ctx, versions):
|
||||||
else:
|
else:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
f"No submodule configuration found"
|
f"No submodule configuration found"
|
||||||
f" for version {odoo_version} ..."
|
f" for version {odoo_version}..."
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -12,31 +12,30 @@ from odoo_openupgrade_wizard.tools.tools_system import restore_filestore
|
||||||
@click.option(
|
@click.option(
|
||||||
"--database-path",
|
"--database-path",
|
||||||
required=True,
|
required=True,
|
||||||
type=click.Path(readable=True, resolve_path=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(
|
@click.option(
|
||||||
"--database-format",
|
"--database-format",
|
||||||
required=True,
|
required=True,
|
||||||
type=click.Choice(("c", "d", "t", "p")),
|
type=click.Choice(("c", "d", "t", "p")),
|
||||||
default="c",
|
default="c",
|
||||||
help="Database format (see pg_dump options): "
|
help="Format of the database dump: custom (c), directory (d), tar (t), "
|
||||||
"custom format compressed (c), directory (d), tar file (t),"
|
"or plain SQL (p).",
|
||||||
" plain sql text (p).",
|
|
||||||
)
|
)
|
||||||
@click.option(
|
@click.option(
|
||||||
"--filestore-path",
|
"--filestore-path",
|
||||||
required=True,
|
required=True,
|
||||||
type=click.Path(readable=True, resolve_path=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(
|
@click.option(
|
||||||
"--filestore-format",
|
"--filestore-format",
|
||||||
required=True,
|
required=True,
|
||||||
type=click.Choice(("d", "t", "tgz")),
|
type=click.Choice(("d", "t", "tgz")),
|
||||||
default="tgz",
|
default="tgz",
|
||||||
help="Filestore format: directory (d), tar file (t), "
|
help="Format of the filestore: directory (d), tar (t), or gzip-compressed "
|
||||||
"tar file compressed with gzip (tgz)",
|
"tar (tgz).",
|
||||||
)
|
)
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def restoredb(
|
def restoredb(
|
||||||
|
|
@ -47,7 +46,13 @@ def restoredb(
|
||||||
filestore_path,
|
filestore_path,
|
||||||
filestore_format,
|
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)
|
database_path = Path(database_path)
|
||||||
filestore_path = Path(filestore_path)
|
filestore_path = Path(filestore_path)
|
||||||
|
|
@ -57,8 +62,9 @@ def restoredb(
|
||||||
if not str(database_path).startswith(str(absolute_env_folder_path)):
|
if not str(database_path).startswith(str(absolute_env_folder_path)):
|
||||||
ctx.fail(
|
ctx.fail(
|
||||||
"database-path should be inside the project path to allow "
|
"database-path should be inside the project path to allow "
|
||||||
"postgresql to read to it."
|
"PostgreSQL to read it."
|
||||||
)
|
)
|
||||||
|
|
||||||
# Restore the database
|
# Restore the database
|
||||||
output = execute_pg_restore(
|
output = execute_pg_restore(
|
||||||
ctx,
|
ctx,
|
||||||
|
|
|
||||||
|
|
@ -27,13 +27,13 @@ from odoo_openupgrade_wizard.tools.tools_postgres import ensure_database
|
||||||
"-i",
|
"-i",
|
||||||
"--init-modules",
|
"--init-modules",
|
||||||
type=str,
|
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(
|
@click.option(
|
||||||
"-u",
|
"-u",
|
||||||
"--update-modules",
|
"--update-modules",
|
||||||
type=str,
|
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(
|
@click.option(
|
||||||
"-e",
|
"-e",
|
||||||
|
|
@ -41,7 +41,7 @@ from odoo_openupgrade_wizard.tools.tools_postgres import ensure_database
|
||||||
type=click.Choice(["regular", "openupgrade"]),
|
type=click.Choice(["regular", "openupgrade"]),
|
||||||
help="Force to use an openupgrade (OCA/openupgrade)"
|
help="Force to use an openupgrade (OCA/openupgrade)"
|
||||||
" or a regular (odoo/odoo or OCA/OCB) base code when running odoo."
|
" 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
|
@click.pass_context
|
||||||
def run(
|
def run(
|
||||||
|
|
@ -54,6 +54,14 @@ def run(
|
||||||
update_modules,
|
update_modules,
|
||||||
execution_context,
|
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)
|
migration_step = get_migration_step_from_options(ctx, step)
|
||||||
ensure_database(ctx, database, state="present")
|
ensure_database(ctx, database, state="present")
|
||||||
try:
|
try:
|
||||||
|
|
@ -74,7 +82,7 @@ def run(
|
||||||
"Odoo is available on your host at http://localhost:"
|
"Odoo is available on your host at http://localhost:"
|
||||||
f"{ctx.obj['config']['odoo_host_xmlrpc_port']}"
|
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):
|
except (KeyboardInterrupt, SystemExit):
|
||||||
logger.info("Received Keyboard Interrupt or System Exiting...")
|
logger.info("Received Keyboard Interrupt or System Exiting...")
|
||||||
finally:
|
finally:
|
||||||
|
|
|
||||||
|
|
@ -25,23 +25,45 @@ from odoo_openupgrade_wizard.tools.tools_postgres import (
|
||||||
@demo_option
|
@demo_option
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def upgrade(ctx, first_step, last_step, database, with_demo):
|
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(
|
migration_steps = get_migration_steps_from_options(
|
||||||
ctx, first_step, last_step
|
ctx, first_step, last_step
|
||||||
)
|
)
|
||||||
for migration_step in migration_steps:
|
for migration_step in migration_steps:
|
||||||
execute_sql_files_pre_migration(ctx, database, migration_step)
|
execute_sql_files_pre_migration(ctx, database, migration_step)
|
||||||
try:
|
if migration_step.get("update", True):
|
||||||
run_odoo(
|
try:
|
||||||
ctx,
|
run_odoo(
|
||||||
migration_step,
|
ctx,
|
||||||
database=database,
|
migration_step,
|
||||||
detached_container=False,
|
database=database,
|
||||||
update="all",
|
detached_container=False,
|
||||||
stop_after_init=True,
|
update="all",
|
||||||
demo=with_demo,
|
stop_after_init=True,
|
||||||
|
demo=with_demo,
|
||||||
|
)
|
||||||
|
except (KeyboardInterrupt, SystemExit):
|
||||||
|
logger.info("Received Keyboard Interrupt or System Exiting...")
|
||||||
|
finally:
|
||||||
|
kill_odoo(ctx, database, migration_step)
|
||||||
|
elif migration_step.get("execution_context") == "openupgrade":
|
||||||
|
raise ValueError(
|
||||||
|
"Incorrect setting 'update: True'"
|
||||||
|
" and 'execution_context: openupgrade'"
|
||||||
)
|
)
|
||||||
except (KeyboardInterrupt, SystemExit):
|
else:
|
||||||
logger.info("Received Keyboard Interrupt or System Exiting...")
|
logger.info(
|
||||||
finally:
|
"Skip update=all for"
|
||||||
kill_odoo(ctx, database, migration_step)
|
f" step {migration_step.get('complete_name')}"
|
||||||
|
)
|
||||||
|
|
||||||
execute_click_odoo_python_files(ctx, database, migration_step)
|
execute_click_odoo_python_files(ctx, database, migration_step)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,15 @@ from pathlib import Path
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
_ALL_ODOO_VERSIONS = [8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0]
|
FIRST_ODOO_VERSION_SUPPORTED = 8
|
||||||
|
LAST_ODOO_VERSION_SUPPORTED = 18
|
||||||
|
|
||||||
|
_ALL_ODOO_VERSIONS = [
|
||||||
|
float(x)
|
||||||
|
for x in range(
|
||||||
|
FIRST_ODOO_VERSION_SUPPORTED, LAST_ODOO_VERSION_SUPPORTED + 1
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def get_version_options(mode: str) -> list:
|
def get_version_options(mode: str) -> list:
|
||||||
|
|
@ -43,7 +51,7 @@ def get_odoo_run_command(migration_step: dict) -> str:
|
||||||
|
|
||||||
|
|
||||||
def get_odoo_folder(
|
def get_odoo_folder(
|
||||||
migration_step: dict, execution_context: str = False
|
migration_step: dict, execution_context: str = None
|
||||||
) -> str:
|
) -> str:
|
||||||
"""return the main odoo folder, depending on the migration step.
|
"""return the main odoo folder, depending on the migration step.
|
||||||
(./src/odoo, ./src/openupgrade, ...)"""
|
(./src/odoo, ./src/openupgrade, ...)"""
|
||||||
|
|
@ -92,7 +100,7 @@ def skip_addon_path(migration_step: dict, path: Path) -> bool:
|
||||||
|
|
||||||
|
|
||||||
def get_server_wide_modules_upgrade(
|
def get_server_wide_modules_upgrade(
|
||||||
migration_step: dict, execution_context: str = False
|
migration_step: dict, execution_context: str = None
|
||||||
) -> list:
|
) -> list:
|
||||||
"""return a list of modules to load, depending on the migration step."""
|
"""return a list of modules to load, depending on the migration step."""
|
||||||
if (
|
if (
|
||||||
|
|
@ -117,8 +125,8 @@ def get_upgrade_analysis_module(migration_step: dict) -> str:
|
||||||
|
|
||||||
def generate_records(odoo_instance, migration_step: dict):
|
def generate_records(odoo_instance, migration_step: dict):
|
||||||
logger.info(
|
logger.info(
|
||||||
"Generate Records in version %s ..."
|
"Generate Records in version %s..."
|
||||||
" (It can take a while)" % (migration_step["version"])
|
" (This may take a while)" % (migration_step["version"])
|
||||||
)
|
)
|
||||||
if migration_step["version"] < 14.0:
|
if migration_step["version"] < 14.0:
|
||||||
wizard = odoo_instance.browse_by_create(
|
wizard = odoo_instance.browse_by_create(
|
||||||
|
|
@ -157,7 +165,7 @@ def generate_analysis_files(
|
||||||
):
|
):
|
||||||
logger.info(
|
logger.info(
|
||||||
"Generate analysis files for"
|
"Generate analysis files for"
|
||||||
" the modules installed on %s ..." % (initial_database)
|
" the modules installed on %s..." % (initial_database)
|
||||||
)
|
)
|
||||||
proxy_vals = {
|
proxy_vals = {
|
||||||
"name": "Proxy to Previous version",
|
"name": "Proxy to Previous version",
|
||||||
|
|
@ -168,12 +176,12 @@ def generate_analysis_files(
|
||||||
"password": "admin",
|
"password": "admin",
|
||||||
}
|
}
|
||||||
if final_step["version"] < 14.0:
|
if final_step["version"] < 14.0:
|
||||||
logger.info("> Create proxy ...")
|
logger.info("> Create proxy...")
|
||||||
proxy = final_odoo_instance.browse_by_create(
|
proxy = final_odoo_instance.browse_by_create(
|
||||||
"openupgrade.comparison.config", proxy_vals
|
"openupgrade.comparison.config", proxy_vals
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.info("> Create wizard ...")
|
logger.info("> Create wizard...")
|
||||||
wizard = final_odoo_instance.browse_by_create(
|
wizard = final_odoo_instance.browse_by_create(
|
||||||
"openupgrade.analysis.wizard",
|
"openupgrade.analysis.wizard",
|
||||||
{
|
{
|
||||||
|
|
@ -181,16 +189,16 @@ def generate_analysis_files(
|
||||||
"write_files": True,
|
"write_files": True,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
logger.info("> Launch analysis. This can take a while ...")
|
logger.info("> Launch analysis. This can take a while...")
|
||||||
wizard.get_communication()
|
wizard.get_communication()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.info("> Create proxy ...")
|
logger.info("> Create proxy...")
|
||||||
proxy = final_odoo_instance.browse_by_create(
|
proxy = final_odoo_instance.browse_by_create(
|
||||||
"upgrade.comparison.config", proxy_vals
|
"upgrade.comparison.config", proxy_vals
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.info("> Create wizard ...")
|
logger.info("> Create wizard...")
|
||||||
analysis = final_odoo_instance.browse_by_create(
|
analysis = final_odoo_instance.browse_by_create(
|
||||||
"upgrade.analysis",
|
"upgrade.analysis",
|
||||||
{
|
{
|
||||||
|
|
@ -198,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()
|
analysis.analyze()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -259,6 +267,6 @@ def get_openupgrade_analysis_files(
|
||||||
module_name = file.parent.parent.name
|
module_name = file.parent.parent.name
|
||||||
result[module_name] = file
|
result[module_name] = file
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"Version %s : %d analysis files found." % (version, len(result))
|
"Version %s: %d analysis files found." % (version, len(result))
|
||||||
)
|
)
|
||||||
return result
|
return result
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,23 @@
|
||||||
<html>
|
<html>
|
||||||
|
<head>
|
||||||
|
<script>
|
||||||
|
function ShowAll(){
|
||||||
|
var elements = document.getElementsByClassName('work_done');
|
||||||
|
|
||||||
|
for (var i = 0; i < elements.length; i ++) {
|
||||||
|
elements[i].style.display = 'table-row';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function HideWorkDone(){
|
||||||
|
var elements = document.getElementsByClassName('work_done');
|
||||||
|
|
||||||
|
for (var i = 0; i < elements.length; i ++) {
|
||||||
|
elements[i].style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Migration Analysis</h1>
|
<h1>Migration Analysis</h1>
|
||||||
<table border="1" width="100%">
|
<table border="1" width="100%">
|
||||||
|
|
@ -18,6 +37,14 @@
|
||||||
<td>{{ current_date }}</td>
|
<td>{{ current_date }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td colspan="4" style="text-align: center;">
|
||||||
|
<a href="#" onclick="ShowAll()">Show All Modules</a>
|
||||||
|
<a href="#" onclick="HideWorkDone()">Hide Done Modules</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<h2>Summary</h2>
|
<h2>Summary</h2>
|
||||||
|
|
@ -33,29 +60,31 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td>Odoo</td>
|
<td>Odoo</td>
|
||||||
<td>{{ analysis.get_module_qty('odoo') }}</td>
|
<td>{{ analysis.get_module_qty('odoo') }}</td>
|
||||||
<td>{{ analysis.workload_hour_text('odoo') }}</td>
|
<td>{{ time_to_text(analysis.workload('odoo', False)) }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>OCA</td>
|
<td>OCA</td>
|
||||||
<td>{{ analysis.get_module_qty('oca') }}</td>
|
<td>{{ analysis.get_module_qty('oca') }}</td>
|
||||||
<td>{{ analysis.workload_hour_text('oca') }}</td>
|
<td>{{ time_to_text(analysis.workload('oca', False)) }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Custom</td>
|
<td>Custom</td>
|
||||||
<td>{{ analysis.get_module_qty('custom') }}</td>
|
<td>{{ analysis.get_module_qty('custom') }}</td>
|
||||||
<td>{{ analysis.workload_hour_text('custom') }}</td>
|
<td>{{ time_to_text(analysis.workload('custom', False)) }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
{%- if analysis.get_module_qty('not_found') -%}
|
||||||
<tr>
|
<tr>
|
||||||
<td>Not Found</td>
|
<td>Not Found</td>
|
||||||
<td>{{ analysis.get_module_qty('not_found') }}</td>
|
<td>{{ analysis.get_module_qty('not_found') }}</td>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
</tr>
|
</tr>
|
||||||
|
{%- endif -%}
|
||||||
</tbody>
|
</tbody>
|
||||||
<tfood>
|
<tfood>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Total</th>
|
<th>Total</th>
|
||||||
<td>{{ analysis.get_module_qty() }}</td>
|
<td>{{ analysis.get_module_qty() }}</td>
|
||||||
<td>{{ analysis.workload_hour_text() }}</td>
|
<td>{{ time_to_text(analysis.workload(False, False)) }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tfood>
|
</tfood>
|
||||||
</table>
|
</table>
|
||||||
|
|
@ -66,116 +95,100 @@
|
||||||
<tr>
|
<tr>
|
||||||
<th> </th>
|
<th> </th>
|
||||||
<th>Total</th>
|
<th>Total</th>
|
||||||
{%- for odoo_version in ctx.obj['config']['odoo_versions'] -%}
|
{%- for odoo_version in ctx.obj['config']['odoo_versions'] %}
|
||||||
<th>{{ odoo_version }}</th>
|
<th>{{ odoo_version }}</th>
|
||||||
{% endfor %}
|
{%- endfor %}
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody>
|
<tbody>
|
||||||
{% set ns = namespace(
|
{%- set ns = namespace(current_repository='', current_module_type='') %}
|
||||||
current_repository='',
|
|
||||||
current_module_type='',
|
|
||||||
) %}
|
|
||||||
{% for odoo_module in analysis.modules %}
|
|
||||||
|
|
||||||
<!-- ---------------------- -->
|
{%- for odoo_module in analysis.modules %}
|
||||||
<!-- Handle New Module Type -->
|
{%- if (ns.current_module_type != odoo_module.module_type) %}
|
||||||
<!-- ---------------------- -->
|
{%- set ns.current_module_type = odoo_module.module_type %}
|
||||||
|
|
||||||
{% if (
|
<!-- ------------------------------------------------ -->
|
||||||
ns.current_module_type != odoo_module.module_type
|
<!-- Handle New Module Type {{ns.current_module_type}}-->
|
||||||
and odoo_module.module_type != 'odoo') %}
|
<!-- ------------------------------------------------ -->
|
||||||
{% set ns.current_module_type = odoo_module.module_type %}
|
|
||||||
<tr>
|
<tr>
|
||||||
<th colspan="{{2 + ctx.obj['config']['odoo_versions']|length}}">
|
<th colspan="{{2 + ctx.obj['config']['odoo_versions']|length}}">
|
||||||
{{ ns.current_module_type}}
|
<h3>{{ odoo_module.module_type}}</h3>
|
||||||
</th>
|
</th>
|
||||||
<tr>
|
<tr>
|
||||||
{% endif %}
|
{%- endif %}
|
||||||
|
|
||||||
<!-- -------------------- -->
|
{%- if ns.current_repository != odoo_module.repository %}
|
||||||
<!-- Handle New Repository-->
|
{%- set ns.current_repository = odoo_module.repository %}
|
||||||
<!-- -------------------- -->
|
{%- set repository_workload = analysis.workload(False, odoo_module.repository) %}
|
||||||
|
|
||||||
{% if ns.current_repository != odoo_module.repository %}
|
<!-- ---------------------------------------------- -->
|
||||||
{% set ns.current_repository = odoo_module.repository %}
|
<!-- Handle New Repository {{ns.current_repository}}-->
|
||||||
|
<!-- ---------------------------------------------- -->
|
||||||
|
|
||||||
{% if ns.current_repository %}
|
{%- if ns.current_repository %}
|
||||||
<tr>
|
<tr class="{{repository_workload == 0 and 'work_done' or ''}}">
|
||||||
<th colspan="{{2 + ctx.obj['config']['odoo_versions']|length}}">
|
<th colspan="{{2 + ctx.obj['config']['odoo_versions']|length}}">
|
||||||
{{ ns.current_repository}}
|
<h4>{{ odoo_module.repository}}
|
||||||
|
{% if repository_workload %}
|
||||||
|
({{ time_to_text(repository_workload) }})
|
||||||
|
{% endif %}
|
||||||
|
</h4>
|
||||||
</th>
|
</th>
|
||||||
<tr>
|
<tr>
|
||||||
{% endif %}
|
{%- endif %}
|
||||||
{% endif %}
|
{%- endif %}
|
||||||
|
|
||||||
<!-- -------------------- -->
|
<tr class="{{odoo_module.workload == 0 and 'work_done' or ''}}">
|
||||||
<!-- Display Module Line -->
|
|
||||||
<!-- -------------------- -->
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>{{odoo_module.name}}
|
<td>{{odoo_module.name}}
|
||||||
{% if odoo_module.module_type == 'not_found' %}
|
{%- if odoo_module.module_type == 'not_found' -%}
|
||||||
{% set odoo_apps_url = odoo_module.get_odoo_apps_url() %}
|
{%- set odoo_apps_url = odoo_module.get_odoo_apps_url() -%}
|
||||||
{% if odoo_apps_url %}
|
{%- if odoo_apps_url -%}
|
||||||
<a href="{{odoo_apps_url}}" target="_blank">AppsStore</a>
|
<a href="{{odoo_apps_url}}" target="_blank">AppsStore</a>
|
||||||
{% else %}
|
{%- else -%}
|
||||||
{% set odoo_code_search_url = odoo_module.get_odoo_code_search_url() %}
|
{%- set odoo_code_search_url = odoo_module.get_odoo_code_search_url() -%}
|
||||||
{% if odoo_code_search_url %}
|
{%- if odoo_code_search_url -%}
|
||||||
<a href="{{odoo_code_search_url}}" target="_blank">
|
<a href="{{odoo_code_search_url}}" target="_blank">OdooCodeSearch</a>
|
||||||
OdooCodeSearch
|
{%- endif -%}
|
||||||
</a>
|
{%- endif -%}
|
||||||
{% endif %}
|
{%- endif -%}
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
{% if odoo_module.workload %}
|
{%- if odoo_module.workload -%}
|
||||||
{{time_to_text(odoo_module.workload)}}
|
{{time_to_text(odoo_module.workload)}}
|
||||||
{% endif %}
|
{%- endif -%}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
{% for version in odoo_module.analyse.all_versions %}
|
{%- for version in odoo_module.analyse.all_versions %}
|
||||||
{% set module_version = odoo_module.get_module_version(version) %}
|
{%- set module_version = odoo_module.get_module_version(version) %}
|
||||||
{% if module_version %}
|
{%- if module_version %}
|
||||||
{% set size_text = module_version.get_size_text() %}
|
{%- set size_text = module_version.get_size_text() %}
|
||||||
{% set analysis_text = module_version.get_analysis_text() %}
|
{%- set analysis_text = module_version.get_analysis_text() %}
|
||||||
{% set workload = module_version.workload %}
|
{%- set workload = module_version.workload %}
|
||||||
|
|
||||||
<td style="background-color:{{module_version.get_bg_color()}};">
|
<td style="background-color:{{module_version.get_bg_color()}};">
|
||||||
{{module_version.get_text()}}
|
{{module_version.get_text()}}
|
||||||
|
|
||||||
{% if workload %}
|
{%- if workload -%}
|
||||||
<span style="background-color:lightblue;">
|
<span style="background-color:lightblue;">({{time_to_text(workload)}})</span>
|
||||||
({{time_to_text(workload)}})
|
{%- endif -%}
|
||||||
</span>
|
{%- if size_text -%}
|
||||||
{% endif %}
|
<br/>
|
||||||
{% if size_text %}
|
<span style="color:gray;font-size:11px;font-family:monospace;">({{ size_text}})</span>
|
||||||
<br/>
|
{%- endif -%}
|
||||||
<span style="color:gray;font-size:11px;font-family:monospace;">
|
{%- if analysis_text -%}
|
||||||
({{ size_text}})
|
<br/>
|
||||||
</span>
|
<span style="color:gray;font-size:11px;font-family:monospace;">
|
||||||
{% endif %}
|
<a href="{{module_version.analysis_url()}}" target="_blank">({{ analysis_text}})</a>
|
||||||
{% if analysis_text %}
|
</span>
|
||||||
<br/>
|
{%- endif %}
|
||||||
<span style="color:gray;font-size:11px;font-family:monospace;">
|
|
||||||
<a href="{{module_version.analysis_url()}}" target="_blank">
|
|
||||||
({{ analysis_text}})
|
|
||||||
</a>
|
|
||||||
</span>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
{% else %}
|
{%- else %}
|
||||||
<td style="background-color:gray;"> </td>
|
<td style="background-color:gray;"> </td>
|
||||||
{% endif %}
|
{%- endif %}
|
||||||
{% endfor %}
|
{%- endfor %}
|
||||||
</tr>
|
</tr>
|
||||||
|
{%- endfor %}
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,9 @@ migration_steps:
|
||||||
version: {{ step['version'] }}
|
version: {{ step['version'] }}
|
||||||
execution_context: {{ step['execution_context'] }}
|
execution_context: {{ step['execution_context'] }}
|
||||||
complete_name: {{ step['complete_name'] }}
|
complete_name: {{ step['complete_name'] }}
|
||||||
|
{%- if step['execution_context'] == 'regular'%}
|
||||||
|
update: True
|
||||||
|
{%- endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
workload_settings:
|
workload_settings:
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ RUN apt-get update && \
|
||||||
RUN dpkg-reconfigure locales && \
|
RUN dpkg-reconfigure locales && \
|
||||||
locale-gen C.UTF-8 && \
|
locale-gen C.UTF-8 && \
|
||||||
/usr/sbin/update-locale LANG=C.UTF-8
|
/usr/sbin/update-locale LANG=C.UTF-8
|
||||||
ENV LC_ALL C.UTF-8
|
ENV LC_ALL=C.UTF-8
|
||||||
|
|
||||||
RUN apt-get update -qq && \
|
RUN apt-get update -qq && \
|
||||||
apt-get upgrade -qq -y && \
|
apt-get upgrade -qq -y && \
|
||||||
|
|
@ -39,18 +39,22 @@ RUN apt-get update -qq && \
|
||||||
|
|
||||||
# <OOW> Install Debian packages
|
# <OOW> Install Debian packages
|
||||||
COPY extra_debian_requirements.txt /extra_debian_requirements.txt
|
COPY extra_debian_requirements.txt /extra_debian_requirements.txt
|
||||||
|
COPY addons_debian_requirements.txt /addons_debian_requirements.txt
|
||||||
RUN apt-get update -qq \
|
RUN apt-get update -qq \
|
||||||
&& apt-get install -y git \
|
&& apt-get install -y git \
|
||||||
&& xargs apt-get install -y --no-install-recommends <extra_debian_requirements.txt \
|
&& grep -vE '^\s*#|^\s*$' extra_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
|
||||||
|
&& grep -vE '^\s*#|^\s*$' addons_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# <OOW> Install Python librairies
|
# <OOW> Install Python librairies
|
||||||
COPY ./src/odoo/requirements.txt /odoo_python_requirements.txt
|
COPY ./src/odoo/requirements.txt /odoo_python_requirements.txt
|
||||||
|
COPY addons_python_requirements.txt /addons_python_requirements.txt
|
||||||
COPY extra_python_requirements.txt /extra_python_requirements.txt
|
COPY extra_python_requirements.txt /extra_python_requirements.txt
|
||||||
RUN pip3 install --upgrade pip \
|
RUN pip3 install --upgrade pip \
|
||||||
&& python3 -m pip install --no-cache-dir setuptools-scm \
|
&& python3 -m pip install --no-cache-dir setuptools-scm \
|
||||||
&& python3 -m pip install --no-cache-dir -r /odoo_python_requirements.txt \
|
&& python3 -m pip install --no-cache-dir -r /odoo_python_requirements.txt \
|
||||||
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt
|
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt \
|
||||||
|
&& python3 -m pip install --no-cache-dir -r /addons_python_requirements.txt
|
||||||
|
|
||||||
# <OOW> Get local user id and set it to the odoo user
|
# <OOW> Get local user id and set it to the odoo user
|
||||||
ARG LOCAL_USER_ID
|
ARG LOCAL_USER_ID
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ RUN apt-get update && \
|
||||||
RUN dpkg-reconfigure locales && \
|
RUN dpkg-reconfigure locales && \
|
||||||
locale-gen C.UTF-8 && \
|
locale-gen C.UTF-8 && \
|
||||||
/usr/sbin/update-locale LANG=C.UTF-8
|
/usr/sbin/update-locale LANG=C.UTF-8
|
||||||
ENV LC_ALL C.UTF-8
|
ENV LC_ALL=C.UTF-8
|
||||||
|
|
||||||
RUN apt-get update -qq && \
|
RUN apt-get update -qq && \
|
||||||
apt-get upgrade -qq -y && \
|
apt-get upgrade -qq -y && \
|
||||||
|
|
@ -39,18 +39,22 @@ RUN apt-get update -qq && \
|
||||||
|
|
||||||
# <OOW> Install Debian packages
|
# <OOW> Install Debian packages
|
||||||
COPY extra_debian_requirements.txt /extra_debian_requirements.txt
|
COPY extra_debian_requirements.txt /extra_debian_requirements.txt
|
||||||
|
COPY addons_debian_requirements.txt /addons_debian_requirements.txt
|
||||||
RUN apt-get update -qq \
|
RUN apt-get update -qq \
|
||||||
&& apt-get install -y git \
|
&& apt-get install -y git \
|
||||||
&& xargs apt-get install -y --no-install-recommends <extra_debian_requirements.txt \
|
&& grep -vE '^\s*#|^\s*$' extra_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
|
||||||
|
&& grep -vE '^\s*#|^\s*$' addons_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# <OOW> Install Python librairies
|
# <OOW> Install Python librairies
|
||||||
COPY ./src/odoo/requirements.txt /odoo_python_requirements.txt
|
COPY ./src/odoo/requirements.txt /odoo_python_requirements.txt
|
||||||
|
COPY addons_python_requirements.txt /addons_python_requirements.txt
|
||||||
COPY extra_python_requirements.txt /extra_python_requirements.txt
|
COPY extra_python_requirements.txt /extra_python_requirements.txt
|
||||||
RUN pip3 install --upgrade pip \
|
RUN pip3 install --upgrade pip \
|
||||||
&& python3 -m pip install --no-cache-dir setuptools-scm \
|
&& python3 -m pip install --no-cache-dir setuptools-scm \
|
||||||
&& python3 -m pip install --no-cache-dir -r /odoo_python_requirements.txt \
|
&& python3 -m pip install --no-cache-dir -r /odoo_python_requirements.txt \
|
||||||
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt
|
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt \
|
||||||
|
&& python3 -m pip install --no-cache-dir -r /addons_python_requirements.txt
|
||||||
|
|
||||||
# <OOW> Get local user id and set it to the odoo user
|
# <OOW> Get local user id and set it to the odoo user
|
||||||
ARG LOCAL_USER_ID
|
ARG LOCAL_USER_ID
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
# <OOW> : Copy of https://github.com/odoo/odoo/blob/13.0/setup/package.dfsrc
|
# <OOW> : Copy of https://github.com/odoo/odoo/blob/13.0/setup/package.dfsrc
|
||||||
FROM debian:buster
|
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 && \
|
RUN apt-get update && \
|
||||||
apt-get install -y locales && \
|
apt-get install -y locales && \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
@ -9,7 +12,7 @@ RUN apt-get update && \
|
||||||
RUN dpkg-reconfigure locales && \
|
RUN dpkg-reconfigure locales && \
|
||||||
locale-gen C.UTF-8 && \
|
locale-gen C.UTF-8 && \
|
||||||
/usr/sbin/update-locale LANG=C.UTF-8
|
/usr/sbin/update-locale LANG=C.UTF-8
|
||||||
ENV LC_ALL C.UTF-8
|
ENV LC_ALL=C.UTF-8
|
||||||
|
|
||||||
RUN apt-get update -qq && \
|
RUN apt-get update -qq && \
|
||||||
apt-get upgrade -qq -y && \
|
apt-get upgrade -qq -y && \
|
||||||
|
|
@ -35,18 +38,22 @@ RUN apt-get update -qq && \
|
||||||
|
|
||||||
# <OOW> Install Debian packages
|
# <OOW> Install Debian packages
|
||||||
COPY extra_debian_requirements.txt /extra_debian_requirements.txt
|
COPY extra_debian_requirements.txt /extra_debian_requirements.txt
|
||||||
|
COPY addons_debian_requirements.txt /addons_debian_requirements.txt
|
||||||
RUN apt-get update -qq \
|
RUN apt-get update -qq \
|
||||||
&& apt-get install -y git \
|
&& apt-get install -y git \
|
||||||
&& xargs apt-get install -y --no-install-recommends <extra_debian_requirements.txt \
|
&& grep -vE '^\s*#|^\s*$' extra_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
|
||||||
|
&& grep -vE '^\s*#|^\s*$' addons_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# <OOW> Install Python librairies
|
# <OOW> Install Python librairies
|
||||||
COPY ./src/odoo/requirements.txt /odoo_python_requirements.txt
|
COPY ./src/odoo/requirements.txt /odoo_python_requirements.txt
|
||||||
|
COPY addons_python_requirements.txt /addons_python_requirements.txt
|
||||||
COPY extra_python_requirements.txt /extra_python_requirements.txt
|
COPY extra_python_requirements.txt /extra_python_requirements.txt
|
||||||
RUN pip3 install --upgrade pip \
|
RUN pip3 install --upgrade pip \
|
||||||
&& python3 -m pip install --no-cache-dir setuptools-scm \
|
&& python3 -m pip install --no-cache-dir setuptools-scm \
|
||||||
&& python3 -m pip install --no-cache-dir -r /odoo_python_requirements.txt \
|
&& python3 -m pip install --no-cache-dir -r /odoo_python_requirements.txt \
|
||||||
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt
|
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt \
|
||||||
|
&& python3 -m pip install --no-cache-dir -r /addons_python_requirements.txt
|
||||||
|
|
||||||
# <OOW> Get local user id and set it to the odoo user
|
# <OOW> Get local user id and set it to the odoo user
|
||||||
ARG LOCAL_USER_ID
|
ARG LOCAL_USER_ID
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
# <OOW> : Copy of https://github.com/odoo/odoo/blob/14.0/setup/package.dfsrc
|
# <OOW> : Copy of https://github.com/odoo/odoo/blob/14.0/setup/package.dfsrc
|
||||||
FROM debian:buster
|
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 && \
|
RUN apt-get update && \
|
||||||
apt-get install -y locales && \
|
apt-get install -y locales && \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
@ -9,7 +12,7 @@ RUN apt-get update && \
|
||||||
RUN dpkg-reconfigure locales && \
|
RUN dpkg-reconfigure locales && \
|
||||||
locale-gen C.UTF-8 && \
|
locale-gen C.UTF-8 && \
|
||||||
/usr/sbin/update-locale LANG=C.UTF-8
|
/usr/sbin/update-locale LANG=C.UTF-8
|
||||||
ENV LC_ALL C.UTF-8
|
ENV LC_ALL=C.UTF-8
|
||||||
|
|
||||||
RUN apt-get update -qq && \
|
RUN apt-get update -qq && \
|
||||||
apt-get upgrade -qq -y && \
|
apt-get upgrade -qq -y && \
|
||||||
|
|
@ -28,18 +31,22 @@ RUN apt-get update -qq && \
|
||||||
|
|
||||||
# <OOW> Install Debian packages
|
# <OOW> Install Debian packages
|
||||||
COPY extra_debian_requirements.txt /extra_debian_requirements.txt
|
COPY extra_debian_requirements.txt /extra_debian_requirements.txt
|
||||||
|
COPY addons_debian_requirements.txt /addons_debian_requirements.txt
|
||||||
RUN apt-get update -qq \
|
RUN apt-get update -qq \
|
||||||
&& apt-get install -y git \
|
&& apt-get install -y git \
|
||||||
&& xargs apt-get install -y --no-install-recommends <extra_debian_requirements.txt \
|
&& grep -vE '^\s*#|^\s*$' extra_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
|
||||||
|
&& grep -vE '^\s*#|^\s*$' addons_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# <OOW> Install Python librairies
|
# <OOW> Install Python librairies
|
||||||
COPY ./src/odoo/requirements.txt /odoo_python_requirements.txt
|
COPY ./src/odoo/requirements.txt /odoo_python_requirements.txt
|
||||||
|
COPY addons_python_requirements.txt /addons_python_requirements.txt
|
||||||
COPY extra_python_requirements.txt /extra_python_requirements.txt
|
COPY extra_python_requirements.txt /extra_python_requirements.txt
|
||||||
RUN pip3 install --upgrade pip \
|
RUN pip3 install --upgrade pip \
|
||||||
&& python3 -m pip install --no-cache-dir setuptools-scm \
|
&& python3 -m pip install --no-cache-dir setuptools-scm \
|
||||||
&& python3 -m pip install --no-cache-dir -r /odoo_python_requirements.txt \
|
&& python3 -m pip install --no-cache-dir -r /odoo_python_requirements.txt \
|
||||||
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt
|
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt \
|
||||||
|
&& python3 -m pip install --no-cache-dir -r /addons_python_requirements.txt
|
||||||
|
|
||||||
# <OOW> Get local user id and set it to the odoo user
|
# <OOW> Get local user id and set it to the odoo user
|
||||||
ARG LOCAL_USER_ID
|
ARG LOCAL_USER_ID
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
# <OOW> : Copy of https://github.com/odoo/odoo/blob/15.0/setup/package.dfsrc
|
# <OOW> : Copy of https://github.com/odoo/odoo/blob/15.0/setup/package.dfsrc
|
||||||
FROM debian:buster
|
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 && \
|
RUN apt-get update && \
|
||||||
apt-get install -y locales && \
|
apt-get install -y locales && \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
@ -9,7 +12,7 @@ RUN apt-get update && \
|
||||||
RUN dpkg-reconfigure locales && \
|
RUN dpkg-reconfigure locales && \
|
||||||
locale-gen C.UTF-8 && \
|
locale-gen C.UTF-8 && \
|
||||||
/usr/sbin/update-locale LANG=C.UTF-8
|
/usr/sbin/update-locale LANG=C.UTF-8
|
||||||
ENV LC_ALL C.UTF-8
|
ENV LC_ALL=C.UTF-8
|
||||||
|
|
||||||
RUN apt-get update -qq && \
|
RUN apt-get update -qq && \
|
||||||
apt-get upgrade -qq -y && \
|
apt-get upgrade -qq -y && \
|
||||||
|
|
@ -28,18 +31,22 @@ RUN apt-get update -qq && \
|
||||||
|
|
||||||
# <OOW> Install Debian packages
|
# <OOW> Install Debian packages
|
||||||
COPY extra_debian_requirements.txt /extra_debian_requirements.txt
|
COPY extra_debian_requirements.txt /extra_debian_requirements.txt
|
||||||
|
COPY addons_debian_requirements.txt /addons_debian_requirements.txt
|
||||||
RUN apt-get update -qq \
|
RUN apt-get update -qq \
|
||||||
&& apt-get install -y git \
|
&& apt-get install -y git \
|
||||||
&& xargs apt-get install -y --no-install-recommends <extra_debian_requirements.txt \
|
&& grep -vE '^\s*#|^\s*$' extra_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
|
||||||
|
&& grep -vE '^\s*#|^\s*$' addons_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# <OOW> Install Python librairies
|
# <OOW> Install Python librairies
|
||||||
COPY ./src/odoo/requirements.txt /odoo_python_requirements.txt
|
COPY ./src/odoo/requirements.txt /odoo_python_requirements.txt
|
||||||
|
COPY addons_python_requirements.txt /addons_python_requirements.txt
|
||||||
COPY extra_python_requirements.txt /extra_python_requirements.txt
|
COPY extra_python_requirements.txt /extra_python_requirements.txt
|
||||||
RUN pip3 install --upgrade pip \
|
RUN pip3 install --upgrade pip \
|
||||||
&& python3 -m pip install --no-cache-dir setuptools-scm \
|
&& python3 -m pip install --no-cache-dir setuptools-scm \
|
||||||
&& python3 -m pip install --no-cache-dir -r /odoo_python_requirements.txt \
|
&& python3 -m pip install --no-cache-dir -r /odoo_python_requirements.txt \
|
||||||
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt
|
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt \
|
||||||
|
&& python3 -m pip install --no-cache-dir -r /addons_python_requirements.txt
|
||||||
|
|
||||||
# <OOW> Get local user id and set it to the odoo user
|
# <OOW> Get local user id and set it to the odoo user
|
||||||
ARG LOCAL_USER_ID
|
ARG LOCAL_USER_ID
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
# <OOW> : Copy of https://github.com/odoo/odoo/blob/16.0/setup/package.dfsrc
|
# <OOW> : Copy of https://github.com/odoo/odoo/blob/16.0/setup/package.dfsrc
|
||||||
FROM debian:buster
|
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 && \
|
RUN apt-get update && \
|
||||||
apt-get install -y locales && \
|
apt-get install -y locales && \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
@ -9,7 +12,7 @@ RUN apt-get update && \
|
||||||
RUN dpkg-reconfigure locales && \
|
RUN dpkg-reconfigure locales && \
|
||||||
locale-gen C.UTF-8 && \
|
locale-gen C.UTF-8 && \
|
||||||
/usr/sbin/update-locale LANG=C.UTF-8
|
/usr/sbin/update-locale LANG=C.UTF-8
|
||||||
ENV LC_ALL C.UTF-8
|
ENV LC_ALL=C.UTF-8
|
||||||
|
|
||||||
RUN apt-get update -qq && \
|
RUN apt-get update -qq && \
|
||||||
apt-get upgrade -qq -y && \
|
apt-get upgrade -qq -y && \
|
||||||
|
|
@ -28,18 +31,22 @@ RUN apt-get update -qq && \
|
||||||
|
|
||||||
# <OOW> Install Debian packages
|
# <OOW> Install Debian packages
|
||||||
COPY extra_debian_requirements.txt /extra_debian_requirements.txt
|
COPY extra_debian_requirements.txt /extra_debian_requirements.txt
|
||||||
|
COPY addons_debian_requirements.txt /addons_debian_requirements.txt
|
||||||
RUN apt-get update -qq \
|
RUN apt-get update -qq \
|
||||||
&& apt-get install -y git \
|
&& apt-get install -y git \
|
||||||
&& xargs apt-get install -y --no-install-recommends <extra_debian_requirements.txt \
|
&& grep -vE '^\s*#|^\s*$' extra_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
|
||||||
|
&& grep -vE '^\s*#|^\s*$' addons_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# <OOW> Install Python librairies
|
# <OOW> Install Python librairies
|
||||||
COPY ./src/odoo/requirements.txt /odoo_python_requirements.txt
|
COPY ./src/odoo/requirements.txt /odoo_python_requirements.txt
|
||||||
|
COPY addons_python_requirements.txt /addons_python_requirements.txt
|
||||||
COPY extra_python_requirements.txt /extra_python_requirements.txt
|
COPY extra_python_requirements.txt /extra_python_requirements.txt
|
||||||
RUN pip3 install --upgrade pip \
|
RUN pip3 install --upgrade pip \
|
||||||
&& python3 -m pip install --no-cache-dir setuptools-scm \
|
&& python3 -m pip install --no-cache-dir setuptools-scm \
|
||||||
&& python3 -m pip install --no-cache-dir -r /odoo_python_requirements.txt \
|
&& python3 -m pip install --no-cache-dir -r /odoo_python_requirements.txt \
|
||||||
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt
|
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt \
|
||||||
|
&& python3 -m pip install --no-cache-dir -r /addons_python_requirements.txt
|
||||||
|
|
||||||
# <OOW> Get local user id and set it to the odoo user
|
# <OOW> Get local user id and set it to the odoo user
|
||||||
ARG LOCAL_USER_ID
|
ARG LOCAL_USER_ID
|
||||||
|
|
|
||||||
54
odoo_openupgrade_wizard/templates/odoo/17.0/Dockerfile
Normal file
54
odoo_openupgrade_wizard/templates/odoo/17.0/Dockerfile
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
# <OOW> : Copy of https://github.com/odoo/odoo/blob/17.0/setup/package.dfsrc
|
||||||
|
FROM debian:bookworm
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y locales && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Reconfigure locales such that postgresql uses UTF-8 encoding
|
||||||
|
RUN dpkg-reconfigure locales && \
|
||||||
|
locale-gen C.UTF-8 && \
|
||||||
|
/usr/sbin/update-locale LANG=C.UTF-8
|
||||||
|
ENV LC_ALL=C.UTF-8
|
||||||
|
|
||||||
|
RUN apt-get update -qq && \
|
||||||
|
apt-get upgrade -qq -y && \
|
||||||
|
apt-get install \
|
||||||
|
postgresql \
|
||||||
|
postgresql-server-dev-all \
|
||||||
|
postgresql-client \
|
||||||
|
adduser \
|
||||||
|
libldap2-dev \
|
||||||
|
libsasl2-dev \
|
||||||
|
python3-pip \
|
||||||
|
python3-venv \
|
||||||
|
python3-wheel \
|
||||||
|
build-essential \
|
||||||
|
python3 -y && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# <OOW> Install Debian packages
|
||||||
|
COPY extra_debian_requirements.txt /extra_debian_requirements.txt
|
||||||
|
COPY addons_debian_requirements.txt /addons_debian_requirements.txt
|
||||||
|
RUN apt-get update -qq \
|
||||||
|
&& apt-get install -y git \
|
||||||
|
&& grep -vE '^\s*#|^\s*$' extra_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
|
||||||
|
&& grep -vE '^\s*#|^\s*$' addons_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# <OOW> Install Python librairies
|
||||||
|
COPY ./src/odoo/requirements.txt /odoo_python_requirements.txt
|
||||||
|
COPY addons_python_requirements.txt /addons_python_requirements.txt
|
||||||
|
COPY extra_python_requirements.txt /extra_python_requirements.txt
|
||||||
|
RUN pip3 install --upgrade pip --break-system-packages \
|
||||||
|
&& python3 -m pip install --no-cache-dir setuptools-scm --break-system-packages \
|
||||||
|
&& python3 -m pip install --no-cache-dir -r /odoo_python_requirements.txt --break-system-packages \
|
||||||
|
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt --break-system-packages \
|
||||||
|
&& python3 -m pip install --no-cache-dir -r /addons_python_requirements.txt --break-system-packages
|
||||||
|
|
||||||
|
# <OOW> Get local user id and set it to the odoo user
|
||||||
|
ARG LOCAL_USER_ID
|
||||||
|
|
||||||
|
RUN useradd --uid $LOCAL_USER_ID --non-unique odoo
|
||||||
|
|
||||||
|
USER odoo
|
||||||
54
odoo_openupgrade_wizard/templates/odoo/18.0/Dockerfile
Normal file
54
odoo_openupgrade_wizard/templates/odoo/18.0/Dockerfile
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
# <OOW> : Copy of https://github.com/odoo/odoo/blob/18.0/setup/package.dfsrc
|
||||||
|
FROM debian:bookworm
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y locales && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Reconfigure locales such that postgresql uses UTF-8 encoding
|
||||||
|
RUN dpkg-reconfigure locales && \
|
||||||
|
locale-gen C.UTF-8 && \
|
||||||
|
/usr/sbin/update-locale LANG=C.UTF-8
|
||||||
|
ENV LC_ALL=C.UTF-8
|
||||||
|
|
||||||
|
RUN apt-get update -qq && \
|
||||||
|
apt-get upgrade -qq -y && \
|
||||||
|
apt-get install \
|
||||||
|
postgresql \
|
||||||
|
postgresql-server-dev-all \
|
||||||
|
postgresql-client \
|
||||||
|
adduser \
|
||||||
|
libldap2-dev \
|
||||||
|
libsasl2-dev \
|
||||||
|
python3-pip \
|
||||||
|
python3-venv \
|
||||||
|
python3-wheel \
|
||||||
|
build-essential \
|
||||||
|
python3 -y && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# <OOW> Install Debian packages
|
||||||
|
COPY extra_debian_requirements.txt /extra_debian_requirements.txt
|
||||||
|
COPY addons_debian_requirements.txt /addons_debian_requirements.txt
|
||||||
|
RUN apt-get update -qq \
|
||||||
|
&& apt-get install -y git \
|
||||||
|
&& grep -vE '^\s*#|^\s*$' extra_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
|
||||||
|
&& grep -vE '^\s*#|^\s*$' addons_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# <OOW> Install Python librairies
|
||||||
|
COPY ./src/odoo/requirements.txt /odoo_python_requirements.txt
|
||||||
|
COPY addons_python_requirements.txt /addons_python_requirements.txt
|
||||||
|
COPY extra_python_requirements.txt /extra_python_requirements.txt
|
||||||
|
RUN pip3 install --upgrade pip --break-system-packages \
|
||||||
|
&& python3 -m pip install --no-cache-dir setuptools-scm --break-system-packages \
|
||||||
|
&& python3 -m pip install --no-cache-dir -r /odoo_python_requirements.txt --break-system-packages \
|
||||||
|
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt --break-system-packages \
|
||||||
|
&& python3 -m pip install --no-cache-dir -r /addons_python_requirements.txt --break-system-packages
|
||||||
|
|
||||||
|
# <OOW> Get local user id and set it to the odoo user
|
||||||
|
ARG LOCAL_USER_ID
|
||||||
|
|
||||||
|
RUN useradd --uid $LOCAL_USER_ID --non-unique odoo
|
||||||
|
|
||||||
|
USER odoo
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
# Do NOT edit manually. Changes here will be overwritten by the command 'guess-requirement'
|
||||||
|
|
||||||
|
{%- for bin_lib, module_list in dependencies.items() %}
|
||||||
|
|
||||||
|
# Required by the module(s): {{ ','.join(module_list) }}
|
||||||
|
{{ bin_lib }}
|
||||||
|
|
||||||
|
{%- endfor %}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
# Do NOT edit manually. Changes here will be overwritten by the command 'guess-requirement'
|
||||||
|
|
||||||
|
{%- for python_lib, module_list in dependencies.items() %}
|
||||||
|
|
||||||
|
# Required by the module(s): {{ ','.join(module_list) }}
|
||||||
|
{{ python_lib }}
|
||||||
|
|
||||||
|
{%- endfor %}
|
||||||
|
|
@ -7,3 +7,7 @@
|
||||||
# - http or xml port
|
# - http or xml port
|
||||||
# - etc.
|
# - etc.
|
||||||
# Only non standard or special options should be specified here.
|
# Only non standard or special options should be specified here.
|
||||||
|
|
||||||
|
[options]
|
||||||
|
# Disable default memory limit of 2560 MiB
|
||||||
|
limit_memory_hard = 0
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
_logger.info("Executing post-migration.py script ...")
|
_logger.info("Executing post-migration.py script...")
|
||||||
|
|
||||||
env = env # noqa: F821
|
env = env # noqa: F821
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ def copydb(ctx, source, dest):
|
||||||
shutil.rmtree(dest_path, ignore_errors=True)
|
shutil.rmtree(dest_path, ignore_errors=True)
|
||||||
|
|
||||||
# Copy Filestore
|
# 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)
|
shutil.copytree(source_path, dest_path)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ def pull_image(image_name):
|
||||||
def build_image(path, tag, buildargs={}):
|
def build_image(path, tag, buildargs={}):
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"Building image named based on {path}/Dockerfile."
|
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}"
|
debug_docker_command = f"docker build {path} --tag {tag}"
|
||||||
for arg_name, arg_value in buildargs.items():
|
for arg_name, arg_value in buildargs.items():
|
||||||
|
|
@ -30,11 +30,13 @@ def build_image(path, tag, buildargs={}):
|
||||||
path=str(path),
|
path=str(path),
|
||||||
tag=tag,
|
tag=tag,
|
||||||
buildargs=buildargs,
|
buildargs=buildargs,
|
||||||
|
rm=True,
|
||||||
)
|
)
|
||||||
logger.debug("Image build done.")
|
logger.debug("Image build done.")
|
||||||
except docker.errors.BuildError as buildError:
|
except docker.errors.BuildError as buildError:
|
||||||
logger.error("\n".join([str(log) for log in buildError.build_log]))
|
logger.error("\n".join([str(log) for log in buildError.build_log]))
|
||||||
logger.error("Image build failed.")
|
logger.error("Image build failed.")
|
||||||
|
raise buildError
|
||||||
|
|
||||||
return image
|
return image
|
||||||
|
|
||||||
|
|
@ -57,7 +59,7 @@ def run_container(
|
||||||
" Did you run 'odoo-openupgrade-wizard docker-build' ?"
|
" 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"
|
debug_docker_command = f"docker run --name {container_name}\\\n"
|
||||||
|
|
||||||
for k, v in ports.items():
|
for k, v in ports.items():
|
||||||
|
|
@ -104,8 +106,8 @@ def exec_container(container, command):
|
||||||
if docker_result.exit_code != 0:
|
if docker_result.exit_code != 0:
|
||||||
raise Exception(
|
raise Exception(
|
||||||
f"The command failed in the container {container.name}.\n"
|
f"The command failed in the container {container.name}.\n"
|
||||||
f"- Command : {command}\n"
|
f"- Command: {command}\n"
|
||||||
f"- Exit Code : {docker_result.exit_code}\n"
|
f"- Exit Code: {docker_result.exit_code}\n"
|
||||||
f"- Output: {docker_result.output}"
|
f"- Output: {docker_result.output}"
|
||||||
)
|
)
|
||||||
return docker_result
|
return docker_result
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ def get_odoo_addons_path(
|
||||||
ctx,
|
ctx,
|
||||||
odoo_env_path: Path,
|
odoo_env_path: Path,
|
||||||
migration_step: dict,
|
migration_step: dict,
|
||||||
execution_context: str = False,
|
execution_context: str = None,
|
||||||
) -> str:
|
) -> str:
|
||||||
"""Return
|
"""Return
|
||||||
- addons_path: a list of Path of that contains odoo module
|
- addons_path: a list of Path of that contains odoo module
|
||||||
|
|
@ -88,14 +88,33 @@ def get_odoo_addons_path(
|
||||||
|
|
||||||
|
|
||||||
def is_addons_path(ctx, path: Path, migration_step: dict):
|
def is_addons_path(ctx, path: Path, migration_step: dict):
|
||||||
|
logger.debug(f"Untersuche Pfad: {path}")
|
||||||
for folder in [x for x in path.iterdir() if x.is_dir()]:
|
for folder in [x for x in path.iterdir() if x.is_dir()]:
|
||||||
|
logger.debug(f" Untersuche Pfad: {folder}")
|
||||||
if (folder / "__init__.py").exists() and (
|
if (folder / "__init__.py").exists() and (
|
||||||
folder / get_manifest_name(migration_step)
|
folder / get_manifest_name(migration_step)
|
||||||
).exists():
|
).exists():
|
||||||
|
logger.info(f" ✔️ Odoo-Modul gefunden in: {folder}")
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
#def is_addons_path(ctx, path: Path, migration_step: dict):
|
||||||
|
# """Prüft, ob im Verzeichnis mindestens ein Odoo-Modul liegt."""
|
||||||
|
# logger.debug(f"Untersuche Pfad: {path}")
|
||||||
|
# for folder in path.iterdir():
|
||||||
|
# if folder.is_dir():
|
||||||
|
# init_exists = (folder / "__init__.py").exists()
|
||||||
|
# manifest_path = folder / get_manifest_name(migration_step)
|
||||||
|
# manifest_exists = manifest_path.exists()
|
||||||
|
# logger.debug(
|
||||||
|
# f" Untersuche Unterordner: {folder} | __init__.py: {init_exists}, Manifest: {manifest_path.name}: {manifest_exists}"
|
||||||
|
# )
|
||||||
|
# if init_exists and manifest_exists:
|
||||||
|
# logger.info(f" ✔️ Odoo-Modul gefunden in: {folder}")
|
||||||
|
# return True
|
||||||
|
# return False
|
||||||
|
|
||||||
def get_odoo_env_path(ctx, odoo_version: float) -> Path:
|
def get_odoo_env_path(ctx, odoo_version: float) -> Path:
|
||||||
folder_name = "env_%s" % str(odoo_version).rjust(4, "0")
|
folder_name = "env_%s" % str(odoo_version).rjust(4, "0")
|
||||||
return ctx.obj["src_folder_path"] / folder_name
|
return ctx.obj["src_folder_path"] / folder_name
|
||||||
|
|
@ -121,22 +140,22 @@ def get_docker_container_name(ctx, database: str, migration_step: dict) -> str:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def generate_odoo_command(
|
def generate_odoo_command_options(
|
||||||
ctx,
|
ctx,
|
||||||
migration_step: dict,
|
migration_step: dict,
|
||||||
execution_context: str,
|
execution_context: str,
|
||||||
database: str,
|
database: str,
|
||||||
demo: bool = False,
|
demo: bool = False,
|
||||||
update: str = False,
|
update: str = None,
|
||||||
init: str = False,
|
init: str = None,
|
||||||
stop_after_init: bool = False,
|
stop_after_init: bool = False,
|
||||||
shell: bool = False,
|
) -> list:
|
||||||
) -> str:
|
"""
|
||||||
|
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"])
|
odoo_env_path = get_odoo_env_path(ctx, migration_step["version"])
|
||||||
|
|
||||||
# Compute 'server_wide_modules'
|
# Compute 'server_wide_modules'
|
||||||
# For that purpose, read the custom odoo.conf file
|
|
||||||
# to know if server_wide_modules is defined
|
|
||||||
custom_odoo_config_file = odoo_env_path / "odoo.conf"
|
custom_odoo_config_file = odoo_env_path / "odoo.conf"
|
||||||
parser = configparser.RawConfigParser()
|
parser = configparser.RawConfigParser()
|
||||||
parser.read(custom_odoo_config_file)
|
parser.read(custom_odoo_config_file)
|
||||||
|
|
@ -147,10 +166,22 @@ def generate_odoo_command(
|
||||||
migration_step, execution_context
|
migration_step, execution_context
|
||||||
)
|
)
|
||||||
|
|
||||||
# compute 'addons_path'
|
# Compute 'addons_path'
|
||||||
addons_path_list, empty_addons_path_list = get_odoo_addons_path(
|
addons_path_list, empty_addons_path_list = get_odoo_addons_path(
|
||||||
ctx, odoo_env_path, migration_step, execution_context
|
ctx, odoo_env_path, migration_step, execution_context
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# custom_addons from odoo_version_settings[version]
|
||||||
|
version = migration_step["version"]
|
||||||
|
#TODO: check if custom_addons is in ctx.obj['config']
|
||||||
|
custom_addons = ctx.obj.get("config", {}).get("odoo_version_settings", {}).get(version, {}).get("custom_addons", [])
|
||||||
|
|
||||||
|
for path in custom_addons:
|
||||||
|
logger.info(f"📁 custom_addons: adding path '{path}'")
|
||||||
|
addons_path_list.append(path)
|
||||||
|
|
||||||
|
|
||||||
|
# Normalize addons path (relative to /odoo_env in container)
|
||||||
addons_path = ",".join(
|
addons_path = ",".join(
|
||||||
[str(Path("/odoo_env") / x) for x in addons_path_list]
|
[str(Path("/odoo_env") / x) for x in addons_path_list]
|
||||||
)
|
)
|
||||||
|
|
@ -161,62 +192,88 @@ def generate_odoo_command(
|
||||||
" because it doesn't contain any odoo module."
|
" because it doesn't contain any odoo module."
|
||||||
)
|
)
|
||||||
|
|
||||||
# compute 'log_file'
|
# Compute 'log_file'
|
||||||
log_file_name = "{}____{}.log".format(
|
log_file_name = (
|
||||||
ctx.obj["log_prefix"], migration_step["complete_name"]
|
f"{ctx.obj['log_prefix']}____{migration_step['complete_name']}.log"
|
||||||
)
|
)
|
||||||
log_file_docker_path = "/env/log/%s" % log_file_name
|
log_file_docker_path = f"/env/log/{log_file_name}"
|
||||||
|
|
||||||
database_cmd = database and "--database %s" % database or ""
|
# Build options string
|
||||||
load_cmd = (
|
options = [
|
||||||
server_wide_modules
|
"--config=/odoo_env/odoo.conf",
|
||||||
and "--load %s" % ",".join(server_wide_modules)
|
"--data-dir=/env/filestore/",
|
||||||
or ""
|
f"--addons-path={addons_path}",
|
||||||
|
f"--logfile={log_file_docker_path}",
|
||||||
|
"--db_host=db",
|
||||||
|
"--db_port=5432",
|
||||||
|
"--db_user=odoo",
|
||||||
|
"--db_password=odoo",
|
||||||
|
"--workers=0",
|
||||||
|
f"{'--without-demo=all' if not demo else ''}",
|
||||||
|
f"{'--load ' + ','.join(server_wide_modules) if server_wide_modules else ''}", # noqa
|
||||||
|
f"{'--database=' + database if database else ''}",
|
||||||
|
f"{'--update ' + update if update else ''}",
|
||||||
|
f"{'--init ' + init if init else ''}",
|
||||||
|
f"{'--stop-after-init' if stop_after_init else ''}",
|
||||||
|
]
|
||||||
|
|
||||||
|
# Log resolved addons_path
|
||||||
|
logger.info(f"📦 Final --addons-path: {addons_path}")
|
||||||
|
|
||||||
|
# Remove empty strings
|
||||||
|
return [x for x in options if x]
|
||||||
|
|
||||||
|
|
||||||
|
def generate_odoo_command(
|
||||||
|
ctx,
|
||||||
|
migration_step: dict,
|
||||||
|
execution_context: str,
|
||||||
|
database: str,
|
||||||
|
demo: bool = False,
|
||||||
|
update: str = None,
|
||||||
|
init: str = None,
|
||||||
|
stop_after_init: bool = False,
|
||||||
|
shell: bool = False,
|
||||||
|
) -> str:
|
||||||
|
"""
|
||||||
|
Generate the full Odoo command using options from
|
||||||
|
generate_odoo_command_options.
|
||||||
|
"""
|
||||||
|
options = generate_odoo_command_options(
|
||||||
|
ctx,
|
||||||
|
migration_step,
|
||||||
|
execution_context,
|
||||||
|
database,
|
||||||
|
demo,
|
||||||
|
update,
|
||||||
|
init,
|
||||||
|
stop_after_init,
|
||||||
)
|
)
|
||||||
update_cmd = update and "--update %s" % update or ""
|
|
||||||
init_cmd = init and "--init %s" % init or ""
|
base_command = (
|
||||||
stop_after_init_cmd = stop_after_init and "--stop-after-init" or ""
|
|
||||||
shell_cmd = shell and "shell" or ""
|
|
||||||
demo_cmd = not demo and "--without-demo all" or ""
|
|
||||||
command = (
|
|
||||||
Path("/odoo_env")
|
Path("/odoo_env")
|
||||||
/ Path(get_odoo_folder(migration_step, execution_context))
|
/ Path(get_odoo_folder(migration_step, execution_context))
|
||||||
/ Path(get_odoo_run_command(migration_step))
|
/ Path(get_odoo_run_command(migration_step))
|
||||||
)
|
)
|
||||||
|
|
||||||
result = (
|
options_as_string = " ".join(options)
|
||||||
f" {command}"
|
if shell:
|
||||||
f" {shell_cmd}"
|
return f"{base_command} shell {options_as_string}"
|
||||||
f" --config=/odoo_env/odoo.conf"
|
else:
|
||||||
f" --data-dir=/env/filestore/"
|
return f"{base_command} {options_as_string}"
|
||||||
f" --addons-path={addons_path}"
|
|
||||||
f" --logfile={log_file_docker_path}"
|
|
||||||
f" --db_host=db"
|
|
||||||
f" --db_port=5432"
|
|
||||||
f" --db_user=odoo"
|
|
||||||
f" --db_password=odoo"
|
|
||||||
f" --workers=0"
|
|
||||||
f" {demo_cmd}"
|
|
||||||
f" {load_cmd}"
|
|
||||||
f" {database_cmd}"
|
|
||||||
f" {update_cmd}"
|
|
||||||
f" {init_cmd}"
|
|
||||||
f" {stop_after_init_cmd}"
|
|
||||||
)
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def run_odoo(
|
def run_odoo(
|
||||||
ctx,
|
ctx,
|
||||||
migration_step: dict,
|
migration_step: dict,
|
||||||
detached_container: bool = False,
|
detached_container: bool = False,
|
||||||
database: str = False,
|
database: str = None,
|
||||||
update: str = False,
|
update: str = None,
|
||||||
init: str = False,
|
init: str = None,
|
||||||
stop_after_init: bool = False,
|
stop_after_init: bool = False,
|
||||||
shell: bool = False,
|
shell: bool = False,
|
||||||
demo: bool = False,
|
demo: bool = False,
|
||||||
execution_context: str = False,
|
execution_context: str = None,
|
||||||
alternative_xml_rpc_port: int = False,
|
alternative_xml_rpc_port: int = False,
|
||||||
links: dict = {},
|
links: dict = {},
|
||||||
publish_ports: bool = False,
|
publish_ports: bool = False,
|
||||||
|
|
@ -233,8 +290,8 @@ def run_odoo(
|
||||||
or migration_step["execution_context"],
|
or migration_step["execution_context"],
|
||||||
demo_text=demo and "enabled" or "disabled",
|
demo_text=demo and "enabled" or "disabled",
|
||||||
stop_text=stop_after_init and " (stop-after-init)" or "",
|
stop_text=stop_after_init and " (stop-after-init)" or "",
|
||||||
init_text=init and " (Init : %s)" % init or "",
|
init_text=init and " (Init: %s)" % init or "",
|
||||||
update_text=update and " (Update : %s)" % update or "",
|
update_text=update and " (Update: %s)" % update or "",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -268,9 +325,9 @@ def run_container_odoo(
|
||||||
migration_step: dict,
|
migration_step: dict,
|
||||||
command: str,
|
command: str,
|
||||||
detached_container: bool = False,
|
detached_container: bool = False,
|
||||||
database: str = False,
|
database: str = None,
|
||||||
alternative_xml_rpc_port: int = False,
|
alternative_xml_rpc_port: int = False,
|
||||||
execution_context: str = False,
|
execution_context: str = None,
|
||||||
links: dict = {},
|
links: dict = {},
|
||||||
publish_ports: bool = False,
|
publish_ports: bool = False,
|
||||||
):
|
):
|
||||||
|
|
@ -314,7 +371,7 @@ def execute_click_odoo_python_files(
|
||||||
database: str,
|
database: str,
|
||||||
migration_step: dict,
|
migration_step: dict,
|
||||||
python_files: list = [],
|
python_files: list = [],
|
||||||
execution_context: str = False,
|
execution_context: str = None,
|
||||||
):
|
):
|
||||||
if not python_files:
|
if not python_files:
|
||||||
# Get post-migration python scripts to execute
|
# Get post-migration python scripts to execute
|
||||||
|
|
@ -340,7 +397,7 @@ def execute_click_odoo_python_files(
|
||||||
try:
|
try:
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Step {migration_step['complete_name']}."
|
f"Step {migration_step['complete_name']}."
|
||||||
f" Executing script {python_file} ..."
|
f" Executing script {python_file}..."
|
||||||
)
|
)
|
||||||
run_container_odoo(
|
run_container_odoo(
|
||||||
ctx,
|
ctx,
|
||||||
|
|
@ -362,7 +419,7 @@ def execute_click_odoo_python_files(
|
||||||
|
|
||||||
|
|
||||||
def get_odoo_modules_from_csv(module_file_path: Path) -> list:
|
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 = []
|
module_names = []
|
||||||
csvfile = open(module_file_path, "r")
|
csvfile = open(module_file_path, "r")
|
||||||
spamreader = csv.reader(csvfile, delimiter=",", quotechar='"')
|
spamreader = csv.reader(csvfile, delimiter=",", quotechar='"')
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ class OdooInstance:
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"{x}/{_ODOO_RPC_MAX_TRY}"
|
f"{x}/{_ODOO_RPC_MAX_TRY}"
|
||||||
" Unable to connect to the server."
|
" Unable to connect to the server."
|
||||||
" Retrying in 1 second ..."
|
" Retrying in 1 second..."
|
||||||
)
|
)
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
else:
|
else:
|
||||||
|
|
@ -96,7 +96,7 @@ class OdooInstance:
|
||||||
while installed is False:
|
while installed is False:
|
||||||
try_qty += 1
|
try_qty += 1
|
||||||
try_qty_text = f" (try #{try_qty})" if try_qty != 1 else ""
|
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:
|
try:
|
||||||
module.button_immediate_install()
|
module.button_immediate_install()
|
||||||
installed = True
|
installed = True
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import ast
|
||||||
import importlib
|
import importlib
|
||||||
import os
|
import os
|
||||||
from functools import total_ordering
|
from functools import total_ordering
|
||||||
|
|
@ -105,11 +106,27 @@ class Analysis(object):
|
||||||
last_module_version.analyse_missing_module()
|
last_module_version.analyse_missing_module()
|
||||||
|
|
||||||
def estimate_workload(self, ctx):
|
def estimate_workload(self, ctx):
|
||||||
logger.info("Estimate workload ...")
|
logger.info("Estimate workload...")
|
||||||
for odoo_module in self.modules:
|
for odoo_module in self.modules:
|
||||||
for module_version in odoo_module.module_versions.values():
|
for module_version in odoo_module.module_versions.values():
|
||||||
module_version.estimate_workload(ctx)
|
module_version.estimate_workload(ctx)
|
||||||
|
|
||||||
|
def get_requirements(self, ctx):
|
||||||
|
logger.info("Get requirements...")
|
||||||
|
result = {x: {"python": {}, "bin": {}} for x in self.all_versions}
|
||||||
|
|
||||||
|
for odoo_module in self.modules:
|
||||||
|
for module_version in odoo_module.module_versions.values():
|
||||||
|
module_result = module_version.get_requirements(ctx)
|
||||||
|
python_result = result[module_result["version"]]["python"]
|
||||||
|
module_name = module_result["module_name"]
|
||||||
|
for python_lib in module_result["python"]:
|
||||||
|
if python_lib not in python_result:
|
||||||
|
python_result[python_lib] = [module_name]
|
||||||
|
else:
|
||||||
|
python_result[python_lib].append(module_name)
|
||||||
|
return result
|
||||||
|
|
||||||
def _generate_module_version_first_version(self, ctx, module_list):
|
def _generate_module_version_first_version(self, ctx, module_list):
|
||||||
logger.info(f"Analyse version {self.initial_version}. (First version)")
|
logger.info(f"Analyse version {self.initial_version}. (First version)")
|
||||||
|
|
||||||
|
|
@ -184,14 +201,14 @@ class Analysis(object):
|
||||||
state = "renamed"
|
state = "renamed"
|
||||||
new_module_name = renamed_modules[odoo_module.name]
|
new_module_name = renamed_modules[odoo_module.name]
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"{previous_version} -> {current_version} :"
|
f"{previous_version} -> {current_version}:"
|
||||||
f" {odoo_module.name} renamed into {new_module_name}"
|
f" {odoo_module.name} renamed into {new_module_name}"
|
||||||
)
|
)
|
||||||
elif odoo_module.name in merged_modules:
|
elif odoo_module.name in merged_modules:
|
||||||
state = "merged"
|
state = "merged"
|
||||||
new_module_name = merged_modules[odoo_module.name]
|
new_module_name = merged_modules[odoo_module.name]
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"{previous_version} -> {current_version} :"
|
f"{previous_version} -> {current_version}:"
|
||||||
f" {odoo_module.name} merged into {new_module_name}"
|
f" {odoo_module.name} merged into {new_module_name}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -274,22 +291,27 @@ class Analysis(object):
|
||||||
odoo_modules = self.modules
|
odoo_modules = self.modules
|
||||||
return len(odoo_modules)
|
return len(odoo_modules)
|
||||||
|
|
||||||
def workload_hour_text(self, module_type=False):
|
def workload(self, module_type, repository):
|
||||||
|
odoo_modules = self.modules
|
||||||
if module_type:
|
if module_type:
|
||||||
odoo_modules = [
|
odoo_modules = [
|
||||||
x
|
x
|
||||||
for x in filter(
|
for x in filter(
|
||||||
lambda x: x.module_type == module_type, self.modules
|
lambda x: x.module_type == module_type, odoo_modules
|
||||||
|
)
|
||||||
|
]
|
||||||
|
if repository:
|
||||||
|
odoo_modules = [
|
||||||
|
x
|
||||||
|
for x in filter(
|
||||||
|
lambda x: x.repository == repository, odoo_modules
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
else:
|
|
||||||
odoo_modules = self.modules
|
|
||||||
|
|
||||||
total = 0
|
total = 0
|
||||||
for odoo_module in odoo_modules:
|
for odoo_module in odoo_modules:
|
||||||
for module_version in list(odoo_module.module_versions.values()):
|
for module_version in list(odoo_module.module_versions.values()):
|
||||||
total += module_version.workload
|
total += module_version.workload
|
||||||
return "%d h" % (int(round(total / 60)))
|
return total
|
||||||
|
|
||||||
|
|
||||||
@total_ordering
|
@total_ordering
|
||||||
|
|
@ -327,7 +349,7 @@ class OdooModule(object):
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def get_odoo_apps_url(self):
|
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 = (
|
url = (
|
||||||
f"https://apps.odoo.com/apps/modules/"
|
f"https://apps.odoo.com/apps/modules/"
|
||||||
f"{self.analyse.initial_version}/{self.name}/"
|
f"{self.analyse.initial_version}/{self.name}/"
|
||||||
|
|
@ -342,7 +364,7 @@ class OdooModule(object):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_odoo_code_search_url(self):
|
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 = (
|
url = (
|
||||||
f"https://odoo-code-search.com/ocs/search?"
|
f"https://odoo-code-search.com/ocs/search?"
|
||||||
f"q=name%3A%3D{self.name}+version%3A{self.analyse.initial_version}"
|
f"q=name%3A%3D{self.name}+version%3A{self.analyse.initial_version}"
|
||||||
|
|
@ -473,7 +495,7 @@ class OdooModuleVersion(object):
|
||||||
"doc",
|
"doc",
|
||||||
"description",
|
"description",
|
||||||
]
|
]
|
||||||
_exclude_files = ["__openerp__.py", "__manifest__.py"]
|
_manifest_files = ["__openerp__.py", "__manifest__.py"]
|
||||||
|
|
||||||
_file_extensions = [".py", ".xml", ".js"]
|
_file_extensions = [".py", ".xml", ".js"]
|
||||||
|
|
||||||
|
|
@ -515,6 +537,63 @@ class OdooModuleVersion(object):
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def get_requirements(self, ctx):
|
||||||
|
result = {
|
||||||
|
"python": [],
|
||||||
|
"bin": [],
|
||||||
|
"module_name": self.odoo_module.name,
|
||||||
|
"version": self.version,
|
||||||
|
}
|
||||||
|
manifest_path = False
|
||||||
|
for manifest_name in self._manifest_files:
|
||||||
|
if not self.odoo_module.name or not self.addon_path:
|
||||||
|
continue
|
||||||
|
manifest_path = (
|
||||||
|
self.addon_path / self.odoo_module.name / manifest_name
|
||||||
|
)
|
||||||
|
if manifest_path.exists():
|
||||||
|
break
|
||||||
|
if not manifest_path or not manifest_path.exists():
|
||||||
|
return result
|
||||||
|
|
||||||
|
with manifest_path.open(mode="r", encoding="utf-8") as f_manifest:
|
||||||
|
manifest = ast.literal_eval(f_manifest.read())
|
||||||
|
python_libs = manifest.get("external_dependencies", {}).get(
|
||||||
|
"python", []
|
||||||
|
)
|
||||||
|
bin_libs = manifest.get("external_dependencies", {}).get("bin", [])
|
||||||
|
result["bin"] = bin_libs
|
||||||
|
|
||||||
|
# Handle specific replacement in the setup folder
|
||||||
|
setup_path = (
|
||||||
|
self.addon_path / "setup" / self.odoo_module.name / "setup.py"
|
||||||
|
)
|
||||||
|
if setup_path.exists():
|
||||||
|
with setup_path.open(mode="r", encoding="utf-8") as f_setup:
|
||||||
|
tree = ast.parse(source=f_setup.read())
|
||||||
|
|
||||||
|
for node in ast.walk(tree):
|
||||||
|
if (
|
||||||
|
node.__class__.__name__ == "Dict"
|
||||||
|
and "external_dependencies_override"
|
||||||
|
in [k.value for k in node.keys]
|
||||||
|
):
|
||||||
|
python_replacements = ast.literal_eval(
|
||||||
|
ast.unparse(node)
|
||||||
|
)["external_dependencies_override"]
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
python_replacements = {}
|
||||||
|
|
||||||
|
for k, v in python_replacements.items():
|
||||||
|
if k in python_libs:
|
||||||
|
python_libs.remove(k)
|
||||||
|
result["python"].append(v)
|
||||||
|
|
||||||
|
result["python"] += python_libs
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
def estimate_workload(self, ctx):
|
def estimate_workload(self, ctx):
|
||||||
settings = ctx.obj["config"]["workload_settings"]
|
settings = ctx.obj["config"]["workload_settings"]
|
||||||
port_minimal_time = settings["port_minimal_time"]
|
port_minimal_time = settings["port_minimal_time"]
|
||||||
|
|
@ -605,7 +684,7 @@ class OdooModuleVersion(object):
|
||||||
if set(Path(relative_path).parts) & set(self._exclude_directories):
|
if set(Path(relative_path).parts) & set(self._exclude_directories):
|
||||||
continue
|
continue
|
||||||
for name in files:
|
for name in files:
|
||||||
if name in self._exclude_files:
|
if name in self._manifest_files:
|
||||||
continue
|
continue
|
||||||
filename, file_extension = os.path.splitext(name)
|
filename, file_extension = os.path.splitext(name)
|
||||||
if file_extension in self._file_extensions:
|
if file_extension in self._file_extensions:
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ def get_postgres_container(ctx):
|
||||||
# Check if volume exists
|
# Check if volume exists
|
||||||
try:
|
try:
|
||||||
client.volumes.get(volume_name)
|
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:
|
except docker.errors.NotFound:
|
||||||
logger.info(f"Creating Postgres volume: {volume_name}")
|
logger.info(f"Creating Postgres volume: {volume_name}")
|
||||||
client.volumes.create(volume_name)
|
client.volumes.create(volume_name)
|
||||||
|
|
@ -53,7 +53,7 @@ def get_postgres_container(ctx):
|
||||||
for key, value in postgres_extra_settings.items():
|
for key, value in postgres_extra_settings.items():
|
||||||
command += f" -c {key}={value}"
|
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
|
# base environement variables
|
||||||
environments = {
|
environments = {
|
||||||
|
|
@ -69,7 +69,7 @@ def get_postgres_container(ctx):
|
||||||
postgres_version = float(image_name.split(":")[1])
|
postgres_version = float(image_name.split(":")[1])
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise Exception(
|
raise Exception(
|
||||||
"Unable to extract postgres version "
|
"Unable to extract PostgreSQL version "
|
||||||
f"from image name {image_name}. "
|
f"from image name {image_name}. "
|
||||||
"Define version in the image name is mandatory."
|
"Define version in the image name is mandatory."
|
||||||
)
|
)
|
||||||
|
|
@ -102,6 +102,7 @@ def get_postgres_container(ctx):
|
||||||
ctx.obj["env_folder_path"].absolute(): "/env/",
|
ctx.obj["env_folder_path"].absolute(): "/env/",
|
||||||
},
|
},
|
||||||
detach=True,
|
detach=True,
|
||||||
|
# ports={"5432/tcp": 5432}, # <--- Port-Mapping hinzugefügt
|
||||||
)
|
)
|
||||||
# TODO, improve me.
|
# TODO, improve me.
|
||||||
# Postgres container doesn't seems available immediately.
|
# Postgres container doesn't seems available immediately.
|
||||||
|
|
@ -119,8 +120,8 @@ def execute_sql_file(ctx, database, sql_file):
|
||||||
if str(ctx.obj["env_folder_path"]) not in str(sql_file):
|
if str(ctx.obj["env_folder_path"]) not in str(sql_file):
|
||||||
raise Exception(
|
raise Exception(
|
||||||
f"The SQL file {sql_file} is not in the"
|
f"The SQL file {sql_file} is not in the"
|
||||||
f" main folder {ctx.obj['env_folder_path']} available"
|
f" main directory {ctx.obj['env_folder_path']} available"
|
||||||
" in the postgres container."
|
" in the PostgreSQL container."
|
||||||
)
|
)
|
||||||
relative_path = Path(
|
relative_path = Path(
|
||||||
str(sql_file).replace(str(ctx.obj["env_folder_path"]), ".")
|
str(sql_file).replace(str(ctx.obj["env_folder_path"]), ".")
|
||||||
|
|
@ -131,7 +132,7 @@ def execute_sql_file(ctx, database, sql_file):
|
||||||
"psql --username=odoo --dbname={database} --file {file_path}"
|
"psql --username=odoo --dbname={database} --file {file_path}"
|
||||||
).format(database=database, file_path=container_path)
|
).format(database=database, file_path=container_path)
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Executing the script '{relative_path}' in postgres container"
|
f"Executing the script '{relative_path}' in PostgreSQL container"
|
||||||
f" on database {database}"
|
f" on database {database}"
|
||||||
)
|
)
|
||||||
exec_container(container, command)
|
exec_container(container, command)
|
||||||
|
|
@ -162,7 +163,7 @@ def execute_psql_command(
|
||||||
f" {' '.join(psql_args)}"
|
f" {' '.join(psql_args)}"
|
||||||
)
|
)
|
||||||
logger.debug(
|
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)
|
docker_result = exec_container(container, command)
|
||||||
return docker_result.output.decode("utf-8")
|
return docker_result.output.decode("utf-8")
|
||||||
|
|
@ -240,7 +241,7 @@ def chown_to_local_user(ctx, filepath: os.PathLike):
|
||||||
uid=user_uid, filepath=filepath
|
uid=user_uid, filepath=filepath
|
||||||
)
|
)
|
||||||
logger.debug(
|
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)
|
chown_result = exec_container(container, command)
|
||||||
return chown_result.output.decode("utf8")
|
return chown_result.output.decode("utf8")
|
||||||
|
|
@ -276,7 +277,7 @@ def execute_pg_dump(
|
||||||
pg_dump_args=pg_dump_args,
|
pg_dump_args=pg_dump_args,
|
||||||
)
|
)
|
||||||
logger.debug(
|
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)
|
pg_dump_result = exec_container(container, command)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ def get_script_folder(ctx, migration_step: dict) -> Path:
|
||||||
|
|
||||||
|
|
||||||
def ensure_folder_writable(folder_path: 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:
|
try:
|
||||||
chmod(["--silent", "--recursive", "o+w", str(folder_path)])
|
chmod(["--silent", "--recursive", "o+w", str(folder_path)])
|
||||||
except ProcessExecutionError:
|
except ProcessExecutionError:
|
||||||
|
|
@ -35,9 +35,9 @@ def ensure_folder_exists(
|
||||||
- a log is done at INFO level.
|
- a log is done at INFO level.
|
||||||
"""
|
"""
|
||||||
if not folder_path.exists():
|
if not folder_path.exists():
|
||||||
cmd = ["--parents", folder_path]
|
cmd = ["-p", folder_path]
|
||||||
cmd = ["--mode", mode] + cmd
|
cmd = ["-m", mode] + cmd
|
||||||
logger.info(f"Creating folder '{folder_path}' ...")
|
logger.info(f"Creating directory '{folder_path}'...")
|
||||||
mkdir(cmd)
|
mkdir(cmd)
|
||||||
|
|
||||||
if git_ignore_content:
|
if git_ignore_content:
|
||||||
|
|
@ -74,31 +74,35 @@ def ensure_file_exists_from_template(
|
||||||
if data == output:
|
if data == output:
|
||||||
return
|
return
|
||||||
|
|
||||||
log_text = f"Updating file '{file_path}' from template ..."
|
log_text = f"Updating file '{file_path}' from template..."
|
||||||
else:
|
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:
|
with open(file_path, "w") as f:
|
||||||
logger.info(log_text)
|
logger.info(log_text)
|
||||||
print(output, file=f)
|
print(output, file=f)
|
||||||
|
|
||||||
|
|
||||||
def git_aggregate(folder_path: Path, config_path: Path, jobs: int):
|
def git_aggregate(folder_path: Path, config_path: Path, jobs: int, env_file: str = ".env"):
|
||||||
|
# Convert relative env_file path to absolute path before changing directory
|
||||||
|
if not os.path.isabs(env_file):
|
||||||
|
env_file = os.path.abspath(env_file)
|
||||||
|
|
||||||
args = argparse.Namespace(
|
args = argparse.Namespace(
|
||||||
command="aggregate",
|
command="aggregate",
|
||||||
config=str(config_path),
|
config=str(config_path),
|
||||||
jobs=jobs,
|
jobs=jobs,
|
||||||
dirmatch=None,
|
dirmatch=None,
|
||||||
do_push=False,
|
do_push=False,
|
||||||
expand_env=False,
|
expand_env=True,
|
||||||
env_file=None,
|
env_file=env_file,
|
||||||
force=True,
|
force=True,
|
||||||
)
|
)
|
||||||
with working_directory_keeper:
|
with working_directory_keeper:
|
||||||
os.chdir(folder_path)
|
os.chdir(folder_path)
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Gitaggregate source code for {config_path}."
|
f"Gitaggregate source code for {config_path}."
|
||||||
" This can take a while ..."
|
" This can take a while..."
|
||||||
)
|
)
|
||||||
gitaggregate_cmd.run(args)
|
gitaggregate_cmd.run(args)
|
||||||
|
|
||||||
|
|
@ -173,3 +177,12 @@ def restore_filestore(
|
||||||
else: # works for "t" and "tgz"
|
else: # works for "t" and "tgz"
|
||||||
tar = tarfile.open(src_path)
|
tar = tarfile.open(src_path)
|
||||||
tar.extractall(path=filestore_path)
|
tar.extractall(path=filestore_path)
|
||||||
|
|
||||||
|
# If a filestore/filestore/database/filestore directory exists,
|
||||||
|
# it means that the filestore was in a "filestore" subdirectory
|
||||||
|
# and we need to move this content to the parent directory.
|
||||||
|
filestore_subfolder = filestore_path / "filestore"
|
||||||
|
if filestore_subfolder.exists():
|
||||||
|
for file in filestore_subfolder.iterdir():
|
||||||
|
shutil.move(file, filestore_path)
|
||||||
|
shutil.rmtree(filestore_subfolder)
|
||||||
|
|
|
||||||
649
poetry.lock
generated
649
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
|
|
@ -1,15 +1,15 @@
|
||||||
[tool.poetry]
|
[project]
|
||||||
name = "odoo-openupgrade-wizard"
|
name = "odoo-openupgrade-wizard"
|
||||||
version = "1.0.3"
|
version = "1.3.1.1"
|
||||||
description = "CLI tool to manage Odoo Major Upgrades"
|
description = "CLI tool to manage Odoo Major Upgrades"
|
||||||
authors = [
|
authors = [
|
||||||
"Sylvain LE GAL <sylvain.legal@grap.coop>",
|
{name = "Sylvain LE GAL", email = "sylvain.legal@grap.coop"},
|
||||||
"Rémy TAYMANS <remy@coopiteasy.be>",
|
{name = "Rémy TAYMANS", email = "remy@coopiteasy.be"},
|
||||||
"Simon MAILLARD <simon@ogesta.fr>",
|
{name = "Simon MAILLARD", email = "simon@ogesta.fr"},
|
||||||
]
|
]
|
||||||
maintainers = [
|
maintainers = [
|
||||||
"Sylvain LE GAL <sylvain.legal@grap.coop>",
|
{name = "Sylvain LE GAL", email = "sylvain.legal@grap.coop"},
|
||||||
"Rémy TAYMANS <remy@coopiteasy.be>",
|
{name = "Rémy TAYMANS", email = "remy@coopiteasy.be"},
|
||||||
]
|
]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
repository = "https://gitlab.com/odoo-openupgrade-wizard/odoo-openupgrade-wizard"
|
repository = "https://gitlab.com/odoo-openupgrade-wizard/odoo-openupgrade-wizard"
|
||||||
|
|
@ -23,31 +23,34 @@ classifiers = [
|
||||||
"Programming Language :: Python :: 3.10",
|
"Programming Language :: Python :: 3.10",
|
||||||
"Programming Language :: Python :: 3.11",
|
"Programming Language :: Python :: 3.11",
|
||||||
"Programming Language :: Python :: 3.12",
|
"Programming Language :: Python :: 3.12",
|
||||||
|
# Currently poetry 2.0.0 failed to find the following classifier
|
||||||
|
#"Programming Language :: Python :: 3.13",
|
||||||
"Framework :: Odoo",
|
"Framework :: Odoo",
|
||||||
]
|
]
|
||||||
|
requires-python = ">=3.9,<4.0"
|
||||||
|
dependencies = [
|
||||||
|
"click (>=7.0,<8.0)",
|
||||||
|
"click-loglevel (>=0.4)",
|
||||||
|
"docker (>=7.0,<8.0)",
|
||||||
|
"importlib-resources (>=5.4,<6.0)",
|
||||||
|
"git-aggregator (>=2.1,<3.0)",
|
||||||
|
"GitPython (>=3.1,<4.0)",
|
||||||
|
"jinja2 (>=3.0,<4.0)",
|
||||||
|
"loguru (>=0.6)",
|
||||||
|
"odoorpc (>=0.10.1)",
|
||||||
|
"plumbum (>=1.7,<2.0)",
|
||||||
|
"pygount (>=1.4,<2.0)",
|
||||||
|
"pyyaml (>=6.0.0,<7.0.0)",
|
||||||
|
"single-source (>=0.3)",
|
||||||
|
]
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
Repository = "https://gitlab.com/odoo-openupgrade-wizard/odoo-openupgrade-wizard"
|
Repository = "https://gitlab.com/odoo-openupgrade-wizard/odoo-openupgrade-wizard"
|
||||||
|
|
||||||
[tool.poetry.scripts]
|
[project.scripts]
|
||||||
oow = "odoo_openupgrade_wizard.cli.cli:main"
|
oow = "odoo_openupgrade_wizard.cli.cli:main"
|
||||||
odoo-openupgrade-wizard = "odoo_openupgrade_wizard.cli.cli:main"
|
odoo-openupgrade-wizard = "odoo_openupgrade_wizard.cli.cli:main"
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
|
||||||
python = ">=3.9,<4.0.0"
|
|
||||||
click = "^7.0"
|
|
||||||
click-loglevel = "^0.4"
|
|
||||||
docker = "^7.0"
|
|
||||||
importlib-resources = "^5.4"
|
|
||||||
git-aggregator = "^2.1"
|
|
||||||
GitPython = "^3.1"
|
|
||||||
jinja2 = "^3.0"
|
|
||||||
loguru = "^0.6"
|
|
||||||
odoorpc = "^0.10.1"
|
|
||||||
plumbum = "^1.7"
|
|
||||||
pygount = "^1.4"
|
|
||||||
pyyaml = "^6.0.0"
|
|
||||||
single-source = "^0.3"
|
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
pytest = [
|
pytest = [
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ def move_to_test_folder():
|
||||||
if os.getcwd().endswith("tests/data/output"):
|
if os.getcwd().endswith("tests/data/output"):
|
||||||
return
|
return
|
||||||
test_folder_path = Path("tests/data/output")
|
test_folder_path = Path("tests/data/output")
|
||||||
mkdir([test_folder_path, "--parents"])
|
mkdir(["-p", test_folder_path])
|
||||||
os.chdir(test_folder_path)
|
os.chdir(test_folder_path)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
23
tests/cli_09_guess_requirement_test.py
Normal file
23
tests/cli_09_guess_requirement_test.py
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import filecmp
|
||||||
|
import unittest
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from . import cli_runner_invoke, move_to_test_folder
|
||||||
|
|
||||||
|
|
||||||
|
class TestCliGuessRequirement(unittest.TestCase):
|
||||||
|
def test_cli_guess_requirement(self):
|
||||||
|
move_to_test_folder()
|
||||||
|
|
||||||
|
expected_folder_path = Path("../output_expected").absolute()
|
||||||
|
|
||||||
|
cli_runner_invoke(
|
||||||
|
["guess-requirement", "--extra-modules=sentry"],
|
||||||
|
)
|
||||||
|
|
||||||
|
relative_path = Path("src/env_14.0/addons_python_requirements.txt")
|
||||||
|
|
||||||
|
assert filecmp.cmp(
|
||||||
|
relative_path,
|
||||||
|
expected_folder_path / relative_path,
|
||||||
|
)
|
||||||
|
|
@ -45,6 +45,38 @@ def test_cli_restoredb(mocker):
|
||||||
# check filestore exists
|
# check filestore exists
|
||||||
assert dest_filestore_path.exists()
|
assert dest_filestore_path.exists()
|
||||||
|
|
||||||
|
# check the filestore content is at the right place
|
||||||
|
assert (dest_filestore_path / "01").exists()
|
||||||
|
|
||||||
|
# Check database exists
|
||||||
|
assert_database(ctx, db_name, "present")
|
||||||
|
|
||||||
|
# Delete filestore and database
|
||||||
|
shutil.rmtree(dest_filestore_path)
|
||||||
|
ensure_database(ctx, db_name, state="absent")
|
||||||
|
|
||||||
|
shutil.copyfile(
|
||||||
|
pathlib.Path("../restoredb/test_with_nested_filestore_dir.tar.gz"),
|
||||||
|
filestore_path,
|
||||||
|
)
|
||||||
|
|
||||||
|
cli_runner_invoke(
|
||||||
|
[
|
||||||
|
"restoredb",
|
||||||
|
f"--database={db_name}",
|
||||||
|
f"--database-path={database_path}",
|
||||||
|
"--database-format=c",
|
||||||
|
f"--filestore-path={filestore_path}",
|
||||||
|
"--filestore-format=tgz",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
# check filestore exists
|
||||||
|
assert dest_filestore_path.exists()
|
||||||
|
|
||||||
|
# check the filestore content is at the right place
|
||||||
|
assert (dest_filestore_path / "01").exists()
|
||||||
|
|
||||||
# Check database exists
|
# Check database exists
|
||||||
assert_database(ctx, db_name, "present")
|
assert_database(ctx, db_name, "present")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ migration_steps:
|
||||||
version: 14.0
|
version: 14.0
|
||||||
execution_context: regular
|
execution_context: regular
|
||||||
complete_name: step_01__regular__14.0
|
complete_name: step_01__regular__14.0
|
||||||
|
update: True
|
||||||
|
|
||||||
- name: 2
|
- name: 2
|
||||||
version: 15.0
|
version: 15.0
|
||||||
|
|
@ -38,6 +39,7 @@ migration_steps:
|
||||||
version: 15.0
|
version: 15.0
|
||||||
execution_context: regular
|
execution_context: regular
|
||||||
complete_name: step_03__regular__15.0
|
complete_name: step_03__regular__15.0
|
||||||
|
update: True
|
||||||
|
|
||||||
|
|
||||||
workload_settings:
|
workload_settings:
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Do NOT edit manually. Changes here will be overwritten by the command 'guess-requirement'
|
||||||
|
|
||||||
|
# Required by the module(s): sentry
|
||||||
|
sentry_sdk<=1.9.0
|
||||||
Binary file not shown.
BIN
tests/data/restoredb/test_with_nested_filestore_dir.tar.gz
Normal file
BIN
tests/data/restoredb/test_with_nested_filestore_dir.tar.gz
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user