show completion in frontend
This commit is contained in:
+24
-3
@@ -452,21 +452,42 @@ def get_holidays() -> dict[str, Any]:
|
||||
return {"dates": sorted(db.list_holidays(DB_PATH))}
|
||||
|
||||
|
||||
@app.get("/api/schedule/versions")
|
||||
def get_schedule_versions() -> dict[str, Any]:
|
||||
return {"versions": db.get_schedule_versions(DB_PATH)}
|
||||
|
||||
|
||||
@app.get("/api/schedule/week")
|
||||
def get_schedule_week(start: str | None = None) -> dict[str, Any]:
|
||||
def get_schedule_week(start: str | None = None, version: int | None = None) -> dict[str, Any]:
|
||||
week_start = start or date.today().isoformat()
|
||||
try:
|
||||
datetime.strptime(week_start, "%Y-%m-%d")
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=400, detail="start must be YYYY-MM-DD") from exc
|
||||
if version is not None and version <= 0:
|
||||
raise HTTPException(status_code=400, detail="version must be a positive integer")
|
||||
|
||||
week_start_date = datetime.strptime(week_start, "%Y-%m-%d").date()
|
||||
rows = db.get_schedule_week(week_start, DB_PATH)
|
||||
all_rows = db.get_schedule_rows_for_latest_version(DB_PATH)
|
||||
selected_version = db.resolve_schedule_version(version, DB_PATH)
|
||||
if version is not None and selected_version is None:
|
||||
raise HTTPException(status_code=404, detail=f"Schedule version {version} was not found")
|
||||
|
||||
rows = db.get_schedule_week(week_start, selected_version, DB_PATH)
|
||||
|
||||
# Log completed tests on the current schedule
|
||||
completed_count = sum(1 for row in rows if row.status == 'completed')
|
||||
if completed_count > 0:
|
||||
print(f"[api] /schedule/week: {completed_count} test(s) marked as completed on calendar")
|
||||
for row in rows:
|
||||
if row.status == 'completed':
|
||||
print(f" - {row.test_id} on {row.device} (scheduled {row.scheduled_date})")
|
||||
|
||||
all_rows = db.get_schedule_rows(selected_version, DB_PATH)
|
||||
completion_date = max((row.scheduled_date for row in all_rows), default=None)
|
||||
holiday_dates = db.list_holidays(DB_PATH)
|
||||
return {
|
||||
"start_date": week_start,
|
||||
"schedule_version": selected_version,
|
||||
"items": [_serialize_schedule_row(row) for row in rows],
|
||||
"total_scheduled_tests": len(all_rows),
|
||||
"completion_date": completion_date,
|
||||
|
||||
+106
-22
@@ -471,11 +471,69 @@ def create_schedule_version(
|
||||
return next_version
|
||||
|
||||
|
||||
def get_schedule_week(start_date: str, db_path: str | Path = DB_PATH) -> list[ScheduleRow]:
|
||||
def get_schedule_versions(db_path: str | Path = DB_PATH) -> list[dict[str, Any]]:
|
||||
with get_connection(db_path) as conn:
|
||||
version_row = conn.execute("SELECT MAX(schedule_version) AS latest FROM schedules").fetchone()
|
||||
latest = version_row["latest"]
|
||||
if latest is None:
|
||||
rows = conn.execute(
|
||||
"""
|
||||
SELECT
|
||||
schedule_version,
|
||||
MIN(created_at) AS created_at,
|
||||
COUNT(*) AS entry_count
|
||||
FROM schedules
|
||||
GROUP BY schedule_version
|
||||
ORDER BY schedule_version DESC
|
||||
"""
|
||||
).fetchall()
|
||||
|
||||
return [
|
||||
{
|
||||
"schedule_version": int(row["schedule_version"]),
|
||||
"created_at": row["created_at"],
|
||||
"entry_count": int(row["entry_count"]),
|
||||
}
|
||||
for row in rows
|
||||
]
|
||||
|
||||
|
||||
def resolve_schedule_version(
|
||||
version: int | None = None,
|
||||
db_path: str | Path = DB_PATH,
|
||||
) -> int | None:
|
||||
with get_connection(db_path) as conn:
|
||||
if version is not None:
|
||||
row = conn.execute(
|
||||
"SELECT 1 FROM schedules WHERE schedule_version = ? LIMIT 1",
|
||||
(version,),
|
||||
).fetchone()
|
||||
return int(version) if row else None
|
||||
|
||||
latest_row = conn.execute("SELECT MAX(schedule_version) AS latest FROM schedules").fetchone()
|
||||
latest = latest_row["latest"]
|
||||
return int(latest) if latest is not None else None
|
||||
|
||||
|
||||
def get_schedule_week(
|
||||
start_date: str,
|
||||
version: int | None = None,
|
||||
db_path: str | Path = DB_PATH,
|
||||
) -> list[ScheduleRow]:
|
||||
with get_connection(db_path) as conn:
|
||||
if version is not None:
|
||||
version_row = conn.execute(
|
||||
"SELECT 1 AS exists_row FROM schedules WHERE schedule_version = ? LIMIT 1",
|
||||
(version,),
|
||||
).fetchone()
|
||||
if version_row is None:
|
||||
return []
|
||||
selected_version = int(version)
|
||||
else:
|
||||
latest_row = conn.execute("SELECT MAX(schedule_version) AS latest FROM schedules").fetchone()
|
||||
latest = latest_row["latest"]
|
||||
if latest is None:
|
||||
return []
|
||||
selected_version = int(latest)
|
||||
|
||||
if selected_version is None:
|
||||
return []
|
||||
|
||||
rows = conn.execute(
|
||||
@@ -514,7 +572,7 @@ def get_schedule_week(start_date: str, db_path: str | Path = DB_PATH) -> list[Sc
|
||||
ORDER BY s.scheduled_date, s.shift_index, s.sequence_in_shift
|
||||
""",
|
||||
(
|
||||
latest,
|
||||
selected_version,
|
||||
start_date,
|
||||
start_date,
|
||||
start_date,
|
||||
@@ -544,11 +602,27 @@ def get_schedule_week(start_date: str, db_path: str | Path = DB_PATH) -> list[Sc
|
||||
return result
|
||||
|
||||
|
||||
def get_schedule_rows_for_latest_version(db_path: str | Path = DB_PATH) -> list[ScheduleRow]:
|
||||
def get_schedule_rows(
|
||||
version: int | None = None,
|
||||
db_path: str | Path = DB_PATH,
|
||||
) -> list[ScheduleRow]:
|
||||
with get_connection(db_path) as conn:
|
||||
version_row = conn.execute("SELECT MAX(schedule_version) AS latest FROM schedules").fetchone()
|
||||
latest = version_row["latest"]
|
||||
if latest is None:
|
||||
if version is not None:
|
||||
version_row = conn.execute(
|
||||
"SELECT 1 AS exists_row FROM schedules WHERE schedule_version = ? LIMIT 1",
|
||||
(version,),
|
||||
).fetchone()
|
||||
if version_row is None:
|
||||
return []
|
||||
selected_version = int(version)
|
||||
else:
|
||||
latest_row = conn.execute("SELECT MAX(schedule_version) AS latest FROM schedules").fetchone()
|
||||
latest = latest_row["latest"]
|
||||
if latest is None:
|
||||
return []
|
||||
selected_version = int(latest)
|
||||
|
||||
if selected_version is None:
|
||||
return []
|
||||
|
||||
rows = conn.execute(
|
||||
@@ -570,7 +644,7 @@ def get_schedule_rows_for_latest_version(db_path: str | Path = DB_PATH) -> list[
|
||||
WHERE s.schedule_version = ?
|
||||
ORDER BY s.scheduled_date, s.shift_index, s.sequence_in_shift
|
||||
""",
|
||||
(latest,),
|
||||
(selected_version,),
|
||||
).fetchall()
|
||||
|
||||
result: list[ScheduleRow] = []
|
||||
@@ -593,21 +667,31 @@ def get_schedule_rows_for_latest_version(db_path: str | Path = DB_PATH) -> list[
|
||||
|
||||
return result
|
||||
|
||||
def mark_tests_completed(test_ids_with_device: list[tuple[str, str]], db_path: str | Path = DB_PATH) -> None:
|
||||
def mark_tests_completed(test_ids_with_device: list[tuple[str, str]], db_path: str | Path = DB_PATH) -> int:
|
||||
if not test_ids_with_device:
|
||||
return
|
||||
return 0
|
||||
|
||||
with get_connection(db_path) as conn:
|
||||
conn.executemany(
|
||||
"""
|
||||
UPDATE tests
|
||||
SET status = 'completed', updated_at = CURRENT_TIMESTAMP
|
||||
WHERE test_id = ?
|
||||
AND device = ?
|
||||
AND status != 'completed'
|
||||
""",
|
||||
test_ids_with_device,
|
||||
)
|
||||
# executemany() doesn't properly return rowcount, so we track manually
|
||||
total_updated = 0
|
||||
for test_id, device in test_ids_with_device:
|
||||
cursor = conn.execute(
|
||||
"""
|
||||
UPDATE tests
|
||||
SET status = 'completed', updated_at = CURRENT_TIMESTAMP
|
||||
WHERE test_id = ?
|
||||
AND device = ?
|
||||
AND status != 'completed'
|
||||
""",
|
||||
(test_id, device),
|
||||
)
|
||||
if cursor.rowcount > 0:
|
||||
total_updated += cursor.rowcount
|
||||
print(f"[db] marked {test_id} on {device} as completed")
|
||||
else:
|
||||
print(f"[db] {test_id} on {device}: no update (not found or already completed)")
|
||||
|
||||
return total_updated
|
||||
|
||||
|
||||
def mark_overdue_as_rerun(db_path: str | Path = DB_PATH) -> int:
|
||||
|
||||
+9
-1
@@ -283,6 +283,7 @@ def scan_results(results_dir_dut, results_dir_ref, smb_credentials=None):
|
||||
entry.name
|
||||
for entry in _iter_dir_entries(results_dir_ref, smb_credentials=smb_credentials)
|
||||
if entry.is_dir()
|
||||
and not entry.name.startswith("obsolete")
|
||||
]
|
||||
except OSError as exc:
|
||||
print(f"[scanner] Cannot read results dir: {exc}")
|
||||
@@ -310,7 +311,14 @@ def scan_results(results_dir_dut, results_dir_ref, smb_credentials=None):
|
||||
if unmatched_entries:
|
||||
print(f"[scanner] skipped {len(unmatched_entries)} result dir(s) with no recognizable test id")
|
||||
|
||||
mark_tests_completed(completed_batch)
|
||||
if completed_batch:
|
||||
print(f"[scanner] marking {len(completed_batch)} test(s) as completed:")
|
||||
for test_id, device in completed_batch:
|
||||
print(f" - {test_id} on {device}")
|
||||
|
||||
updated_count = mark_tests_completed(completed_batch)
|
||||
print(f"[scanner] {updated_count} test(s) actually updated in database")
|
||||
|
||||
newly_rerun = mark_overdue_as_rerun()
|
||||
if newly_rerun:
|
||||
print(f"[scanner] {newly_rerun} test(s) marked as rerun-required (scheduled but not completed)")
|
||||
|
||||
Reference in New Issue
Block a user