diff --git a/odoo_openupgrade_wizard/cli.py b/odoo_openupgrade_wizard/cli.py index f6e0310..9be7cd2 100644 --- a/odoo_openupgrade_wizard/cli.py +++ b/odoo_openupgrade_wizard/cli.py @@ -1,12 +1,16 @@ import datetime +import logging +import sys from pathlib import Path import click import yaml +from click_loglevel import LogLevel from loguru import logger import odoo_openupgrade_wizard from odoo_openupgrade_wizard.cli_docker_build import docker_build +from odoo_openupgrade_wizard.cli_execute_script import execute_script from odoo_openupgrade_wizard.cli_get_code import get_code from odoo_openupgrade_wizard.cli_init import init from odoo_openupgrade_wizard.cli_run import run @@ -18,7 +22,6 @@ from odoo_openupgrade_wizard.tools_system import ensure_folder_exists @click.group() @click.version_option(version=odoo_openupgrade_wizard.__version__) @click.option( - "-ef", "--env-folder", default="./", type=click.Path( @@ -33,19 +36,21 @@ from odoo_openupgrade_wizard.tools_system import ensure_folder_exists " use current folder (./).", ) @click.option( - "-fs", "--filestore-folder", type=click.Path(dir_okay=True, file_okay=False, resolve_path=True), help="Folder that contains the Odoo filestore of the database(s)" " to migrate. Let empty to use the subfolder 'filestore' of the" " environment folder.", ) +@click.option("-l", "--log-level", type=LogLevel(), default=logging.INFO) @click.pass_context -def main(ctx, env_folder, filestore_folder): +def main(ctx, env_folder, filestore_folder, log_level): """ Provides a command set to perform odoo Community Edition migrations. """ date_begin = datetime.datetime.now() + logger.remove() + logger.add(sys.stderr, level=log_level) logger.debug("Beginning script '%s' ..." % (ctx.invoked_subcommand)) if not isinstance(ctx.obj, dict): ctx.obj = {} @@ -97,4 +102,5 @@ main.add_command(get_code) main.add_command(docker_build) main.add_command(run) main.add_command(upgrade) +main.add_command(execute_script) main.add_command(test_dev) diff --git a/odoo_openupgrade_wizard/cli_execute_script.py b/odoo_openupgrade_wizard/cli_execute_script.py new file mode 100644 index 0000000..8804086 --- /dev/null +++ b/odoo_openupgrade_wizard/cli_execute_script.py @@ -0,0 +1,21 @@ +import click + +from odoo_openupgrade_wizard.cli_options import ( + database_option_required, + get_migration_step_from_options, + step_option, +) +from odoo_openupgrade_wizard.tools_odoo import ( + execute_python_files_post_migration, +) + + +@click.command() +@step_option +@database_option_required +@click.pass_context +def execute_script(ctx, step, database): + + migration_step = get_migration_step_from_options(ctx, step) + + execute_python_files_post_migration(ctx, database, migration_step) diff --git a/odoo_openupgrade_wizard/cli_run.py b/odoo_openupgrade_wizard/cli_run.py index 73949b8..ed8fe03 100644 --- a/odoo_openupgrade_wizard/cli_run.py +++ b/odoo_openupgrade_wizard/cli_run.py @@ -7,6 +7,7 @@ from odoo_openupgrade_wizard.cli_options import ( step_option, ) from odoo_openupgrade_wizard.tools_odoo import kill_odoo, run_odoo +from odoo_openupgrade_wizard.tools_odoo_instance import get_odoo_url @click.command() @@ -40,8 +41,7 @@ def run(ctx, step, database, stop_after_init, init_modules): ) if not stop_after_init: logger.info( - "Odoo is available on your host at http://localhost:%d" - % (ctx.obj["config"]["host_odoo_xmlrpc_port"]) + "Odoo is available on your host at %s" % get_odoo_url(ctx) ) input("Press 'Enter' to kill the odoo container and exit ...") except (KeyboardInterrupt, SystemExit): diff --git a/odoo_openupgrade_wizard/cli_upgrade.py b/odoo_openupgrade_wizard/cli_upgrade.py index 4936fcc..a9a149b 100644 --- a/odoo_openupgrade_wizard/cli_upgrade.py +++ b/odoo_openupgrade_wizard/cli_upgrade.py @@ -7,7 +7,11 @@ from odoo_openupgrade_wizard.cli_options import ( get_migration_steps_from_options, last_step_option, ) -from odoo_openupgrade_wizard.tools_odoo import kill_odoo, run_odoo +from odoo_openupgrade_wizard.tools_odoo import ( + execute_python_files_post_migration, + kill_odoo, + run_odoo, +) @click.command() @@ -20,8 +24,8 @@ def upgrade(ctx, first_step, last_step, database): migration_steps = get_migration_steps_from_options( ctx, first_step, last_step ) - try: - for migration_step in migration_steps: + for migration_step in migration_steps: + try: run_odoo( ctx, migration_step, @@ -30,7 +34,8 @@ def upgrade(ctx, first_step, last_step, database): update="all", stop_after_init=True, ) - except (KeyboardInterrupt, SystemExit): - logger.info("Received Keyboard Interrupt or System Exiting...") - finally: - kill_odoo(ctx, migration_step) + except (KeyboardInterrupt, SystemExit): + logger.info("Received Keyboard Interrupt or System Exiting...") + finally: + kill_odoo(ctx, migration_step) + execute_python_files_post_migration(ctx, database, migration_step) diff --git a/odoo_openupgrade_wizard/templates.py b/odoo_openupgrade_wizard/templates.py index af16a9c..2e4736c 100644 --- a/odoo_openupgrade_wizard/templates.py +++ b/odoo_openupgrade_wizard/templates.py @@ -106,7 +106,7 @@ USER odoo PRE_MIGRATION_SQL_TEMPLATE = "" POST_MIGRATION_PY_TEMPLATE = """ -def main(self, step): +def main(self): pass """ diff --git a/odoo_openupgrade_wizard/tools_odoo.py b/odoo_openupgrade_wizard/tools_odoo.py index e13e127..92cbfac 100644 --- a/odoo_openupgrade_wizard/tools_odoo.py +++ b/odoo_openupgrade_wizard/tools_odoo.py @@ -1,6 +1,11 @@ +import importlib.util +import os +import sys +import traceback from pathlib import Path import yaml +from loguru import logger from odoo_openupgrade_wizard.configuration_version_dependant import ( get_base_module_folder, @@ -10,6 +15,7 @@ from odoo_openupgrade_wizard.configuration_version_dependant import ( skip_addon_path, ) from odoo_openupgrade_wizard.tools_docker import kill_container, run_container +from odoo_openupgrade_wizard.tools_odoo_instance import OdooInstance def get_odoo_addons_path(ctx, root_path: Path, migration_step: dict) -> str: @@ -37,6 +43,10 @@ def get_odoo_addons_path(ctx, root_path: Path, migration_step: dict) -> str: return ",".join([str(x) for x in addons_path]) +def get_script_folder(ctx, migration_step: dict) -> Path: + return ctx.obj["script_folder_path"] / migration_step["complete_name"] + + def get_odoo_env_path(ctx, odoo_version: dict) -> Path: folder_name = "env_%s" % str(odoo_version["release"]).rjust(4, "0") return ctx.obj["src_folder_path"] / folder_name @@ -85,7 +95,6 @@ def generate_odoo_command( shell: bool, demo: bool, ) -> str: - # TODO, make it dynamic addons_path = get_odoo_addons_path(ctx, Path("/odoo_env"), migration_step) server_wide_modules = get_server_wide_modules(ctx, migration_step) server_wide_modules_cmd = ( @@ -176,3 +185,51 @@ def run_odoo( def kill_odoo(ctx, migration_step: dict): kill_container(get_docker_container_name(ctx, migration_step)) + + +def execute_python_files_post_migration( + ctx, database: str, migration_step: dict +): + script_folder = get_script_folder(ctx, migration_step) + + python_files = [ + f + for f in os.listdir(script_folder) + if os.path.isfile(os.path.join(script_folder, f)) and f[-3:] == ".py" + ] + python_files = sorted(python_files) + + try: + # Launch Odoo + run_odoo( + ctx, + migration_step, + detached_container=True, + database=database, + ) + + # Create Odoo instance via Odoo RPC + odoo_instance = OdooInstance(ctx, database) + + for python_file in python_files: + # Generate Python Script + logger.info("Running Script Post (Python) %s" % python_file) + package_name = "script.%s.%s" % ( + migration_step["complete_name"], + python_file[:-3], + ) + module_spec = importlib.util.spec_from_file_location( + package_name, Path(script_folder, python_file) + ) + module = importlib.util.module_from_spec(module_spec) + module_spec.loader.exec_module(module) + + module.main(odoo_instance) + except Exception as e: + logger.error( + "An error occured. Exiting. %s\n%s" + % (e, traceback.print_exception(*sys.exc_info())) + ) + raise e + finally: + kill_odoo(ctx, migration_step) diff --git a/odoo_openupgrade_wizard/tools_odoo_instance.py b/odoo_openupgrade_wizard/tools_odoo_instance.py new file mode 100644 index 0000000..5e73426 --- /dev/null +++ b/odoo_openupgrade_wizard/tools_odoo_instance.py @@ -0,0 +1,190 @@ +import socket +import time + +import odoorpc +from loguru import logger + + +def get_odoo_url(ctx) -> str: + return "http://localhost:%d" % (ctx.obj["config"]["host_odoo_xmlrpc_port"]) + + +class OdooInstance: + + env = False + version = False + + # constructeur de la classe + def __init__(self, ctx, database): + # TODO, improve me waith for response on http://localhost:port + # with a time out + # the docker container take a little time to be up. + time.sleep(2) + + # Connection + try: + rpc_connexion = odoorpc.ODOO( + "localhost", + "jsonrpc", + port=ctx.obj["config"]["host_odoo_xmlrpc_port"], + timeout=60, + ) + except (socket.gaierror, socket.error) as e: + logger.critical("Unable to connect to the server.") + raise e + + # Login + try: + rpc_connexion.login( + database, + "admin", + "admin", + ) + except Exception as e: + logger.error( + "Unable to connect to %s with login %s and password %s" + % ( + get_odoo_url(ctx), + "admin", + "admin", + ) + ) + raise e + + self.env = rpc_connexion.env + self.version = rpc_connexion.version + + def browse_by_search( + self, model_name, domain=False, order=False, limit=False + ): + domain = domain or [] + model = self.env[model_name] + return model.browse(model.search(domain, order=order, limit=limit)) + + def browse_by_create(self, model_name, vals): + model = self.env[model_name] + return model.browse(model.create(vals)) + + def check_modules_installed(self, module_names) -> bool: + if type(module_names) == str: + module_names = [module_names] + installed_module_ids = self.env["ir.module.module"].search( + [ + ("name", "in", module_names), + ("state", "=", "installed"), + ] + ) + return len(module_names) == len(installed_module_ids) + + def check_models_present( + self, model_name, warning_if_not_found=True + ) -> bool: + if self.env["ir.model"].search([("model", "=", model_name)]): + return True + else: + if warning_if_not_found: + logger.warning( + "Model '%s' not found." + " Part of the script will be skipped." % (model_name) + ) + return False + + def install_modules(self, module_names): + if type(module_names) == str: + module_names = [module_names] + installed_modules = [] + i = 0 + for module_name in module_names: + i += 1 + prefix = str(i) + "/" + str(len(module_names)) + modules = self.browse_by_search( + "ir.module.module", [("name", "=", module_name)] + ) + if not len(modules): + logger.error( + "%s - Module '%s': Not found." % (prefix, module_name) + ) + continue + + module = modules[0] + if module.state == "installed": + logger.info( + "%s - Module %s still installed." + " skipped." % (prefix, module_name) + ) + elif module.state == "uninstalled": + try_qty = 0 + installed = False + while installed is False: + try_qty += 1 + logger.info( + "%s - Module '%s': Installing ... %s" + % ( + prefix, + module_name, + "(try #%d)" % try_qty if try_qty != 1 else "", + ) + ) + try: + module.button_immediate_install() + installed = True + installed_modules.append(module_name) + time.sleep(5) + except Exception as e: + if try_qty <= 5: + sleeping_time = 2 * try_qty * 60 + logger.warning( + "Error. Retrying in %d seconds.\n %s" + % (sleeping_time, e) + ) + time.sleep(sleeping_time) + else: + logger.critical( + "Error after %d try. Exiting.\n %s" + % (try_qty, e) + ) + raise e + else: + logger.error( + "%s - Module '%s': In the %s state." + " (Unable to install)" + % (prefix, module_name, module.state) + ) + return installed_modules + + def uninstall_modules(self, module_names): + if type(module_names) == str: + module_names = [module_names] + i = 0 + for module_name in module_names: + i += 1 + prefix = str(i) + "/" + str(len(module_names)) + modules = self.browse_by_search( + "ir.module.module", [("name", "=", module_name)] + ) + if not len(modules): + logger.error( + "%s - Module '%s': Not found." % (prefix, module_name) + ) + continue + module = modules[0] + if module.state in ( + "installed", + "to upgrade", + "to update", + "to remove", + ): + logger.info( + "%s - Module '%s': Uninstalling .." % (prefix, module_name) + ) + module.button_upgrade_cancel() + module.button_uninstall() + wizard = self.browse_by_create("base.module.upgrade", {}) + wizard.upgrade_module() + + else: + logger.error( + "%s - Module '%s': In the %s state." + " (Unable to uninstall)" + % (prefix, module_name, module.state) + ) diff --git a/poetry.lock b/poetry.lock index 97b830d..01ac4a7 100644 --- a/poetry.lock +++ b/poetry.lock @@ -97,6 +97,17 @@ python-versions = "*" [package.dependencies] click = "*" +[[package]] +name = "click-loglevel" +version = "0.4.0.post1" +description = "Log level parameter type for Click" +category = "main" +optional = false +python-versions = "~=3.6" + +[package.dependencies] +click = ">=6.0" + [[package]] name = "colorama" version = "0.4.4" @@ -477,7 +488,7 @@ testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xm [[package]] name = "pytest" -version = "7.1.1" +version = "7.1.2" description = "pytest: simple powerful testing with Python" category = "dev" optional = false @@ -614,7 +625,7 @@ dev = ["packaging"] [[package]] name = "tox" -version = "3.24.5" +version = "3.25.0" description = "tox is a generic virtualenv management and test command line tool" category = "dev" optional = false @@ -637,7 +648,7 @@ testing = ["flaky (>=3.4.0)", "freezegun (>=0.3.11)", "pytest (>=4.0.0)", "pytes [[package]] name = "typed-ast" -version = "1.5.2" +version = "1.5.3" description = "a fork of Python 2 and 3 ast modules with type comment support" category = "dev" optional = false @@ -666,7 +677,7 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "virtualenv" -version = "20.14.0" +version = "20.14.1" description = "Virtual Python Environment builder" category = "dev" optional = false @@ -731,7 +742,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytes [metadata] lock-version = "1.1" python-versions = "^3.6" -content-hash = "d1032300d832c58b3e154412055bb689da8f90750b412c5bf52d70a47ff0a586" +content-hash = "5337fb24cba5bdf35d6307ba0b418a0e2ee2415fac89df2563249157df1b256a" [metadata.files] aiocontextvars = [ @@ -769,6 +780,10 @@ click = [ click-default-group = [ {file = "click-default-group-1.2.2.tar.gz", hash = "sha256:d9560e8e8dfa44b3562fbc9425042a0fd6d21956fcc2db0077f63f34253ab904"}, ] +click-loglevel = [ + {file = "click-loglevel-0.4.0.post1.tar.gz", hash = "sha256:470bf1e208fe650cedacb23061e4e18d36df601ca9d8b79e6d8e8cdf1792ece1"}, + {file = "click_loglevel-0.4.0.post1-py3-none-any.whl", hash = "sha256:f3449b5d28d6cba5bfbeed371ad59950aba035730d5cc28a32b4e7632e17ed6c"}, +] colorama = [ {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, @@ -1078,8 +1093,8 @@ pyparsing = [ pytest = [ {file = "pytest-6.1.2-py3-none-any.whl", hash = "sha256:4288fed0d9153d9646bfcdf0c0428197dba1ecb27a33bb6e031d002fa88653fe"}, {file = "pytest-6.1.2.tar.gz", hash = "sha256:c0a7e94a8cdbc5422a51ccdad8e6f1024795939cc89159a0ae7f0b316ad3823e"}, - {file = "pytest-7.1.1-py3-none-any.whl", hash = "sha256:92f723789a8fdd7180b6b06483874feca4c48a5c76968e03bb3e7f806a1869ea"}, - {file = "pytest-7.1.1.tar.gz", hash = "sha256:841132caef6b1ad17a9afde46dc4f6cfa59a05f9555aae5151f73bdf2820ca63"}, + {file = "pytest-7.1.2-py3-none-any.whl", hash = "sha256:13d0e3ccfc2b6e26be000cb6568c832ba67ba32e719443bfe725814d3c42433c"}, + {file = "pytest-7.1.2.tar.gz", hash = "sha256:a06a0425453864a270bc45e71f783330a7428defb4230fb5e6a731fde06ecd45"}, ] pytest-cov = [ {file = "pytest-cov-3.0.0.tar.gz", hash = "sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470"}, @@ -1159,34 +1174,34 @@ towncrier = [ {file = "towncrier-21.9.0.tar.gz", hash = "sha256:9cb6f45c16e1a1eec9d0e7651165e7be60cd0ab81d13a5c96ca97a498ae87f48"}, ] tox = [ - {file = "tox-3.24.5-py2.py3-none-any.whl", hash = "sha256:be3362472a33094bce26727f5f771ca0facf6dafa217f65875314e9a6600c95c"}, - {file = "tox-3.24.5.tar.gz", hash = "sha256:67e0e32c90e278251fea45b696d0fef3879089ccbe979b0c556d35d5a70e2993"}, + {file = "tox-3.25.0-py2.py3-none-any.whl", hash = "sha256:0805727eb4d6b049de304977dfc9ce315a1938e6619c3ab9f38682bb04662a5a"}, + {file = "tox-3.25.0.tar.gz", hash = "sha256:37888f3092aa4e9f835fc8cc6dadbaaa0782651c41ef359e3a5743fcb0308160"}, ] typed-ast = [ - {file = "typed_ast-1.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:183b183b7771a508395d2cbffd6db67d6ad52958a5fdc99f450d954003900266"}, - {file = "typed_ast-1.5.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:676d051b1da67a852c0447621fdd11c4e104827417bf216092ec3e286f7da596"}, - {file = "typed_ast-1.5.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc2542e83ac8399752bc16e0b35e038bdb659ba237f4222616b4e83fb9654985"}, - {file = "typed_ast-1.5.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:74cac86cc586db8dfda0ce65d8bcd2bf17b58668dfcc3652762f3ef0e6677e76"}, - {file = "typed_ast-1.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:18fe320f354d6f9ad3147859b6e16649a0781425268c4dde596093177660e71a"}, - {file = "typed_ast-1.5.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:31d8c6b2df19a777bc8826770b872a45a1f30cfefcfd729491baa5237faae837"}, - {file = "typed_ast-1.5.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:963a0ccc9a4188524e6e6d39b12c9ca24cc2d45a71cfdd04a26d883c922b4b78"}, - {file = "typed_ast-1.5.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0eb77764ea470f14fcbb89d51bc6bbf5e7623446ac4ed06cbd9ca9495b62e36e"}, - {file = "typed_ast-1.5.2-cp36-cp36m-win_amd64.whl", hash = "sha256:294a6903a4d087db805a7656989f613371915fc45c8cc0ddc5c5a0a8ad9bea4d"}, - {file = "typed_ast-1.5.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:26a432dc219c6b6f38be20a958cbe1abffcc5492821d7e27f08606ef99e0dffd"}, - {file = "typed_ast-1.5.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7407cfcad702f0b6c0e0f3e7ab876cd1d2c13b14ce770e412c0c4b9728a0f88"}, - {file = "typed_ast-1.5.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f30ddd110634c2d7534b2d4e0e22967e88366b0d356b24de87419cc4410c41b7"}, - {file = "typed_ast-1.5.2-cp37-cp37m-win_amd64.whl", hash = "sha256:8c08d6625bb258179b6e512f55ad20f9dfef019bbfbe3095247401e053a3ea30"}, - {file = "typed_ast-1.5.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:90904d889ab8e81a956f2c0935a523cc4e077c7847a836abee832f868d5c26a4"}, - {file = "typed_ast-1.5.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bbebc31bf11762b63bf61aaae232becb41c5bf6b3461b80a4df7e791fabb3aca"}, - {file = "typed_ast-1.5.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c29dd9a3a9d259c9fa19d19738d021632d673f6ed9b35a739f48e5f807f264fb"}, - {file = "typed_ast-1.5.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:58ae097a325e9bb7a684572d20eb3e1809802c5c9ec7108e85da1eb6c1a3331b"}, - {file = "typed_ast-1.5.2-cp38-cp38-win_amd64.whl", hash = "sha256:da0a98d458010bf4fe535f2d1e367a2e2060e105978873c04c04212fb20543f7"}, - {file = "typed_ast-1.5.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:33b4a19ddc9fc551ebabca9765d54d04600c4a50eda13893dadf67ed81d9a098"}, - {file = "typed_ast-1.5.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1098df9a0592dd4c8c0ccfc2e98931278a6c6c53cb3a3e2cf7e9ee3b06153344"}, - {file = "typed_ast-1.5.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42c47c3b43fe3a39ddf8de1d40dbbfca60ac8530a36c9b198ea5b9efac75c09e"}, - {file = "typed_ast-1.5.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f290617f74a610849bd8f5514e34ae3d09eafd521dceaa6cf68b3f4414266d4e"}, - {file = "typed_ast-1.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:df05aa5b241e2e8045f5f4367a9f6187b09c4cdf8578bb219861c4e27c443db5"}, - {file = "typed_ast-1.5.2.tar.gz", hash = "sha256:525a2d4088e70a9f75b08b3f87a51acc9cde640e19cc523c7e41aa355564ae27"}, + {file = "typed_ast-1.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ad3b48cf2b487be140072fb86feff36801487d4abb7382bb1929aaac80638ea"}, + {file = "typed_ast-1.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:542cd732351ba8235f20faa0fc7398946fe1a57f2cdb289e5497e1e7f48cfedb"}, + {file = "typed_ast-1.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dc2c11ae59003d4a26dda637222d9ae924387f96acae9492df663843aefad55"}, + {file = "typed_ast-1.5.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fd5df1313915dbd70eaaa88c19030b441742e8b05e6103c631c83b75e0435ccc"}, + {file = "typed_ast-1.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:e34f9b9e61333ecb0f7d79c21c28aa5cd63bec15cb7e1310d7d3da6ce886bc9b"}, + {file = "typed_ast-1.5.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f818c5b81966d4728fec14caa338e30a70dfc3da577984d38f97816c4b3071ec"}, + {file = "typed_ast-1.5.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3042bfc9ca118712c9809201f55355479cfcdc17449f9f8db5e744e9625c6805"}, + {file = "typed_ast-1.5.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4fff9fdcce59dc61ec1b317bdb319f8f4e6b69ebbe61193ae0a60c5f9333dc49"}, + {file = "typed_ast-1.5.3-cp36-cp36m-win_amd64.whl", hash = "sha256:8e0b8528838ffd426fea8d18bde4c73bcb4167218998cc8b9ee0a0f2bfe678a6"}, + {file = "typed_ast-1.5.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8ef1d96ad05a291f5c36895d86d1375c0ee70595b90f6bb5f5fdbee749b146db"}, + {file = "typed_ast-1.5.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed44e81517364cb5ba367e4f68fca01fba42a7a4690d40c07886586ac267d9b9"}, + {file = "typed_ast-1.5.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f60d9de0d087454c91b3999a296d0c4558c1666771e3460621875021bf899af9"}, + {file = "typed_ast-1.5.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9e237e74fd321a55c90eee9bc5d44be976979ad38a29bbd734148295c1ce7617"}, + {file = "typed_ast-1.5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ee852185964744987609b40aee1d2eb81502ae63ee8eef614558f96a56c1902d"}, + {file = "typed_ast-1.5.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:27e46cdd01d6c3a0dd8f728b6a938a6751f7bd324817501c15fb056307f918c6"}, + {file = "typed_ast-1.5.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d64dabc6336ddc10373922a146fa2256043b3b43e61f28961caec2a5207c56d5"}, + {file = "typed_ast-1.5.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8cdf91b0c466a6c43f36c1964772918a2c04cfa83df8001ff32a89e357f8eb06"}, + {file = "typed_ast-1.5.3-cp38-cp38-win_amd64.whl", hash = "sha256:9cc9e1457e1feb06b075c8ef8aeb046a28ec351b1958b42c7c31c989c841403a"}, + {file = "typed_ast-1.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e20d196815eeffb3d76b75223e8ffed124e65ee62097e4e73afb5fec6b993e7a"}, + {file = "typed_ast-1.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:37e5349d1d5de2f4763d534ccb26809d1c24b180a477659a12c4bde9dd677d74"}, + {file = "typed_ast-1.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9f1a27592fac87daa4e3f16538713d705599b0a27dfe25518b80b6b017f0a6d"}, + {file = "typed_ast-1.5.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8831479695eadc8b5ffed06fdfb3e424adc37962a75925668deeb503f446c0a3"}, + {file = "typed_ast-1.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:20d5118e494478ef2d3a2702d964dae830aedd7b4d3b626d003eea526be18718"}, + {file = "typed_ast-1.5.3.tar.gz", hash = "sha256:27f25232e2dd0edfe1f019d6bfaaf11e86e657d9bdb7b0956db95f560cceb2b3"}, ] typing-extensions = [ {file = "typing_extensions-4.1.1-py3-none-any.whl", hash = "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"}, @@ -1197,8 +1212,8 @@ urllib3 = [ {file = "urllib3-1.26.9.tar.gz", hash = "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"}, ] virtualenv = [ - {file = "virtualenv-20.14.0-py2.py3-none-any.whl", hash = "sha256:1e8588f35e8b42c6ec6841a13c5e88239de1e6e4e4cedfd3916b306dc826ec66"}, - {file = "virtualenv-20.14.0.tar.gz", hash = "sha256:8e5b402037287126e81ccde9432b95a8be5b19d36584f64957060a3488c11ca8"}, + {file = "virtualenv-20.14.1-py2.py3-none-any.whl", hash = "sha256:e617f16e25b42eb4f6e74096b9c9e37713cf10bf30168fb4a739f3fa8f898a3a"}, + {file = "virtualenv-20.14.1.tar.gz", hash = "sha256:ef589a79795589aada0c1c5b319486797c03b67ac3984c48c669c0e4f50df3a5"}, ] websocket-client = [ {file = "websocket-client-1.3.1.tar.gz", hash = "sha256:6278a75065395418283f887de7c3beafb3aa68dada5cacbe4b214e8d26da499b"}, diff --git a/pyproject.toml b/pyproject.toml index f46bafb..1d4d5ef 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,6 +31,8 @@ odoo-openupgrade-wizard = "odoo_openupgrade_wizard.cli:main" [tool.poetry.dependencies] python = "^3.6" click = "^7.0" +click-loglevel = "^0.4" +odoorpc = "^0.8" loguru = "^0.6" plumbum = "^1.7" single-source = "^0.3" diff --git a/tests/cli_B_04_execute_script_test.py b/tests/cli_B_04_execute_script_test.py new file mode 100644 index 0000000..e8ec649 --- /dev/null +++ b/tests/cli_B_04_execute_script_test.py @@ -0,0 +1,20 @@ +from pathlib import Path + +from . import cli_runner_invoke + + +def test_cli_execute_script(): + output_folder_path = Path("./tests/output_B") + + db_name = "database_test_cli_execute_script" + cli_runner_invoke( + [ + "--env-folder=%s" % output_folder_path, + "run", + "--step=1", + "--database=%s" % db_name, + "--init-modules=base,product", + "--stop-after-init", + ] + ) + # TODO, add manually script diff --git a/tests/cli_B_03_upgrade_test.py b/tests/cli_B_05_upgrade_test.py similarity index 100% rename from tests/cli_B_03_upgrade_test.py rename to tests/cli_B_05_upgrade_test.py