From d64cfbef308178226a23e3614e0103f4969374be Mon Sep 17 00:00:00 2001 From: Elias Haberl Date: Thu, 7 May 2026 12:11:14 +0200 Subject: [PATCH 01/11] feat: add age based removal of runs Signed-off-by: HuntTheSun --- docs/basic-command-line-interface-cli.md | 8 +++- robotframework_dashboard/arguments.py | 2 + robotframework_dashboard/database.py | 55 ++++++++++++++++++++++- tests/robot/resources/cli_output/help.txt | 4 +- 4 files changed, 65 insertions(+), 4 deletions(-) diff --git a/docs/basic-command-line-interface-cli.md b/docs/basic-command-line-interface-cli.md index 19b4cf11..c123f246 100644 --- a/docs/basic-command-line-interface-cli.md +++ b/docs/basic-command-line-interface-cli.md @@ -120,13 +120,17 @@ robotdashboard -r index=0,index=1:4;9,index=10 robotdashboard --removeruns 'run_start=2024-07-30 15:27:20.184407,index=20' robotdashboard -r alias=some_cool_alias,tag=prod,tag=dev -r alias=alias12345 robotdashboard -r limit=10 +robotdashboard -r age=10d # (y)ear/(d)ay/(m)inutes/(s)econds supported +robotdashboard -r age=-10d ``` - Optional: `-r` or `--removeruns` specifies one or more runs to remove. - Multiple values are separated by commas (,). - Must specify data types: index, run_start, alias, tag or limit. - Index ranges use `:` for ranges and `;` for lists. -- Quotation marks are required when spaces exist in identifiers. -- With limit=10 only the 10 most recent runs will be kept, all others will be removed. +- Quotation marks are required when spaces exist in identifiers. +- With limit=10 only the 10 most recent runs will be kept, all others will be removed. +- With age=10d only runs _**older**_ than 10 days will be removed +- With age=-10d only runs _**younger**_ than 10 days will be removed ## Customizing the Dashboard diff --git a/robotframework_dashboard/arguments.py b/robotframework_dashboard/arguments.py index 05593d77..aa7b9a73 100644 --- a/robotframework_dashboard/arguments.py +++ b/robotframework_dashboard/arguments.py @@ -267,6 +267,8 @@ def _parse_arguments(self): " • '-r run_start=2024-07-30 15:27:20.184407' -> remove specified run\n" " • '-r alias=some_alias,tag=prod'\n" " • '-r limit=10' -> keep only the 10 most recent runs\n" + " • '-r age=10d' -> remove runs older than 10 days\n" + " • '-r age=-10d' -> remove runs younger than 10 days\n" ), action="append", nargs="*", diff --git a/robotframework_dashboard/database.py b/robotframework_dashboard/database.py index d077e8e5..220ec55b 100644 --- a/robotframework_dashboard/database.py +++ b/robotframework_dashboard/database.py @@ -1,9 +1,10 @@ import sqlite3 +import re from pathlib import Path from .queries import * from .abstractdb import AbstractDatabaseProcessor from time import time -from datetime import datetime, timezone +from datetime import datetime, timezone, timedelta from typing import Union # Explicit adapter for datetime -> ISO string, replacing the deprecated default @@ -399,6 +400,8 @@ def remove_runs(self, remove_runs: list): console += self._remove_by_tag(run, run_starts, run_tags) elif "limit=" in run: console += self._remove_by_limit(run, run_starts) + elif "age=" in run: + console += self._remove_by_age(run, run_starts) else: print( f" ERROR: incorrect usage of the remove_run feature ({run}), check out robotdashboard --help for instructions" @@ -490,6 +493,37 @@ def _remove_by_limit(self, run: str, run_starts: list): console += f" Removed run from the database: index={index}, run_start={run_starts[index]}\n" return console + def _remove_by_age(self, run_query: str, run_starts: list): + console = "" + try: + clean_query = run_query.replace("age=", "") + mod, delta = self.parse_time_range(clean_query) + except ValueError as e: + return f" ERROR: {e}" + cutoff = datetime.now(timezone.utc)-delta + targets = [] + for r in run_starts: + try: + run_dt = datetime.fromisoformat(r) + if run_dt.tzinfo is None: + run_dt = run_dt.replace(tzinfo=timezone.utc) + if mod == "+": + if run_dt < cutoff: + targets.append(r) + elif mod == "-": + if run_dt > cutoff: + targets.append(r) + except ValueError as e: + print(f" WARNING: Skipping invalid timestamp: '{r}' ({e})") + if not targets: + console += f" WARNING: no runs were removed as no runs were within range {clean_query}" + return console + for run_to_remove in targets: + self._remove_run(run_to_remove) + print(f" Removed run from the database: run_start={run_to_remove}") + console += f" Removed run from the database: run_start={run_to_remove}\n" + return console + def _remove_run(self, run_start: str): """Helper function to remove the data from all tables""" self.connection.cursor().execute(DELETE_FROM_RUNS.format(run_start=run_start)) @@ -510,6 +544,25 @@ def vacuum_database(self): print(f" Vacuumed the database in {round(end - start, 2)} seconds") return console + def parse_time_range(self, range_str: str): + # Regex groups : [modifier] [value] [unit] + # e.g., +10d, -4h, 1y + match = re.match(r"([+-])?(\d+)([smhdy])", range_str) + if not match: + raise ValueError("Invalid format. Use e.g., 10d, +5h, -1y") + modifier, value, unit = match.groups() + value = int(value) + units = { + 's': 'seconds', + 'm': 'minutes', + 'h': 'hours', + 'd': 'days', + 'y': 'days' + } + # assume year is 365 days + delta_kwargs = {units[unit]: value * (365 if unit == 'y' else 1)} + return modifier or '+', timedelta(**delta_kwargs) + def update_output_path(self, log_path: str): """Function to update the output_path using the log path that the server has used""" console = "" diff --git a/tests/robot/resources/cli_output/help.txt b/tests/robot/resources/cli_output/help.txt index ad6eaedb..03e3998d 100644 --- a/tests/robot/resources/cli_output/help.txt +++ b/tests/robot/resources/cli_output/help.txt @@ -69,6 +69,8 @@ database: • '-r run_start=2024-07-30 15:27:20.184407' -> remove specified run • '-r alias=some_alias,tag=prod' • '-r limit=10' -> keep only the 10 most recent runs + • '-r age=10d' -> remove runs older than 10 days + • '-r age=-10d' -> remove runs younger than 10 days -c PATH, --databaseclass PATH Path to a custom database class (.py) to override the built-in SQLite engine. • See docs for implementation details @@ -139,4 +141,4 @@ server: • '--ssl-certfile cert.pem --ssl-keyfile key.pem' Boolean flags: omit the value to toggle the default (e.g. '--uselogs'); or pass 'true'/'false' explicitly. -For full documentation, visit: https://marketsquare.github.io/robotframework-dashboard/ \ No newline at end of file +For full documentation, visit: https://marketsquare.github.io/robotframework-dashboard/ From ab7c0e4908473d9354069b8c40f0e736f8c92d07 Mon Sep 17 00:00:00 2001 From: HuntTheSun Date: Wed, 20 May 2026 08:45:08 +0200 Subject: [PATCH 02/11] feat/timerange_deletion: add (h)our supported text Signed-off-by: HuntTheSun --- robotframework_dashboard/arguments.py | 1 + 1 file changed, 1 insertion(+) diff --git a/robotframework_dashboard/arguments.py b/robotframework_dashboard/arguments.py index aa7b9a73..75a90355 100644 --- a/robotframework_dashboard/arguments.py +++ b/robotframework_dashboard/arguments.py @@ -269,6 +269,7 @@ def _parse_arguments(self): " • '-r limit=10' -> keep only the 10 most recent runs\n" " • '-r age=10d' -> remove runs older than 10 days\n" " • '-r age=-10d' -> remove runs younger than 10 days\n" + " • (y)ear/(d)ay/(h)our/(m)inute/(s)econd supported\n" ), action="append", nargs="*", From bc70a7a5369884ed193056fed49fd173c2a449ac Mon Sep 17 00:00:00 2001 From: HuntTheSun Date: Wed, 20 May 2026 08:46:55 +0200 Subject: [PATCH 03/11] feat/timerange_deletion: implement age rm api py Signed-off-by: HuntTheSun --- robotframework_dashboard/server.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/robotframework_dashboard/server.py b/robotframework_dashboard/server.py index 4dae91c5..3f1cb136 100644 --- a/robotframework_dashboard/server.py +++ b/robotframework_dashboard/server.py @@ -113,6 +113,8 @@ "tags": ["tag1", "tag2", "tag3"], }, {"limit": 10}, + {"age": "10d"}, + {"age": "-10d"}, {"all": True}, ], "openapi_examples": { @@ -140,6 +142,11 @@ "tags": ["tag1", "tag2", "tag3"], }, }, + "age": { + "summary": "Remove runs based on age threshold", + "description": "Remove runs older than a threshold (e.g., '10d') or younger than a threshold (e.g., '-10d'). Supports (y)ear/(d)ay/(h)our/(m)inute/(s)econd.", + "value": {"age": "10d"}, + }, "limit": { "summary": "Remove all but the N most recent runs", "description": "Keep only the specified number of most recent runs, deleting the rest.", @@ -246,6 +253,7 @@ class RemoveOutputs(BaseModel): tags: Optional[List[str]] = None all: Optional[bool] = False limit: Optional[int] = None + age: Optional[str] = None model_config = remove_outputs_model_config @@ -607,6 +615,8 @@ async def remove_outputs_from_database( if remove_output.tags != None: for run in remove_output.tags: remove_runs.append(f"tag={run}") + if remove_output.age != None: + remove_runs.append(f"age={remove_output.age}") if remove_output.limit != None: remove_runs.append(f"limit={remove_output.limit}") paths_before = self.robotdashboard.get_run_paths() From d39e549e0b2a1b4b9c05fc98b0bdfb130d035e07 Mon Sep 17 00:00:00 2001 From: HuntTheSun Date: Wed, 20 May 2026 08:49:34 +0200 Subject: [PATCH 04/11] feat/timerange_deletion: implement age rm api js Signed-off-by: HuntTheSun --- robotframework_dashboard/js/admin_page/admin_api.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/robotframework_dashboard/js/admin_page/admin_api.js b/robotframework_dashboard/js/admin_page/admin_api.js index 3b889355..b2f65e18 100644 --- a/robotframework_dashboard/js/admin_page/admin_api.js +++ b/robotframework_dashboard/js/admin_page/admin_api.js @@ -116,6 +116,8 @@ function remove_outputs() { const removeTags = document.getElementById("removeTags").value.split(",") const removeLimit = document.getElementById("removeLimit").value if (removeLimit != "") { data["limit"] = removeLimit } + const removeAge = document.getElementById("removeAge").value + if (removeAge != "") { data["age"] = removeAge } for (const removeTag of removeTags) { if (removeTag == "") { continue } tags.push(removeTag) @@ -126,6 +128,7 @@ function remove_outputs() { document.getElementById("removeAliases").value = "" document.getElementById("removeTags").value = "" document.getElementById("removeLimit").value = "" + document.getElementById("removeAge").value = "" const body = JSON.stringify(data) send_request("DELETE", "/remove-outputs", body, "removeSpinner") } From b57159cbb10b2b3ea8ab3cc260f614512af48b44 Mon Sep 17 00:00:00 2001 From: HuntTheSun Date: Wed, 20 May 2026 08:48:19 +0200 Subject: [PATCH 05/11] feat/timerange_deletion: add age rm admin ui Signed-off-by: HuntTheSun --- robotframework_dashboard/templates/admin.html | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/robotframework_dashboard/templates/admin.html b/robotframework_dashboard/templates/admin.html index c771af3e..f6b3ad7d 100644 --- a/robotframework_dashboard/templates/admin.html +++ b/robotframework_dashboard/templates/admin.html @@ -232,6 +232,16 @@

Remove output.xml(s) From Database

+
+
+

outputs to remove by age

+
+
+ + +
+

outputs to remove by limit

From 71f0d36e4608875ab6316615762c9e15a67f491f Mon Sep 17 00:00:00 2001 From: HuntTheSun Date: Wed, 20 May 2026 09:00:23 +0200 Subject: [PATCH 06/11] feat/timerange_deletion: update help.txt Signed-off-by: HuntTheSun --- tests/robot/resources/cli_output/help.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/robot/resources/cli_output/help.txt b/tests/robot/resources/cli_output/help.txt index 03e3998d..18c05a35 100644 --- a/tests/robot/resources/cli_output/help.txt +++ b/tests/robot/resources/cli_output/help.txt @@ -71,6 +71,7 @@ database: • '-r limit=10' -> keep only the 10 most recent runs • '-r age=10d' -> remove runs older than 10 days • '-r age=-10d' -> remove runs younger than 10 days + • (y)ear/(d)ay/(h)our/(m)inute/(s)econd supported -c PATH, --databaseclass PATH Path to a custom database class (.py) to override the built-in SQLite engine. • See docs for implementation details @@ -142,3 +143,4 @@ server: Boolean flags: omit the value to toggle the default (e.g. '--uselogs'); or pass 'true'/'false' explicitly. For full documentation, visit: https://marketsquare.github.io/robotframework-dashboard/ + From 7c3c0cd2df4333d6e7aaa0b0a589cb61a73ee59f Mon Sep 17 00:00:00 2001 From: HuntTheSun Date: Wed, 20 May 2026 09:46:37 +0200 Subject: [PATCH 07/11] feat/timerange_deletion: add hour supported text to docs Signed-off-by: HuntTheSun --- docs/basic-command-line-interface-cli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/basic-command-line-interface-cli.md b/docs/basic-command-line-interface-cli.md index c123f246..40d08c87 100644 --- a/docs/basic-command-line-interface-cli.md +++ b/docs/basic-command-line-interface-cli.md @@ -120,7 +120,7 @@ robotdashboard -r index=0,index=1:4;9,index=10 robotdashboard --removeruns 'run_start=2024-07-30 15:27:20.184407,index=20' robotdashboard -r alias=some_cool_alias,tag=prod,tag=dev -r alias=alias12345 robotdashboard -r limit=10 -robotdashboard -r age=10d # (y)ear/(d)ay/(m)inutes/(s)econds supported +robotdashboard -r age=10d # (y)ear/(d)ay/(h)our/(m)inute/(s)econd supported robotdashboard -r age=-10d ``` - Optional: `-r` or `--removeruns` specifies one or more runs to remove. From a2a1bf3a613420fda5ab539778010e129092d358 Mon Sep 17 00:00:00 2001 From: HuntTheSun Date: Wed, 20 May 2026 09:55:09 +0200 Subject: [PATCH 08/11] feat/timerange_deletion: remove ending newline help.txt Signed-off-by: HuntTheSun --- tests/robot/resources/cli_output/help.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/robot/resources/cli_output/help.txt b/tests/robot/resources/cli_output/help.txt index 18c05a35..14d09f36 100644 --- a/tests/robot/resources/cli_output/help.txt +++ b/tests/robot/resources/cli_output/help.txt @@ -143,4 +143,3 @@ server: Boolean flags: omit the value to toggle the default (e.g. '--uselogs'); or pass 'true'/'false' explicitly. For full documentation, visit: https://marketsquare.github.io/robotframework-dashboard/ - From f065f09a1308432c088cdbb65b29c6d922e7eaa1 Mon Sep 17 00:00:00 2001 From: HuntTheSun Date: Fri, 22 May 2026 10:18:19 +0200 Subject: [PATCH 09/11] feat/timerange_deletion: fix help.txt format Signed-off-by: HuntTheSun --- tests/robot/resources/cli_output/help.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/robot/resources/cli_output/help.txt b/tests/robot/resources/cli_output/help.txt index 14d09f36..df425bfb 100644 --- a/tests/robot/resources/cli_output/help.txt +++ b/tests/robot/resources/cli_output/help.txt @@ -142,4 +142,4 @@ server: • '--ssl-certfile cert.pem --ssl-keyfile key.pem' Boolean flags: omit the value to toggle the default (e.g. '--uselogs'); or pass 'true'/'false' explicitly. -For full documentation, visit: https://marketsquare.github.io/robotframework-dashboard/ +For full documentation, visit: https://marketsquare.github.io/robotframework-dashboard/ \ No newline at end of file From f5699a1e7b6786e118a2b75b49d08ad4b3151f5f Mon Sep 17 00:00:00 2001 From: HuntTheSun Date: Fri, 22 May 2026 10:42:11 +0200 Subject: [PATCH 10/11] feat/timerange_deletion: rerun flaky CI test commit Signed-off-by: HuntTheSun --- tests/robot/testsuites/06_filters.robot | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/robot/testsuites/06_filters.robot b/tests/robot/testsuites/06_filters.robot index 2b3f2ffd..b3e033d6 100644 --- a/tests/robot/testsuites/06_filters.robot +++ b/tests/robot/testsuites/06_filters.robot @@ -59,6 +59,7 @@ Add Filter Profile With Versions Filter Add Filter Profile PrfVersions For Versions Filter Profile PrfVersions Should Be {'projectVersions': [{'value': 'All', 'checked': False}, {'value': 'None', 'checked': True}, {'value': '1.2', 'checked': False}, {'value': '1.1', 'checked': False}, {'value': '1.0', 'checked': False}]} +# A little flaky Add Filter Profile With Date Filters Set Date Filter fromDate=03132025 fromTime=1225am toDate=04012025 toTime=1159pm From d6996a32c15c7a8e94eb5e085502d90f8f8904e2 Mon Sep 17 00:00:00 2001 From: HuntTheSun Date: Fri, 22 May 2026 10:53:41 +0200 Subject: [PATCH 11/11] feat/timerange_deletion: fix admin age unit order Signed-off-by: HuntTheSun --- robotframework_dashboard/templates/admin.html | 4 ++-- tests/robot/testsuites/06_filters.robot | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/robotframework_dashboard/templates/admin.html b/robotframework_dashboard/templates/admin.html index f6b3ad7d..8595971c 100644 --- a/robotframework_dashboard/templates/admin.html +++ b/robotframework_dashboard/templates/admin.html @@ -238,7 +238,7 @@

Remove output.xml(s) From Database

+ or -10d (delete younger than 10 days). (y)ear/(d)ay/(h)our/(m)inute/(s)econd supported
@@ -411,4 +411,4 @@ - \ No newline at end of file + diff --git a/tests/robot/testsuites/06_filters.robot b/tests/robot/testsuites/06_filters.robot index b3e033d6..2b3f2ffd 100644 --- a/tests/robot/testsuites/06_filters.robot +++ b/tests/robot/testsuites/06_filters.robot @@ -59,7 +59,6 @@ Add Filter Profile With Versions Filter Add Filter Profile PrfVersions For Versions Filter Profile PrfVersions Should Be {'projectVersions': [{'value': 'All', 'checked': False}, {'value': 'None', 'checked': True}, {'value': '1.2', 'checked': False}, {'value': '1.1', 'checked': False}, {'value': '1.0', 'checked': False}]} -# A little flaky Add Filter Profile With Date Filters Set Date Filter fromDate=03132025 fromTime=1225am toDate=04012025 toTime=1159pm