Merge branch 'develop'

- TODO support RobotLibre commands
- Format all ignore zip and __pycache__
- TODO config better support private configuration
This commit is contained in:
Mathieu Benoit 2025-11-11 05:15:56 -05:00
commit 2400f4e6be
6 changed files with 120 additions and 46 deletions

View file

@ -5,6 +5,7 @@
import json import json
import logging import logging
import os import os
from typing import Any, Dict, Literal, Mapping
CONFIG_FILE = "./script/todo/todo.json" CONFIG_FILE = "./script/todo/todo.json"
CONFIG_OVERRIDE_FILE = "./private/todo/todo_override.json" CONFIG_OVERRIDE_FILE = "./private/todo/todo_override.json"
@ -23,34 +24,74 @@ _logger = logging.getLogger(__name__)
class ConfigFile: class ConfigFile:
def get_config(self, lst_params): def get_config(self, key_param: str):
# Open file # Open file and update dct_data
config_file = CONFIG_FILE dct_data_init = {}
if os.path.exists(CONFIG_OVERRIDE_FILE): dct_data_second = {}
config_file = CONFIG_OVERRIDE_FILE dct_data_final = {}
if os.path.exists(CONFIG_FILE):
with open(CONFIG_FILE) as cfg:
dct_data_init = json.load(cfg)
if os.path.exists(CONFIG_OVERRIDE_FILE):
with open(CONFIG_OVERRIDE_FILE) as cfg:
dct_data_second = json.load(cfg)
find_in_private = False
if os.path.exists(CONFIG_OVERRIDE_PRIVATE_FILE): if os.path.exists(CONFIG_OVERRIDE_PRIVATE_FILE):
with open(CONFIG_OVERRIDE_PRIVATE_FILE) as cfg: with open(CONFIG_OVERRIDE_PRIVATE_FILE) as cfg:
dct_data = json.load(cfg) dct_data_final = json.load(cfg)
for param in lst_params:
if param in dct_data.keys():
find_in_private = True
dct_data = dct_data[param]
if not find_in_private: dct_data_first_merge = self.deep_merge_with_lists(
with open(config_file) as cfg: dct_data_init, dct_data_final, list_strategy="extend"
dct_data = json.load(cfg) )
for param in lst_params: dct_data = self.deep_merge_with_lists(
try: dct_data_first_merge, dct_data_second, list_strategy="extend"
dct_data = dct_data[param] )
except KeyError:
_logger.error( return dct_data.get(key_param)
f"KeyError on file {config_file} with keys"
f" {lst_params}" def get_config_value(self, lst_params: list):
) dct_data = self.get_config(lst_params[0])
return {} for param in lst_params[1:]:
if param in dct_data.keys():
find_in_private = True
dct_data = dct_data.get(param)
return dct_data return dct_data
def get_logo_ascii_file_path(self): def get_logo_ascii_file_path(self):
return LOGO_ASCII_FILE return LOGO_ASCII_FILE
def deep_merge_with_lists(
self,
dest: Mapping[str, Any],
src: Mapping[str, Any],
list_strategy: Literal["replace", "extend"] = "replace",
) -> Dict[str, Any]:
result: Dict[str, Any] = {}
for k, v in dest.items():
result[k] = v.copy() if isinstance(v, dict) else v
for k, v in src.items():
if (
k in result
and isinstance(result[k], dict)
and isinstance(v, dict)
):
result[k] = self.deep_merge_with_lists(
result[k], v, list_strategy
)
elif (
k in result
and isinstance(result[k], list)
and isinstance(v, list)
and list_strategy == "extend"
):
# on étend : dest_list + src_list
result[k] = result[k] + v
elif k in result and isinstance(result[k], str):
if v:
result[k] = v
else:
result[k] = v
return result

View file

@ -78,6 +78,13 @@ def get_modified_files():
) )
if has_space: if has_space:
file_path = file_path_space file_path = file_path_space
# Remove ignoring
if (
file_path.endswith(".zip")
or file_path.endswith(".tar.gz")
or file_path.endswith("__pycache__/")
):
continue
file_path = os.path.join(directory, file_path) file_path = os.path.join(directory, file_path)
except Exception as e: except Exception as e:

View file

@ -397,7 +397,9 @@ class SeleniumLib(object):
return self.kdbx return self.kdbx
print("Open KDBX") print("Open KDBX")
# Open file # Open file
chemin_fichier_kdbx = self.config_file.get_config(["kdbx", "path"]) chemin_fichier_kdbx = self.config_file.get_config_value(
["kdbx", "path"]
)
if not chemin_fichier_kdbx: if not chemin_fichier_kdbx:
root = tk.Tk() root = tk.Tk()
root.withdraw() # Hide the main window root.withdraw() # Hide the main window
@ -409,7 +411,9 @@ class SeleniumLib(object):
# _logger.error(f"KDBX is not configured, please fill {CONFIG_FILE}") # _logger.error(f"KDBX is not configured, please fill {CONFIG_FILE}")
return return
mot_de_passe_kdbx = self.config_file.get_config(["kdbx", "password"]) mot_de_passe_kdbx = self.config_file.get_config_value(
["kdbx", "password"]
)
if not mot_de_passe_kdbx: if not mot_de_passe_kdbx:
mot_de_passe_kdbx = getpass.getpass( mot_de_passe_kdbx = getpass.getpass(
prompt="Entrez votre mot de passe : " prompt="Entrez votre mot de passe : "

View file

@ -13,6 +13,16 @@
"prompt_description": "Test - Instance de base minimale", "prompt_description": "Test - Instance de base minimale",
"makefile_cmd": "db_restore_erplibre_base_db_test", "makefile_cmd": "db_restore_erplibre_base_db_test",
"database": "test" "database": "test"
},
{
"prompt_description": "Ouvrir RobotLibre \uD83E\uDD16 minimal",
"makefile_cmd": "robot_libre",
"database": "robotlibre"
},
{
"prompt_description": "Ouvrir RobotLibre \uD83E\uDD16 en activant la recherche",
"makefile_cmd": "robot_libre_all",
"database": "robotlibre"
} }
], ],
"function": [ "function": [

View file

@ -153,7 +153,9 @@ class TODO:
if self.kdbx: if self.kdbx:
return self.kdbx return self.kdbx
# Open file # Open file
chemin_fichier_kdbx = self.config_file.get_config(["kdbx", "path"]) chemin_fichier_kdbx = self.config_file.get_config_value(
["kdbx", "path"]
)
if not chemin_fichier_kdbx: if not chemin_fichier_kdbx:
root = tk.Tk() root = tk.Tk()
root.withdraw() # Hide the main window root.withdraw() # Hide the main window
@ -167,7 +169,9 @@ class TODO:
) )
return return
mot_de_passe_kdbx = self.config_file.get_config(["kdbx", "password"]) mot_de_passe_kdbx = self.config_file.get_config_value(
["kdbx", "password"]
)
if not mot_de_passe_kdbx: if not mot_de_passe_kdbx:
mot_de_passe_kdbx = getpass.getpass( mot_de_passe_kdbx = getpass.getpass(
prompt="Entrez votre mot de passe : " prompt="Entrez votre mot de passe : "
@ -191,7 +195,7 @@ class TODO:
kp = self.get_kdbx() kp = self.get_kdbx()
if not kp: if not kp:
return return
nom_configuration = self.config_file.get_config( nom_configuration = self.config_file.get_config_value(
["kdbx_config", "openai", "kdbx_key"] ["kdbx_config", "openai", "kdbx_key"]
) )
entry = kp.find_entries_by_title(nom_configuration, first=True) entry = kp.find_entries_by_title(nom_configuration, first=True)
@ -209,7 +213,7 @@ class TODO:
def prompt_execute(self): def prompt_execute(self):
help_info = """Commande : help_info = """Commande :
[1] Run - Exécuter et installer une instance [1] Run - Exécuter et installer une instance
[2] Exec - Automatisation - Démonstration des fonctions développées [2] Automatisation - Démonstration des fonctions développées
[3] Mise à jour - Update all developed staging source code [3] Mise à jour - Update all developed staging source code
[4] Code - Outil pour développeur [4] Code - Outil pour développeur
[5] Doc - Recherche de documentation [5] Doc - Recherche de documentation
@ -408,11 +412,16 @@ class TODO:
makefile_cmd = dct_instance.get("makefile_cmd") makefile_cmd = dct_instance.get("makefile_cmd")
if makefile_cmd and not ignore_makefile: if makefile_cmd and not ignore_makefile:
self.executer_commande_live( status = self.executer_commande_live(
f"make {makefile_cmd}", f"make {makefile_cmd}",
source_erplibre=False, source_erplibre=False,
single_source_erplibre=True, single_source_erplibre=True,
) )
if status:
_logger.error(
f"Status {status} - exit execute_from_configuration"
)
return
if exec_run_db: if exec_run_db:
db_name = dct_instance.get("database") db_name = dct_instance.get("database")
@ -440,7 +449,7 @@ class TODO:
# TODO proposer le déploiement à distance # TODO proposer le déploiement à distance
# TODO proposer l'exécution de docker # TODO proposer l'exécution de docker
# TODO proposer la création de docker # TODO proposer la création de docker
lst_instance = self.config_file.get_config(["instance"]) lst_instance = self.config_file.get_config("instance")
help_info = self.fill_help_info(lst_instance) help_info = self.fill_help_info(lst_instance)
while True: while True:
@ -469,7 +478,7 @@ class TODO:
print("Commande non trouvée 🤖!") print("Commande non trouvée 🤖!")
def prompt_execute_fonction(self): def prompt_execute_fonction(self):
lst_instance = self.config_file.get_config(["function"]) lst_instance = self.config_file.get_config("function")
help_info = self.fill_help_info(lst_instance) help_info = self.fill_help_info(lst_instance)
while True: while True:
@ -501,7 +510,7 @@ class TODO:
# TODO faire la mise à jour de ERPLibre # TODO faire la mise à jour de ERPLibre
# TODO faire l'upgrade d'un odoo vers un autre # TODO faire l'upgrade d'un odoo vers un autre
lst_instance = self.config_file.get_config(["update_from_makefile"]) lst_instance = self.config_file.get_config("update_from_makefile")
dct_upgrade_odoo_database = { dct_upgrade_odoo_database = {
"prompt_description": "Upgrade Odoo - Migration Database", "prompt_description": "Upgrade Odoo - Migration Database",
} }
@ -549,7 +558,7 @@ class TODO:
# [0] Retour # [0] Retour
# """ # """
lst_instance = self.config_file.get_config(["code_from_makefile"]) lst_instance = self.config_file.get_config("code_from_makefile")
dct_upgrade_odoo_database = { dct_upgrade_odoo_database = {
"prompt_description": "Upgrade Module", "prompt_description": "Upgrade Module",
} }
@ -785,7 +794,9 @@ class TODO:
with open("./.erplibre-version") as f: with open("./.erplibre-version") as f:
source_odoo = f.read() source_odoo = f.read()
if not source_odoo: if not source_odoo:
_logger.error(f"You cannot execute Odoo command if no version is installed. Command : {commande}") _logger.error(
f"You cannot execute Odoo command if no version is installed. Command : {commande}"
)
return -1 return -1
commande = ( commande = (
f"source ./.venv.{source_odoo}/bin/activate && {commande}" f"source ./.venv.{source_odoo}/bin/activate && {commande}"

View file

@ -76,17 +76,18 @@ class TodoUpgrade:
def execute_module_upgrade(self): def execute_module_upgrade(self):
print("Welcome to Odoo module upgrade processus with ERPLibre 🤖") print("Welcome to Odoo module upgrade processus with ERPLibre 🤖")
with open(UPGRADE_DATABASE_CONFIG_LOG, "r") as f: if os.path.exists(UPGRADE_DATABASE_CONFIG_LOG):
try: with open(UPGRADE_DATABASE_CONFIG_LOG, "r") as f:
old_dct_progression = json.load(f) try:
self.dct_progression = old_dct_progression old_dct_progression = json.load(f)
self.lst_command_executed = old_dct_progression.get( self.dct_progression = old_dct_progression
"command_executed" self.lst_command_executed = old_dct_progression.get(
) "command_executed"
except json.decoder.JSONDecodeError: )
print( except json.decoder.JSONDecodeError:
f'⚠️ The config file "{UPGRADE_DATABASE_CONFIG_LOG}" is invalid, ignore it.' print(
) f'⚠️ The config file "{UPGRADE_DATABASE_CONFIG_LOG}" is invalid, ignore it.'
)
print( print(
"Migrate a directory repo to migrate all module, or select a directory module." "Migrate a directory repo to migrate all module, or select a directory module."