From 1c7664409e43d1daef75b0638055d8998ab2a3db Mon Sep 17 00:00:00 2001 From: Mathieu Benoit Date: Tue, 18 Aug 2026 02:36:44 -0400 Subject: [PATCH] [FIX] migration: the module-upgrade step no longer waits forever MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Six « press to continue » prompts on the module-code migration were bare input() calls. Auto-run never reached them, so it stopped there and said nothing — the question had been asked, after all. They now go through the timed reader, where Enter and the countdown mean the same thing. They were English too, on a path the rest of which speaks the system language. The guard that forbids a bare input() only looked at a handful of methods, and internal_module_upgrade was not among them — which is exactly how these six survived the first sweep. It is now covered, and the module menu's own prompts are documented as deliberately blocking: they ask for a module name, a path, a version, and « » after five seconds would be a wrong answer, not a convenience. --- FR --- [FIX] migration : l'étape de migration de code n'attend plus indéfiniment Six invites « appuyez pour continuer » de la migration de code étaient des input() nus. L'auto-exécution ne les atteignait pas : elle s'arrêtait là sans rien dire — la question avait bien été posée. Elles passent désormais par le lecteur temporisé, où Entrée et le compte à rebours font la même chose. Elles étaient aussi en anglais, sur un chemin dont tout le reste parle la langue du système. Le garde-fou qui interdit les input() nus ne regardait qu'une poignée de méthodes, et internal_module_upgrade n'en faisait pas partie — c'est ainsi que ces six-là avaient survécu. Il la couvre maintenant, et les invites du menu de modules sont documentées comme bloquantes à dessein : elles demandent un nom, un chemin, une version. Assisted-by: Claude Opus 5 --- script/todo/todo_i18n.py | 16 ++++++++++++++++ script/todo/todo_upgrade.py | 29 +++++++++++++++++++--------- test/test_prompt_defaults.py | 37 ++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 9 deletions(-) diff --git a/script/todo/todo_i18n.py b/script/todo/todo_i18n.py index 97f0b13..eb2a1c6 100644 --- a/script/todo/todo_i18n.py +++ b/script/todo/todo_i18n.py @@ -5482,6 +5482,22 @@ TRANSLATIONS = { "fr": "Trop de tours sur cette invite : on passe.", "en": "Too many turns on this prompt: moving on.", }, + "Please validate git commit on repos, press to": { + "fr": "Veuillez valider les commits sur les dépôts, appuyez pour", + "en": "Please validate git commit on repos, press to", + }, + "Check the migrated code, press to continue": { + "fr": "Vérifiez le code migré, appuyez pour continuer", + "en": "Check the migrated code, press to continue", + }, + "Please validate the repo is ready to run": { + "fr": "Veuillez valider que le dépôt est prêt pour", + "en": "Please validate the repo is ready to run", + }, + "press to continue": { + "fr": "appuyez pour continuer", + "en": "press to continue", + }, "Clean the database before testing the pages?": { "fr": "Nettoyer la base avant de tester les pages ?", "en": "Clean the database before testing the pages?", diff --git a/script/todo/todo_upgrade.py b/script/todo/todo_upgrade.py index 1813421..b50ff35 100755 --- a/script/todo/todo_upgrade.py +++ b/script/todo/todo_upgrade.py @@ -1062,8 +1062,9 @@ class TodoUpgrade: cmd = f"./script/code/git_commit_migration_addons_path.py --path {commit_path} --odoo_version {next_version}.0" self.todo_upgrade_execute(cmd) print(set_path_migrate_addons) - status = input( - f"💬 Please validate git commit on repos, press to continue : " + status = self.ask( + f"💬 {t('Please validate git commit on repos, press to')}" + f" {t('continue')} : " ).strip() def internal_module_upgrade( @@ -1111,7 +1112,9 @@ class TodoUpgrade: print("List of path with migrate code :") print(lst_path_git_clone_migrate) print("ℹ To show repo status :\nmake repo_show_status") - input("💬 Check migration code, press to continue : ") + self.ask( + f"💬 {t('Check the migrated code, press to continue')} : " + ) # source_module_path = dct_module_result.get( # "source_module_path" @@ -1147,8 +1150,9 @@ class TodoUpgrade: if next_version in [18]: # TODO need odoo 18, validate python version without switch - status = input( - f"💬 Please validate repo is ready to run upgrade views_migration_18, press to continue : " + status = self.ask( + f"💬 {t('Please validate the repo is ready to run')}" + f" views_migration_18, {t('press to continue')} : " ).strip() # Apply modification with views_migration_18 has_cmd = False @@ -1171,11 +1175,15 @@ class TodoUpgrade: print("List of module with migration 18 :") print(lst_module_to_migrate_all) print("ℹ To show repo status :\nmake repo_show_status") - input("💬 Check migration 18 code, press to continue : ") + self.ask( + f"💬 {t('Check the migrated code, press to continue')}" + " (18) : " + ) if next_version == 17: - status = input( - f"💬 Please validate repo is ready to run upgrade views_migration_17, press to continue : " + status = self.ask( + f"💬 {t('Please validate the repo is ready to run')}" + f" views_migration_17, {t('press to continue')} : " ).strip() # Apply modification with views_migration_17 has_cmd = False @@ -1202,7 +1210,10 @@ class TodoUpgrade: print("List of module with migration 17 :") print(lst_module_to_migrate_all) print("ℹ To show repo status :\nmake repo_show_status") - input("💬 Check migration 17 code, press to continue : ") + self.ask( + f"💬 {t('Check the migrated code, press to continue')}" + " (17) : " + ) def execute_odoo_upgrade(self): # TODO update dev environment for git project diff --git a/test/test_prompt_defaults.py b/test/test_prompt_defaults.py index bb773ea..fb0248d 100644 --- a/test/test_prompt_defaults.py +++ b/test/test_prompt_defaults.py @@ -174,6 +174,9 @@ class TestNoPromptOfTheMigrationCanHang(unittest.TestCase): METHODES = ( "execute_odoo_upgrade", + # Appelée DEPUIS execute_odoo_upgrade : c'est par elle que le + # « validez que le dépôt est prêt » arrivait, et il bloquait. + "internal_module_upgrade", "prompt_cow_prediction", "prompt_uninstall_theme", "prompt_reset_stale_cow_views", @@ -210,6 +213,40 @@ class TestNoPromptOfTheMigrationCanHang(unittest.TestCase): self.assertEqual(coupables, {}, "invites hors du mode auto") +class TestWhereBlockingIsStillRight(unittest.TestCase): + """Tout ne doit pas prendre un défaut : certaines questions n'en ont pas. + + `execute_module_upgrade` demande un nom de module, un chemin, une + version de départ. Rendre « » au bout de cinq secondes n'y serait pas + une commodité mais une réponse fausse. Ces invites restent bloquantes, + et c'est correct — à une condition, vérifiée ici : qu'aucune migration + automatique ne passe par elles. + """ + + def test_the_module_menu_is_not_on_the_automatic_path(self): + import inspect + + source = inspect.getsource(TodoUpgrade.execute_odoo_upgrade) + self.assertNotIn("execute_module_upgrade", source) + + def test_but_the_step_it_shares_IS(self): + # `internal_module_upgrade` est appelée des DEUX côtés : par le + # menu et par la migration. C'est ce qui la rend obligatoire. + import inspect + + source = inspect.getsource(TodoUpgrade.execute_odoo_upgrade) + self.assertIn("internal_module_upgrade", source) + + def test_its_prompts_ask_for_values_with_no_default(self): + # Si l'un d'eux devenait un oui/non, il faudrait le faire passer + # par le lecteur temporisé comme les autres. + import inspect + + source = inspect.getsource(TodoUpgrade.execute_module_upgrade) + for question in ("Module name", "Path", "From odoo version"): + self.assertIn(question, source) + + class TestWhatEnterDoesIsWritten(unittest.TestCase): """La question doit dire la vérité à qui appuie sur Entrée."""