From 01f6b467eeec8bd77598216a2da9e38055e2f7d0 Mon Sep 17 00:00:00 2001 From: varun-ai69 Date: Fri, 24 Jul 2026 21:59:57 +0530 Subject: [PATCH] fix(rollback): execute version files in LIFO order (#1487) (#1494) Signed-off-by: varun-ai69 Co-authored-by: Paige Patton <64206430+paigerube14@users.noreply.github.com> --- krkn/rollback/config.py | 9 +++++++++ tests/test_rollback.py | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/krkn/rollback/config.py b/krkn/rollback/config.py index e1b81770..c29eb0a0 100644 --- a/krkn/rollback/config.py +++ b/krkn/rollback/config.py @@ -249,6 +249,15 @@ class RollbackConfig(metaclass=SingletonMeta): logger.warning( f"File {file} does not match expected pattern of <{scenario_type or '*'}>__.py" ) + def get_rollback_timestamp(filepath: str) -> int: + filename = os.path.basename(filepath) + parts = filename.rsplit("_", 2) + try: + return int(parts[-2]) + except (IndexError, ValueError): + return 0 + # Execute rollback version files in reverse chronological order (LIFO). + version_files.sort(key=get_rollback_timestamp, reverse=True) return version_files @dataclass(frozen=True) diff --git a/tests/test_rollback.py b/tests/test_rollback.py index 73014f57..a1d735ba 100644 --- a/tests/test_rollback.py +++ b/tests/test_rollback.py @@ -189,6 +189,39 @@ class TestRollbackConfig: def test_is_rollback_version_file_format(self, file_name, expected): assert RollbackConfig.is_rollback_version_file_format(file_name) == expected + def test_search_rollback_version_files_order(self, tmpdir): + from unittest.mock import patch + + run_uuid = "abcdefgh" + versions_dir = str(tmpdir.mkdir("versions_test_order")) + + with patch.object(RollbackConfig, 'versions_directory', versions_dir): + context_dir_name = f"123456789-{run_uuid}" + context_dir = os.path.join(versions_dir, context_dir_name) + os.makedirs(context_dir) + + # Files with different timestamps + files = [ + "scenario_1000_12345678.py", + "scenario_3000_12345678.py", + "scenario_2000_12345678.py", + "scenario_500_12345678.py", + ] + for file in files: + with open(os.path.join(context_dir, file), "w") as f: + f.write("# dummy content") + + result = RollbackConfig.search_rollback_version_files(run_uuid, "scenario") + result_filenames = [os.path.basename(f) for f in result] + + expected_order = [ + "scenario_3000_12345678.py", + "scenario_2000_12345678.py", + "scenario_1000_12345678.py", + "scenario_500_12345678.py", + ] + assert result_filenames == expected_order + class TestRollbackCommand: @pytest.mark.parametrize("auto_rollback", [True, False], ids=["enabled_rollback", "disabled_rollback"])