[ADD] analyse-workload (2/2) WIP
This commit is contained in:
parent
c5da069c42
commit
44fd15b45c
|
|
@ -22,6 +22,8 @@ from odoo_openupgrade_wizard.tools_system import (
|
|||
def estimate_workload(ctx, analysis_file_path):
|
||||
# Analyse
|
||||
analysis = Analysis(ctx)
|
||||
analysis.analyse_module_version(ctx)
|
||||
analysis.analyse_openupgrade_state(ctx)
|
||||
|
||||
# Make some clean to display properly
|
||||
analysis.modules = sorted(analysis.modules)
|
||||
|
|
@ -30,7 +32,7 @@ def estimate_workload(ctx, analysis_file_path):
|
|||
# TODO, make
|
||||
ensure_file_exists_from_template(
|
||||
Path(analysis_file_path),
|
||||
templates.ANALYSIS_TEMPLATE,
|
||||
templates.ANALYSIS_HTML_TEMPLATE,
|
||||
ctx=ctx,
|
||||
analysis=analysis,
|
||||
current_date=datetime.now().strftime("%d/%m/%Y %H:%M:%S"),
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@ def releases_options(function):
|
|||
"--releases",
|
||||
type=str,
|
||||
help="Coma-separated values of odoo releases for which"
|
||||
" you want to perform the operation.",
|
||||
" you want to perform the operation."
|
||||
" Let empty to perform the operation on all the releases"
|
||||
" of the project",
|
||||
)(function)
|
||||
return function
|
||||
|
||||
|
|
|
|||
|
|
@ -228,3 +228,32 @@ def generate_analysis_files(
|
|||
|
||||
logger.info("> Launch analysis. This can take a while ...")
|
||||
analysis.analyze()
|
||||
|
||||
|
||||
def get_apriori_file_relative_path(migration_step: dict) -> (str, Path):
|
||||
"""Return the module name and the relative file path of
|
||||
the apriori.py file that contains all the rename and
|
||||
the merge information for a given upgrade."""
|
||||
if migration_step["release"] < 14.0:
|
||||
return ("openupgrade_records", Path("lib/apriori.py"))
|
||||
else:
|
||||
return ("openupgrade_scripts", Path("apriori.py"))
|
||||
|
||||
|
||||
def get_coverage_relative_path(migration_step: dict) -> (str, Path):
|
||||
"""Return the path of the coverage file."""
|
||||
if migration_step["release"] < 10.0:
|
||||
base_path = Path("src/openupgrade/openerp/openupgrade/doc/source")
|
||||
elif migration_step["release"] < 14.0:
|
||||
base_path = Path("src/openupgrade/odoo/openupgrade/doc/source")
|
||||
else:
|
||||
base_path = Path("src/openupgrade/docsource")
|
||||
|
||||
previous_release = migration_step["release"] - 1
|
||||
return base_path / Path(
|
||||
"modules%s-%s.rst"
|
||||
% (
|
||||
("%.1f" % previous_release).replace(".", ""),
|
||||
("%.1f" % migration_step["release"]).replace(".", ""),
|
||||
)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -126,13 +126,18 @@ GIT_IGNORE_CONTENT = """
|
|||
!.gitignore
|
||||
"""
|
||||
|
||||
# TODO, this value are usefull for test for analyse between 13 and 14.
|
||||
# move that values in data/extra_script/modules.csv
|
||||
# and let this template with only 'base' module.
|
||||
MODULES_CSV_TEMPLATE = """
|
||||
base,Base
|
||||
account,Account Module
|
||||
web_responsive,Web Responsive Module
|
||||
account_facturx,Account Factur X
|
||||
account_bank_statement_import, Account Bank Statement Import
|
||||
"""
|
||||
|
||||
ANALYSIS_TEMPLATE = """
|
||||
ANALYSIS_HTML_TEMPLATE = """
|
||||
<html>
|
||||
<body>
|
||||
<h1>Migration Analysis</h1>
|
||||
|
|
@ -154,19 +159,71 @@ ANALYSIS_TEMPLATE = """
|
|||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<br/><hr/><br/>
|
||||
<table border="1" width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th> - </th>
|
||||
<th> </th>
|
||||
{%- for odoo_version in ctx.obj["config"]["odoo_versions"] -%}
|
||||
<th>{{ odoo_version["release"] }}</th>
|
||||
{% endfor %}
|
||||
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{%- for odoo_module in analysis.modules -%}
|
||||
{% set ns = namespace(
|
||||
current_repository='',
|
||||
current_module_type='',
|
||||
) %}
|
||||
{% for odoo_module in analysis.modules %}
|
||||
|
||||
<!-- ---------------------- -->
|
||||
<!-- Handle New Module Type -->
|
||||
<!-- ---------------------- -->
|
||||
|
||||
{% if (
|
||||
ns.current_module_type != odoo_module.module_type
|
||||
and odoo_module.module_type != 'odoo') %}
|
||||
{% set ns.current_module_type = odoo_module.module_type %}
|
||||
<tr>
|
||||
<td>{{odoo_module.name}} ({{odoo_module.module_type}})
|
||||
<th colspan="{{1 + ctx.obj["config"]["odoo_versions"]|length}}">
|
||||
{{ ns.current_module_type}}
|
||||
</th>
|
||||
<tr>
|
||||
{% endif %}
|
||||
|
||||
<!-- -------------------- -->
|
||||
<!-- Handle New Repository-->
|
||||
<!-- -------------------- -->
|
||||
|
||||
{% if ns.current_repository != odoo_module.repository %}
|
||||
{% set ns.current_repository = odoo_module.repository %}
|
||||
<tr>
|
||||
<th colspan="{{1 + ctx.obj["config"]["odoo_versions"]|length}}">
|
||||
{{ ns.current_repository}}
|
||||
</th>
|
||||
<tr>
|
||||
{% endif %}
|
||||
|
||||
<!-- -------------------- -->
|
||||
<!-- Display Module Line -->
|
||||
<!-- -------------------- -->
|
||||
|
||||
<tr>
|
||||
<td>{{odoo_module.name}}
|
||||
</td>
|
||||
{% for release in odoo_module.analyse.all_releases %}
|
||||
{% set module_version = odoo_module.get_module_version(release) %}
|
||||
{% if module_version %}
|
||||
<td style="background-color:{{module_version.get_bg_color()}};">
|
||||
{{module_version.get_text()}}
|
||||
</td>
|
||||
{% else %}
|
||||
<td style="background-color:gray;"> </td>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</tr>
|
||||
|
||||
{% endfor %}
|
||||
|
||||
</tbody>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,14 @@
|
|||
import importlib
|
||||
from functools import total_ordering
|
||||
from pathlib import Path
|
||||
|
||||
from git import Repo
|
||||
from loguru import logger
|
||||
|
||||
from odoo_openupgrade_wizard.configuration_version_dependant import (
|
||||
get_apriori_file_relative_path,
|
||||
get_coverage_relative_path,
|
||||
)
|
||||
from odoo_openupgrade_wizard.tools_odoo import (
|
||||
get_odoo_addons_path,
|
||||
get_odoo_env_path,
|
||||
|
|
@ -11,78 +17,306 @@ from odoo_openupgrade_wizard.tools_odoo import (
|
|||
|
||||
|
||||
class Analysis(object):
|
||||
|
||||
modules = []
|
||||
|
||||
def __init__(self, ctx):
|
||||
module_names = get_odoo_modules_from_csv(ctx.obj["module_file_path"])
|
||||
|
||||
initial_release = ctx.obj["config"]["odoo_versions"][0]["release"]
|
||||
self.modules = []
|
||||
self.initial_release = ctx.obj["config"]["odoo_versions"][0]["release"]
|
||||
self.final_release = ctx.obj["config"]["odoo_versions"][-1]["release"]
|
||||
self.all_releases = [
|
||||
x["release"] for x in ctx.obj["config"]["odoo_versions"]
|
||||
]
|
||||
|
||||
# Instanciate a new odoo_module
|
||||
for module_name in module_names:
|
||||
repository_name = OdooModule.find_repository(
|
||||
ctx, module_name, initial_release
|
||||
|
||||
addon_path = OdooModule.get_addon_path(
|
||||
ctx, module_name, self.initial_release
|
||||
)
|
||||
if (
|
||||
repository_name
|
||||
and "%s.%s" % (repository_name, module_name)
|
||||
not in self.modules
|
||||
):
|
||||
if addon_path:
|
||||
repository_name = OdooModule.get_repository_name(addon_path)
|
||||
if (
|
||||
"%s.%s" % (repository_name, module_name)
|
||||
not in self.modules
|
||||
):
|
||||
logger.debug(
|
||||
"Discovering module '%s' in %s for release %s"
|
||||
% (module_name, repository_name, self.initial_release)
|
||||
)
|
||||
self.modules.append(
|
||||
OdooModule(ctx, self, module_name, repository_name)
|
||||
)
|
||||
else:
|
||||
raise ValueError(
|
||||
"The module %s has not been found in the release %s."
|
||||
"Analyse can not be done."
|
||||
% (module_name, self.initial_release)
|
||||
)
|
||||
|
||||
def analyse_module_version(self, ctx):
|
||||
self._generate_module_version_first_release(ctx)
|
||||
|
||||
for count in range(len(self.all_releases) - 1):
|
||||
previous_release = self.all_releases[count]
|
||||
current_release = self.all_releases[count + 1]
|
||||
self._generate_module_version_next_release(
|
||||
ctx, previous_release, current_release
|
||||
)
|
||||
|
||||
def analyse_openupgrade_state(self, ctx):
|
||||
logger.info("Parsing openupgrade module coverage for each migration.")
|
||||
coverage_analysis = {}
|
||||
for release in self.all_releases[1:]:
|
||||
coverage_analysis[release] = {}
|
||||
relative_path = get_coverage_relative_path({"release": release})
|
||||
env_folder_path = get_odoo_env_path(ctx, {"release": release})
|
||||
coverage_path = env_folder_path / relative_path
|
||||
with open(coverage_path) as f:
|
||||
lines = f.readlines()
|
||||
for line in [x for x in lines if "|" in x]:
|
||||
clean_line = (
|
||||
line.replace("\n", "")
|
||||
.replace("|del|", "")
|
||||
.replace("|new|", "")
|
||||
)
|
||||
splited_line = [x.strip() for x in clean_line.split("|") if x]
|
||||
if len(splited_line) == 2:
|
||||
coverage_analysis[release][splited_line[0]] = splited_line[
|
||||
1
|
||||
]
|
||||
if len(splited_line) == 3:
|
||||
coverage_analysis[release][splited_line[0]] = (
|
||||
splited_line[1] + " " + splited_line[2]
|
||||
).strip()
|
||||
elif len(splited_line) > 3:
|
||||
raise ValueError(
|
||||
"Incorrect value in openupgrade analysis file %s"
|
||||
" for line %s" % (coverage_path, line)
|
||||
)
|
||||
|
||||
for odoo_module in filter(
|
||||
lambda x: x.module_type == "odoo", self.modules
|
||||
):
|
||||
odoo_module.analyse_openupgrade_state(coverage_analysis)
|
||||
|
||||
def _generate_module_version_first_release(self, ctx):
|
||||
logger.info(
|
||||
"Analyse version %s. (First Release)" % self.initial_release
|
||||
)
|
||||
for odoo_module in self.modules:
|
||||
# Get new name of the module
|
||||
new_name = odoo_module.name
|
||||
|
||||
addon_path = OdooModule.get_addon_path(
|
||||
ctx, new_name, self.initial_release
|
||||
)
|
||||
|
||||
new_module_version = OdooModuleVersion(
|
||||
self.initial_release, odoo_module, addon_path
|
||||
)
|
||||
odoo_module.module_versions.update(
|
||||
{self.initial_release: new_module_version}
|
||||
)
|
||||
|
||||
def _generate_module_version_next_release(
|
||||
self, ctx, previous_release, current_release
|
||||
):
|
||||
logger.info(
|
||||
"Analyse change between %s and %s"
|
||||
% (previous_release, current_release)
|
||||
)
|
||||
# Get changes between the two releases
|
||||
(
|
||||
apriori_module_name,
|
||||
apriori_relative_path,
|
||||
) = get_apriori_file_relative_path({"release": current_release})
|
||||
apriori_module_path = OdooModule.get_addon_path(
|
||||
ctx, apriori_module_name, current_release
|
||||
)
|
||||
apriori_absolute_path = (
|
||||
apriori_module_path
|
||||
/ Path(apriori_module_name)
|
||||
/ apriori_relative_path
|
||||
)
|
||||
|
||||
module_spec = importlib.util.spec_from_file_location(
|
||||
"package", str(apriori_absolute_path)
|
||||
)
|
||||
module = importlib.util.module_from_spec(module_spec)
|
||||
module_spec.loader.exec_module(module)
|
||||
|
||||
renamed_modules = module.renamed_modules
|
||||
merged_modules = module.merged_modules
|
||||
|
||||
for odoo_module in self.modules:
|
||||
state = False
|
||||
new_module_name = False
|
||||
if odoo_module.name in renamed_modules:
|
||||
state = "renamed"
|
||||
new_module_name = renamed_modules[odoo_module.name]
|
||||
logger.debug(
|
||||
"Discovering module '%s' in %s for release %s"
|
||||
% (module_name, repository_name, initial_release)
|
||||
"%s -> %s : %s renamed into %s"
|
||||
% (
|
||||
previous_release,
|
||||
current_release,
|
||||
odoo_module.name,
|
||||
new_module_name,
|
||||
)
|
||||
)
|
||||
self.modules.append(
|
||||
OdooModule(ctx, module_name, repository_name)
|
||||
elif odoo_module.name in merged_modules:
|
||||
state = "merged"
|
||||
new_module_name = merged_modules[odoo_module.name]
|
||||
logger.debug(
|
||||
"%s -> %s : %s merged into %s"
|
||||
% (
|
||||
previous_release,
|
||||
current_release,
|
||||
odoo_module.name,
|
||||
new_module_name,
|
||||
)
|
||||
)
|
||||
|
||||
# Handle new module
|
||||
if state and new_module_name != odoo_module.name:
|
||||
# Ensure that the module exists in self.modules
|
||||
new_addon_path = OdooModule.get_addon_path(
|
||||
ctx, new_module_name, current_release
|
||||
)
|
||||
if not new_addon_path:
|
||||
raise ValueError(
|
||||
"The module %s has not been found in the release %s."
|
||||
" Analyse can not be done."
|
||||
% (new_module_name, current_release)
|
||||
)
|
||||
else:
|
||||
new_repository_name = OdooModule.get_repository_name(
|
||||
new_addon_path
|
||||
)
|
||||
if (
|
||||
"%s.%s" % (new_repository_name, new_module_name)
|
||||
not in self.modules
|
||||
):
|
||||
logger.debug(
|
||||
"Discovering module '%s' in %s for release %s"
|
||||
% (
|
||||
new_module_name,
|
||||
new_repository_name,
|
||||
current_release,
|
||||
)
|
||||
)
|
||||
new_odoo_module = OdooModule(
|
||||
ctx, self, new_module_name, new_repository_name
|
||||
)
|
||||
self.modules.append(new_odoo_module)
|
||||
new_odoo_module.module_versions.update(
|
||||
{
|
||||
current_release: OdooModuleVersion(
|
||||
current_release,
|
||||
new_odoo_module,
|
||||
new_addon_path,
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
# Get the previous release of the module
|
||||
previous_module_version = odoo_module.get_module_version(
|
||||
previous_release
|
||||
)
|
||||
# if the previous release has been renamed or merged
|
||||
# the loss is normal
|
||||
if previous_module_version and previous_module_version.state in [
|
||||
"merged",
|
||||
"renamed",
|
||||
"normal_loss",
|
||||
]:
|
||||
state = "normal_loss"
|
||||
|
||||
new_addon_path = OdooModule.get_addon_path(
|
||||
ctx, odoo_module.name, current_release
|
||||
)
|
||||
odoo_module.module_versions.update(
|
||||
{
|
||||
current_release: OdooModuleVersion(
|
||||
current_release,
|
||||
odoo_module,
|
||||
new_addon_path,
|
||||
state=state,
|
||||
target_module=new_module_name,
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@total_ordering
|
||||
class OdooModule(object):
|
||||
|
||||
active = True
|
||||
name = False
|
||||
repository = False
|
||||
module_type = False
|
||||
unique_name = False
|
||||
|
||||
@classmethod
|
||||
def find_repository(cls, ctx, module_name, current_release):
|
||||
|
||||
# Try to find the repository that contains the module
|
||||
main_path = get_odoo_env_path(ctx, {"release": current_release})
|
||||
addons_path = get_odoo_addons_path(
|
||||
ctx, main_path, {"release": current_release, "action": "update"}
|
||||
)
|
||||
for addon_path in addons_path:
|
||||
if (addon_path / module_name).exists():
|
||||
|
||||
if str(addon_path).endswith("odoo/odoo/addons"):
|
||||
path = addon_path.parent.parent
|
||||
elif str(addon_path).endswith("odoo/addons"):
|
||||
path = addon_path.parent
|
||||
else:
|
||||
path = addon_path
|
||||
repo = Repo(str(path))
|
||||
repository_name = repo.remotes[0].url.replace(
|
||||
"https://github.com/", ""
|
||||
)
|
||||
|
||||
return repository_name
|
||||
|
||||
return False
|
||||
|
||||
def __init__(self, ctx, module_name, repository_name):
|
||||
def __init__(self, ctx, analyse, module_name, repository_name):
|
||||
self.analyse = analyse
|
||||
self.name = module_name
|
||||
self.repository = repository_name
|
||||
self.unique_name = "%s.%s" % (repository_name, module_name)
|
||||
self.module_versions = {}
|
||||
if repository_name == "odoo/odoo":
|
||||
self.module_type = "odoo"
|
||||
elif repository_name.startswith("OCA"):
|
||||
self.module_type = "OCA"
|
||||
else:
|
||||
self.module_type = "custom"
|
||||
self.unique_name = "%s.%s" % (repository_name, module_name)
|
||||
|
||||
def get_module_version(self, current_release):
|
||||
res = self.module_versions.get(current_release, False)
|
||||
return res
|
||||
|
||||
def analyse_openupgrade_state(self, coverage_analysis):
|
||||
for module_version in list(self.module_versions.values()):
|
||||
module_version.analyse_openupgrade_state(coverage_analysis)
|
||||
|
||||
@classmethod
|
||||
def get_addon_path(cls, ctx, module_name, current_release):
|
||||
"""Search the module in all the addons path of the current release
|
||||
and return the addon path of the module, or False if not found.
|
||||
For exemple find_repository(ctx, 'web_responsive', 12.0)
|
||||
'/PATH_TO_LOCAL_ENV/src/OCA/web'
|
||||
"""
|
||||
# Try to find the repository that contains the module
|
||||
main_path = get_odoo_env_path(ctx, {"release": current_release})
|
||||
addons_path = get_odoo_addons_path(
|
||||
ctx, main_path, {"release": current_release, "action": "upgrade"}
|
||||
)
|
||||
for addon_path in addons_path:
|
||||
if (addon_path / module_name).exists():
|
||||
return addon_path
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def get_repository_name(cls, addon_path):
|
||||
"""Given an addons path that contains odoo modules in a folder
|
||||
that has been checkouted via git, return a repository name with the
|
||||
following format org_name/repo_name.
|
||||
For exemple 'OCA/web' or 'odoo/odoo'
|
||||
"""
|
||||
# TODO, make the code cleaner and more resiliant
|
||||
# for the time being, the code will fail for
|
||||
# - github url set with git+http...
|
||||
# - gitlab url
|
||||
# - if odoo code is not in a odoo folder in the repos.yml file...
|
||||
if str(addon_path).endswith("odoo/odoo/addons") or str(
|
||||
addon_path
|
||||
).endswith("openupgrade/odoo/addons"):
|
||||
path = addon_path.parent.parent
|
||||
elif str(addon_path).endswith("odoo/addons") or str(
|
||||
addon_path
|
||||
).endswith("openupgrade/addons"):
|
||||
path = addon_path.parent
|
||||
else:
|
||||
path = addon_path
|
||||
repo = Repo(str(path))
|
||||
repository_name = repo.remotes[0].url.replace(
|
||||
"https://github.com/", ""
|
||||
)
|
||||
if repository_name.lower() == "oca/openupgrade":
|
||||
return "odoo/odoo"
|
||||
else:
|
||||
return repository_name
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, str):
|
||||
|
|
@ -94,9 +328,109 @@ class OdooModule(object):
|
|||
if self.module_type != other.module_type:
|
||||
if self.module_type == "odoo":
|
||||
return True
|
||||
elif self.module_type == "OCA" and self.module_type == "custom":
|
||||
elif self.module_type == "OCA" and other.module_type == "custom":
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
elif self.repository != other.repository:
|
||||
return self.repository < other.repository
|
||||
else:
|
||||
return self.name < other.name
|
||||
|
||||
def __str__(self):
|
||||
return "%s - %s" % (self.unique_name, self.module_type)
|
||||
|
||||
|
||||
class OdooModuleVersion(object):
|
||||
def __init__(
|
||||
self,
|
||||
release,
|
||||
odoo_module,
|
||||
addon_path,
|
||||
state=False,
|
||||
target_module=False,
|
||||
):
|
||||
self.release = release
|
||||
self.odoo_module = odoo_module
|
||||
self.addon_path = addon_path
|
||||
self.state = state
|
||||
self.target_module = target_module
|
||||
self.openupgrade_state = ""
|
||||
|
||||
def analyse_openupgrade_state(self, coverage_analysis):
|
||||
if self.release == self.odoo_module.analyse.initial_release:
|
||||
return
|
||||
self.openupgrade_state = coverage_analysis[self.release].get(
|
||||
self.odoo_module.name, False
|
||||
)
|
||||
|
||||
def get_bg_color(self):
|
||||
if self.addon_path:
|
||||
if (
|
||||
self.odoo_module.module_type == "odoo"
|
||||
and self.release != self.odoo_module.analyse.initial_release
|
||||
):
|
||||
if self.openupgrade_state and (
|
||||
self.openupgrade_state.lower().startswith("done")
|
||||
or self.openupgrade_state.lower().startswith(
|
||||
"nothing to do"
|
||||
)
|
||||
):
|
||||
return "lightgreen"
|
||||
else:
|
||||
return "orange"
|
||||
return "lightgreen"
|
||||
else:
|
||||
# The module doesn't exist in the current release
|
||||
if self.state in ["merged", "renamed", "normal_loss"]:
|
||||
# Normal case, the previous version has been renamed
|
||||
# or merged
|
||||
return "lightgray"
|
||||
|
||||
if self.odoo_module.module_type == "odoo":
|
||||
# A core module disappeared and has not been merged
|
||||
# or renamed
|
||||
return "red"
|
||||
elif self.release != self.odoo_module.analyse.final_release:
|
||||
return "lightgray"
|
||||
else:
|
||||
return "orange"
|
||||
|
||||
def get_text(self):
|
||||
if self.addon_path:
|
||||
if (
|
||||
self.odoo_module.module_type == "odoo"
|
||||
and self.release != self.odoo_module.analyse.initial_release
|
||||
):
|
||||
if self.openupgrade_state.lower().startswith(
|
||||
"done"
|
||||
) or self.openupgrade_state.lower().startswith(
|
||||
"nothing to do"
|
||||
):
|
||||
return self.openupgrade_state
|
||||
else:
|
||||
return "To analyse"
|
||||
return ""
|
||||
else:
|
||||
if self.state == "merged":
|
||||
return "Merged into %s" % self.target_module
|
||||
elif self.state == "renamed":
|
||||
return "Renamed into %s" % self.target_module
|
||||
elif self.state == "normal_loss":
|
||||
return ""
|
||||
|
||||
if self.odoo_module.module_type == "odoo":
|
||||
# A core module disappeared and has not been merged
|
||||
# or renamed
|
||||
return "Module lost"
|
||||
elif self.release != self.odoo_module.analyse.final_release:
|
||||
return "Unported"
|
||||
else:
|
||||
return "To port"
|
||||
|
||||
def __str__(self):
|
||||
return "%s - %s - %s" % (
|
||||
self.odoo_module.name,
|
||||
self.release,
|
||||
self.addon_path,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@ def test_cli_init():
|
|||
"--project-name=test-cli",
|
||||
"--initial-release=13.0",
|
||||
"--final-release=14.0",
|
||||
"--extra-repository=OCA/web,OCA/server-tools",
|
||||
"--extra-repository="
|
||||
"OCA/web,OCA/server-tools,OCA/bank-statement-import",
|
||||
]
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user