[ADD] migration state: how long the migration took
From the first write to the LAST one. The progression file is rewritten after every move, so its update date is the end — or the present moment while the migration is still running. Both dates were already shown; what was missing was the one number one actually wants. The statistics screen already computed this. It is reused rather than rewritten: two formulas would give two durations for the same migration depending on which screen one opens. --- FR --- [ADD] état de migration : combien de temps elle a duré Du premier écrit au DERNIER. Le fichier de progression est réécrit après chaque geste, donc sa date de mise à jour est la fin — ou l'instant présent tant que la migration tourne. Les deux dates étaient déjà affichées ; il manquait le seul chiffre qu'on cherche. L'écran de statistiques portait déjà ce calcul. Il est réutilisé plutôt que réécrit : deux formules donneraient deux durées pour la même migration selon l'écran qu'on ouvre. Assisted-by: Claude Opus 5
This commit is contained in:
parent
c0c5144680
commit
e981500c94
4 changed files with 87 additions and 2 deletions
|
|
@ -288,9 +288,28 @@ def failures(dct):
|
|||
return list(reversed(events(dct, kind="command")))
|
||||
|
||||
|
||||
def elapsed(dct):
|
||||
"""Combien de temps la migration a duré, ou dure encore.
|
||||
|
||||
Du premier écrit à la DERNIÈRE écriture du journal : la progression est
|
||||
réécrite après chaque geste, donc sa date de mise à jour EST la fin —
|
||||
ou l'instant présent si la migration tourne toujours.
|
||||
|
||||
On délègue à `migration_stats.fmt_delay`, qui porte déjà ce calcul pour
|
||||
l'écran de statistiques. Deux formules donneraient deux durées pour la
|
||||
même migration selon l'écran qu'on ouvre.
|
||||
"""
|
||||
try:
|
||||
from script.todo.migration_stats import fmt_delay
|
||||
except Exception:
|
||||
return "?"
|
||||
return fmt_delay(dct.get("date_create"), dct.get("date_update"))
|
||||
|
||||
|
||||
def overview(dct):
|
||||
"""L'en-tête : de quelle migration parle-t-on."""
|
||||
return {
|
||||
"elapsed": elapsed(dct),
|
||||
"file": os.path.basename(dct.get("migration_file") or "?"),
|
||||
"database": dct.get("config_database_name") or "?",
|
||||
"target": dct.get("target_odoo_version") or "?",
|
||||
|
|
@ -340,7 +359,8 @@ def render_text(dct, limit_cmd=12, colour=None):
|
|||
f" {t('database')} : {info['database']}",
|
||||
f" {t('image')} : {info['file']}",
|
||||
f" {t('started')} : {info['started']}",
|
||||
f" {t('last written')} : {info['updated']}",
|
||||
f" {t('finished')} : {info['updated']}",
|
||||
f" {t('duration')} : {info['elapsed']}",
|
||||
f" {t('current step')} : {info['step']}",
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,8 @@ def head_text(dct):
|
|||
return (
|
||||
f"{info['database']} · {info['file']}\n"
|
||||
f"{t('current step')} : {info['step']}\n"
|
||||
f"{t('last written')} : {info['updated']}"
|
||||
f"{t('finished')} : {info['updated']}"
|
||||
f" · {t('duration')} {info['elapsed']}"
|
||||
f" · {len(status.failures(dct))} {t('failed')}"
|
||||
f" · {len(casse)}/{len(lst_test)} {t('Test results')}"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5667,6 +5667,14 @@ TRANSLATIONS = {
|
|||
"fr": "Rétrécir",
|
||||
"en": "Narrower",
|
||||
},
|
||||
"finished": {
|
||||
"fr": "terminée",
|
||||
"en": "finished",
|
||||
},
|
||||
"duration": {
|
||||
"fr": "durée",
|
||||
"en": "duration",
|
||||
},
|
||||
"Clean the database before testing the pages?": {
|
||||
"fr": "Nettoyer la base avant de tester les pages ?",
|
||||
"en": "Clean the database before testing the pages?",
|
||||
|
|
|
|||
|
|
@ -958,6 +958,62 @@ class TestTheFullScreenColoursToo(Base):
|
|||
self.assertIn("colour=True", source)
|
||||
|
||||
|
||||
class TestHowLongItTook(Base):
|
||||
"""Du premier écrit à la dernière écriture du journal.
|
||||
|
||||
La progression est réécrite après chaque geste, donc sa date de mise à
|
||||
jour EST la fin — ou l'instant présent si la migration tourne encore.
|
||||
"""
|
||||
|
||||
def dct(self, debut, fin):
|
||||
return progression(date_create=debut, date_update=fin)
|
||||
|
||||
def test_it_counts_from_the_start_to_the_last_write(self):
|
||||
info = status.overview(
|
||||
self.dct("2026-08-19 09:06:27", "2026-08-19 10:19:18")
|
||||
)
|
||||
self.assertEqual(info["elapsed"], "1 h 12 min")
|
||||
|
||||
def test_a_short_run_is_given_in_minutes(self):
|
||||
info = status.overview(
|
||||
self.dct("2026-08-19 09:06:00", "2026-08-19 09:41:00")
|
||||
)
|
||||
self.assertEqual(info["elapsed"], "35 min")
|
||||
|
||||
def test_a_long_run_is_given_in_days(self):
|
||||
info = status.overview(
|
||||
self.dct("2026-08-17 09:00:00", "2026-08-19 11:30:00")
|
||||
)
|
||||
self.assertIn("j", info["elapsed"])
|
||||
|
||||
def test_a_missing_date_never_invents_a_duration(self):
|
||||
self.assertEqual(status.overview(self.dct(None, None))["elapsed"], "?")
|
||||
|
||||
def test_the_report_shows_it(self):
|
||||
texte = status.render_text(
|
||||
self.dct("2026-08-19 09:06:27", "2026-08-19 10:19:18"),
|
||||
colour=False,
|
||||
)
|
||||
self.assertIn("1 h 12 min", texte)
|
||||
|
||||
def test_the_full_screen_shows_it_too(self):
|
||||
texte = tui.head_text(
|
||||
self.dct("2026-08-19 09:06:27", "2026-08-19 10:19:18")
|
||||
)
|
||||
self.assertIn("1 h 12 min", texte)
|
||||
|
||||
def test_it_is_computed_in_ONE_place(self):
|
||||
# L'écran de statistiques porte déjà ce calcul. Deux formules
|
||||
# donneraient deux durées pour la même migration selon l'écran
|
||||
# qu'on ouvre.
|
||||
import inspect
|
||||
|
||||
source = inspect.getsource(status.elapsed)
|
||||
self.assertIn(
|
||||
"from script.todo.migration_stats import fmt_delay", source
|
||||
)
|
||||
|
||||
|
||||
class TestSeparatingCommandsFromLogs(Base):
|
||||
"""Les deux mélangés dans un même panneau se confondent.
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue