Integrate claude, improve selenium and support qemu #1

Open
mathben wants to merge 224 commits from develop into master
3 changed files with 110 additions and 5 deletions
Showing only changes of commit 7d96b56fb4 - Show all commits

View file

@ -879,12 +879,12 @@ class TODO:
{"prompt_description": t("SSH (remote host)...")},
{
"prompt_description": t(
"Deploy - Install NTFY notification server"
"QEMU/KVM - Deploy an Ubuntu VM (libvirt)"
)
},
{
"prompt_description": t(
"QEMU/KVM - Deploy an Ubuntu VM (libvirt)"
"Deploy - Install NTFY notification server"
)
},
]
@ -902,9 +902,9 @@ class TODO:
elif status == "3":
self.prompt_execute_deploy_ssh()
elif status == "4":
self._deploy_ntfy_server()
elif status == "5":
self.prompt_execute_qemu()
elif status == "5":
self._deploy_ntfy_server()
else:
print(t("Command not found !"))

View file

@ -1403,6 +1403,43 @@ TRANSLATIONS = {
"fr": "🚚 Interface de la migration Odoo",
"en": "🚚 Odoo migration interface",
},
"modules of the list have no code in the active Odoo:": {
"fr": "modules de la liste n'ont plus de code dans l'Odoo actif :",
"en": "modules of the list have no code in the active Odoo:",
},
"Odoo cannot uninstall a module whose code is gone;": {
"fr": "Odoo ne peut pas désinstaller un module dont le code a"
" disparu ;",
"en": "Odoo cannot uninstall a module whose code is gone;",
},
"one of them fails the whole uninstall command.": {
"fr": "un seul d'entre eux fait échouer toute la désinstallation.",
"en": "one of them fails the whole uninstall command.",
},
"are present and can be uninstalled:": {
"fr": "sont présents et peuvent être désinstallés :",
"en": "are present and can be uninstalled:",
},
"No module of the list is present.": {
"fr": "Aucun module de la liste n'est présent.",
"en": "No module of the list is present.",
},
"Uninstall the present ones, skip the missing": {
"fr": "Désinstaller les présents, ignorer les manquants",
"en": "Uninstall the present ones, skip the missing",
},
"Try the whole list anyway (it will fail)": {
"fr": "Tout tenter quand même (ça échouera)",
"en": "Try the whole list anyway (it will fail)",
},
"Uninstall nothing, continue": {
"fr": "Ne rien désinstaller, continuer",
"en": "Uninstall nothing, continue",
},
"Nothing uninstalled.": {
"fr": "Rien de désinstallé.",
"en": "Nothing uninstalled.",
},
"No migration in progress to resume.": {
"fr": "Aucune migration en cours à reprendre.",
"en": "No migration in progress to resume.",

View file

@ -2264,18 +2264,86 @@ class TodoUpgrade:
lst_detail.append((module_name, reason, file_path))
return lst_module, lst_detail
def split_present_missing(self, lst_module):
"""Split a module list into (present, missing) against the ACTIVE code.
« Missing » means the addons path no longer holds the module — not
that it is absent from the database. The distinction matters because
check_addons_exist.py refuses the WHOLE uninstall for a single missing
name, so the modules that ARE there never get uninstalled either.
"""
lst_missing, _lst_duplicate = self.check_addons_exist(lst_module)
set_missing = set(lst_missing or [])
return (
[name for name in lst_module if name not in set_missing],
[name for name in lst_module if name in set_missing],
)
def prompt_uninstall_missing(self, lst_present, lst_missing):
"""Ask what to do when part of the list has no code left.
Returns the list to actually uninstall (possibly empty)."""
print()
print(
f"⚠️ {len(lst_missing)} "
f"{t('modules of the list have no code in the active Odoo:')}"
)
for name in lst_missing:
print(f" {name}")
print(f" {t('Odoo cannot uninstall a module whose code is gone;')}")
print(f" {t('one of them fails the whole uninstall command.')}")
print()
if lst_present:
print(
f" {len(lst_present)} "
f"{t('are present and can be uninstalled:')}"
)
for name in lst_present:
print(f" {name}")
else:
print(f" {t('No module of the list is present.')}")
print()
if lst_present:
print(
f" [1] {t('Uninstall the present ones, skip the missing')}"
" *"
)
print(f" [2] {t('Try the whole list anyway (it will fail)')}")
print(f" [3] {t('Uninstall nothing, continue')}")
answer = input(f"💬 {t('Your choice')} : ").strip()
if answer == "2":
return lst_present + lst_missing
if answer == "3" or not lst_present:
return []
return lst_present
def uninstall_from_database(
self, lst_module_to_uninstall, database_name, actual_version
):
if not lst_module_to_uninstall:
return
# Sort out what the active code still holds BEFORE calling the script:
# it aborts on the first missing name and takes the rest down with it.
lst_present, lst_missing = self.split_present_missing(
lst_module_to_uninstall
)
if lst_missing:
self.add_comment_progression(
"uninstall - no code for: " + ", ".join(lst_missing)
)
lst_module_to_uninstall = self.prompt_uninstall_missing(
lst_present, lst_missing
)
if not lst_module_to_uninstall:
print(f"⏭ {t('Nothing uninstalled.')}")
return
uninstall_module = ",".join(lst_module_to_uninstall)
self.todo_upgrade_execute(
f"./script/addons/uninstall_addons.sh {database_name} {uninstall_module}",
single_source_odoo=True,
)
# Update list installed module
# Update list installed module — only what was REALLY uninstalled, so
# a module left in place stays counted as installed.
self.dct_module_per_version[actual_version] = sorted(
list(
set(self.dct_module_per_version[actual_version])