[UPD] script show_evolution_module: compare CSV information

- fix odoo_odoo addons to include test
- add option to force fetch.
- add check uninstall module
- add stat unique module
This commit is contained in:
Mathieu Benoit 2023-02-19 23:03:43 -05:00
parent d6f652f58c
commit 8dd49e4447

View file

@ -5,6 +5,7 @@ import logging
import os import os
import shutil import shutil
import sys import sys
import csv
from collections import defaultdict from collections import defaultdict
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
@ -36,7 +37,7 @@ IGNORE_REPO_LIST = (
"https://github.com/ERPLibre/ERPLibre_image_db.git", "https://github.com/ERPLibre/ERPLibre_image_db.git",
"https://github.com/muk-it/muk_docs.git", "https://github.com/muk-it/muk_docs.git",
) )
DCT_CHANGE_ADDONS_PATH = {"odoo_odoo": "/addons/"} DCT_CHANGE_ADDONS_PATH = {"odoo_odoo": ["/addons/", "/odoo/addons/"]}
DCT_VERSION_RELEASE = { DCT_VERSION_RELEASE = {
"1.0": datetime.datetime.strptime("2005-02-01", "%Y-%m-%d").date(), "1.0": datetime.datetime.strptime("2005-02-01", "%Y-%m-%d").date(),
"2.0": datetime.datetime.strptime("2005-03-01", "%Y-%m-%d").date(), "2.0": datetime.datetime.strptime("2005-03-01", "%Y-%m-%d").date(),
@ -56,6 +57,7 @@ DCT_VERSION_RELEASE = {
"15.0": datetime.datetime.strptime("2021-10-01", "%Y-%m-%d").date(), "15.0": datetime.datetime.strptime("2021-10-01", "%Y-%m-%d").date(),
"16.0": datetime.datetime.strptime("2022-10-01", "%Y-%m-%d").date(), "16.0": datetime.datetime.strptime("2022-10-01", "%Y-%m-%d").date(),
} }
CSV_HEADER_MODULE_NAME = "Nom technique"
# TODO use rich progress bar when clone # TODO use rich progress bar when clone
# TODO support conflict repo name # TODO support conflict repo name
@ -100,6 +102,11 @@ def get_config():
f" parallelism with asyncio" f" parallelism with asyncio"
), ),
) )
parser.add_argument(
"--force_git_fetch",
action="store_true",
help=f"Force git fetch to update it all remote.",
)
parser.add_argument( parser.add_argument(
"-p", "-p",
"--max_process", "--max_process",
@ -142,6 +149,14 @@ def get_config():
default="6.1,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0,16.0", default="6.1,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0,16.0",
help="Branch to analyse, separate by ','", help="Branch to analyse, separate by ','",
) )
parser.add_argument(
"--compare_csv",
help=(
"Path of CSV, search column 'Nom technique' and give list of"
" difference module, missing from CSV. Need only 1 branches and no"
" more_year."
),
)
args = parser.parse_args() args = parser.parse_args()
die( die(
@ -169,6 +184,16 @@ def get_config():
"The params branches contain not supported version, check" "The params branches contain not supported version, check"
f" DCT_VERSION_RELEASE : {list(DCT_VERSION_RELEASE.keys())}", f" DCT_VERSION_RELEASE : {list(DCT_VERSION_RELEASE.keys())}",
) )
die(
args.compare_csv
and (args.more_year > 0 or len(args.branches.split(",")) > 1),
f"When use param compare_csv, cannot use more_year and only 1 branch.",
)
if args.compare_csv:
die(
not os.path.isfile(args.compare_csv),
f"Path of {args.compare_csv} need to be a file path.",
)
return args return args
@ -176,7 +201,8 @@ def main():
config = get_config() config = get_config()
lst_branch = config.branches.split(",") lst_branch = config.branches.split(",")
before_date = config.before_date before_date = config.before_date
lst_stat = [] lst_unique_module = set()
lst_unique_uninstallable_module = set()
# Check # Check
die( die(
@ -199,7 +225,10 @@ def main():
# Clone all repo # Clone all repo
_logger.info(f"Clone repo") _logger.info(f"Clone repo")
lst_task_clone = [clone_repo(i, a) for i, a in enumerate(lst_repo_url)] lst_task_clone = [
clone_repo(i, a, config.force_git_fetch)
for i, a in enumerate(lst_repo_url)
]
lst_repo_path = lib_asyncio.execute( lst_repo_path = lib_asyncio.execute(
config, lst_task_clone, use_uvloop=True config, lst_task_clone, use_uvloop=True
) )
@ -248,15 +277,22 @@ def main():
tpl_result = lib_asyncio.execute(config, lst_task, use_uvloop=True) tpl_result = lib_asyncio.execute(config, lst_task, use_uvloop=True)
_logger.info("Analyse information") _logger.info("Analyse information")
dct_result = defaultdict(lambda: defaultdict(int)) dct_result = defaultdict(lambda: defaultdict(int))
dct_result_unique = defaultdict(set)
for lst_result_stack in tpl_result: for lst_result_stack in tpl_result:
for dct_result_module in lst_result_stack: for dct_result_module in lst_result_stack:
# lst_module, branch, path, repo, before_date # lst_module, branch, path, repo, before_date
before_date = dct_result_module.get("before_date") before_date = dct_result_module.get("before_date")
lst_module = dct_result_module.get("lst_module") lst_module = dct_result_module.get("lst_module")
lst_uninstallable_module = dct_result_module.get(
"lst_uninstallable_module"
)
branch = dct_result_module.get("branch") branch = dct_result_module.get("branch")
# path = dct_result_module.get("path") # path = dct_result_module.get("path")
# repo = dct_result_module.get("repo") # repo = dct_result_module.get("repo")
dct_result[before_date][branch] += len(lst_module) dct_result[before_date][branch] += len(lst_module)
dct_result_unique[before_date].update(lst_module)
lst_unique_module.update(lst_module)
lst_unique_uninstallable_module.update(lst_uninstallable_module)
# Show result # Show result
_logger.info("Show result") _logger.info("Show result")
@ -267,8 +303,43 @@ def main():
print(f"Stat nb module by branch name{str_extra}") print(f"Stat nb module by branch name{str_extra}")
for branch_name, count_module in dct_branch_result.items(): for branch_name, count_module in dct_branch_result.items():
print(f"{branch_name}\t{count_module}") print(f"{branch_name}\t{count_module}")
for before_date, set_result in dct_result_unique.items():
str_extra = ""
if before_date:
str_extra = f" before {before_date}"
print(f"Diff nb unique module{str_extra}, length {len(set_result)}")
print("end of stat") print("end of stat")
if config.compare_csv:
index_header = -1
lst_unique_module_csv = set()
with open(config.compare_csv, "r") as csvfile:
for csv_module in csv.reader(csvfile):
if index_header == -1:
try:
index_header = csv_module.index(CSV_HEADER_MODULE_NAME)
except Exception as e:
_logger.error(
f"Missing header {CSV_HEADER_MODULE_NAME} in CSV."
)
raise e
else:
module_name = csv_module[index_header]
if module_name not in lst_unique_uninstallable_module:
lst_unique_module_csv.add(module_name)
lst_missing_module_repo = lst_unique_module_csv.difference(
lst_unique_module
)
lst_missing_module_csv = lst_unique_module.difference(
lst_unique_module_csv
)
print("CSV compare")
print(f"Module missing from CSV '{len(lst_missing_module_repo)}':")
print(lst_missing_module_repo)
print(f"Module missing into CSV '{len(lst_missing_module_csv)}':")
print(lst_missing_module_csv)
def die(cond, message, code=1): def die(cond, message, code=1):
if cond: if cond:
@ -318,76 +389,84 @@ async def extract_module(lst_branch, repo, path, before_date):
commit = commit.strip() commit = commit.strip()
# List directory
suffix_path = DCT_CHANGE_ADDONS_PATH.get(repo, "")
adapt_path = path + suffix_path
lst_args = ["git", "ls-tree", "-d", "--name-only", commit]
(
str_folders,
_,
status,
) = await lib_asyncio.run_command_get_output_and_status(
*lst_args, cwd=adapt_path
)
if status:
_logger.error(f"Receive status 'git ls-tree' {status}")
continue
# TODO send msg when no result
if not str_folders:
continue
lst_module = str_folders.split()
if not lst_module:
continue
if suffix_path:
suffix_path = suffix_path[1:]
lst_module_installable = [] lst_module_installable = []
for module in lst_module: lst_module_uninstallable = []
# List directory # List directory
lst_args = [ lst_suffix_path = DCT_CHANGE_ADDONS_PATH.get(repo, "")
"git", if type(lst_suffix_path) is str:
"cat-file", lst_suffix_path = [lst_suffix_path]
"-p", for suffix_path in lst_suffix_path:
f"{commit}:{suffix_path}{module}/__manifest__.py", adapt_path = path + suffix_path
] lst_args = ["git", "ls-tree", "-d", "--name-only", commit]
( (
manifest, str_folders,
_, _,
status, status,
) = await lib_asyncio.run_command_get_output_and_status( ) = await lib_asyncio.run_command_get_output_and_status(
*lst_args, cwd=path *lst_args, cwd=adapt_path
) )
if status: if status:
# Maybe __openerp__.py _logger.error(f"Receive status 'git ls-tree' {status}")
continue
# TODO send msg when no result
if not str_folders:
continue
lst_module = str_folders.split()
if not lst_module:
continue
if suffix_path:
suffix_path = suffix_path[1:]
for module in lst_module:
# List directory
lst_args = [ lst_args = [
"git", "git",
"cat-file", "cat-file",
"-p", "-p",
f"{commit}:{module}/__openerp__.py", f"{commit}:{suffix_path}{module}/__manifest__.py",
] ]
( (
manifest, manifest,
_, _,
status, status,
) = await lib_asyncio.run_command_get_output_and_status( ) = await lib_asyncio.run_command_get_output_and_status(
*lst_args, cwd=adapt_path *lst_args, cwd=path
) )
if status: if status:
# Ignore, it's not a module # Maybe __openerp__.py
# _logger.error(f"Receive status 'git cat-file' {status}") lst_args = [
# return return_value "git",
continue "cat-file",
dct_manifest = eval(manifest + "\n") "-p",
if dct_manifest.get("installable", True): f"{commit}:{module}/__openerp__.py",
lst_module_installable.append(module) ]
(
manifest,
_,
status,
) = await lib_asyncio.run_command_get_output_and_status(
*lst_args, cwd=adapt_path
)
if status:
# Ignore, it's not a module
# _logger.error(f"Receive status 'git cat-file' {status}")
# return return_value
continue
dct_manifest = eval(manifest + "\n")
if dct_manifest.get("installable", True):
lst_module_installable.append(module)
else:
lst_module_uninstallable.append(module)
return_value["lst_module"] = lst_module_installable return_value["lst_module"] = lst_module_installable
return_value["lst_uninstallable_module"] = lst_module_uninstallable
lst_result.append(return_value) lst_result.append(return_value)
return lst_result return lst_result
async def clone_repo(i, repo_url): async def clone_repo(i, repo_url, force_fetch):
split_repo_url = repo_url.split("/") split_repo_url = repo_url.split("/")
repo_name = f"{split_repo_url[-2]}_{split_repo_url[-1][:-4]}" repo_name = f"{split_repo_url[-2]}_{split_repo_url[-1][:-4]}"
repo_path = os.path.join(CACHE_CLONE_PATH, repo_name) repo_path = os.path.join(CACHE_CLONE_PATH, repo_name)
@ -396,6 +475,12 @@ async def clone_repo(i, repo_url):
"git", "clone", repo_url, repo_name, cwd=CACHE_CLONE_PATH "git", "clone", repo_url, repo_name, cwd=CACHE_CLONE_PATH
) )
_logger.info(f"[{i}]New clone {repo_path} with {repo_url}") _logger.info(f"[{i}]New clone {repo_path} with {repo_url}")
elif force_fetch:
await lib_asyncio.run_command_get_output(
"git", "fetch", "--all", cwd=CACHE_CLONE_PATH
)
_logger.info(f"[{i}]Fetch {repo_path} with {repo_url}")
return repo_name, repo_path return repo_name, repo_path