|
1 | 1 | import logging |
| 2 | +import re |
2 | 3 | from dataclasses import dataclass |
3 | 4 | from datetime import datetime |
4 | 5 | from enum import IntEnum, auto |
|
22 | 23 | CACTUS_ORCHESTRATOR_REQUEST_TIMEOUT_SPAWN = int(env.get("CACTUS_ORCHESTRATOR_REQUEST_TIMEOUT_SPAWN", "120")) |
23 | 24 |
|
24 | 25 |
|
| 26 | +HEADER_USER_NAME = "CACTUS-User-Name" |
| 27 | +HEADER_TEST_ID = "CACTUS-Test-Id" |
| 28 | +HEADER_RUN_ID = "CACTUS-Run-Id" |
| 29 | +HEADER_GROUP_ID = "CACTUS-Group-Id" |
| 30 | +HEADER_GROUP_NAME = "CACTUS-Group-Name" |
| 31 | + |
| 32 | + |
25 | 33 | @dataclass |
26 | 34 | class RunResponse: |
27 | 35 | """Ideally this would be defined in a shared cactus-schema but that doesn't exist. Instead, ensure this remains |
@@ -191,6 +199,18 @@ def generate_uri(path: str) -> str: |
191 | 199 | return CACTUS_ORCHESTRATOR_BASEURL.rstrip("/") + "/" + path |
192 | 200 |
|
193 | 201 |
|
| 202 | +def file_name_safe(v: str) -> str: |
| 203 | + return re.sub(r"[^A-Za-z0-9_\-]", "_", v) |
| 204 | + |
| 205 | + |
| 206 | +def generate_run_artifact_file_name(response: requests.Response, run_id: str) -> str: |
| 207 | + raw_run_id = response.headers.get(HEADER_RUN_ID, run_id) |
| 208 | + user = response.headers.get(HEADER_USER_NAME, "") |
| 209 | + test_id = response.headers.get(HEADER_TEST_ID, "") |
| 210 | + group_name = response.headers.get(HEADER_GROUP_NAME, "") |
| 211 | + return file_name_safe(f"{raw_run_id}_{test_id}_{user}_{group_name}_artifacts") + ".zip" |
| 212 | + |
| 213 | + |
194 | 214 | def fetch_procedures(access_token: str, page: int) -> Pagination[ProcedureResponse] | None: |
195 | 215 | """Fetch the list of test procedures for the dropdown""" |
196 | 216 | uri = generate_uri(f"/procedure?page={page}") |
@@ -391,14 +411,14 @@ def finalise_run(access_token: str, run_id: str) -> bytes | None: |
391 | 411 | return response.content |
392 | 412 |
|
393 | 413 |
|
394 | | -def fetch_run_artifact(access_token: str, run_id: str) -> bytes | None: |
395 | | - """Given an already started run - finalise it and return the resulting ZIP file bytes""" |
| 414 | +def fetch_run_artifact(access_token: str, run_id: str) -> tuple[bytes | None, str]: |
| 415 | + """Given an already started run - finalise it and return the resulting ZIP file bytes / file name""" |
396 | 416 | uri = generate_uri(f"/run/{run_id}/artifact") |
397 | 417 | response = safe_request("GET", uri, generate_headers(access_token), CACTUS_ORCHESTRATOR_REQUEST_TIMEOUT_DEFAULT) |
398 | 418 | if response is None or not is_success_response(response): |
399 | | - return None |
| 419 | + return (None, "") |
400 | 420 |
|
401 | | - return response.content |
| 421 | + return (response.content, generate_run_artifact_file_name(response, run_id)) |
402 | 422 |
|
403 | 423 |
|
404 | 424 | def fetch_runs_for_group( |
@@ -750,14 +770,14 @@ def admin_fetch_group_procedure_run_summaries( |
750 | 770 | ] |
751 | 771 |
|
752 | 772 |
|
753 | | -def admin_fetch_run_artifact(access_token: str, run_id: str) -> bytes | None: |
754 | | - """Given an already started run - finalise it and return the resulting ZIP file bytes""" |
| 773 | +def admin_fetch_run_artifact(access_token: str, run_id: str) -> tuple[bytes | None, str]: |
| 774 | + """Given an already started run - finalise it and return the resulting ZIP file bytes and ZIP file name""" |
755 | 775 | uri = generate_uri(f"/admin/run/{run_id}/artifact") |
756 | 776 | response = safe_request("GET", uri, generate_headers(access_token), CACTUS_ORCHESTRATOR_REQUEST_TIMEOUT_DEFAULT) |
757 | 777 | if response is None or not is_success_response(response): |
758 | | - return None |
| 778 | + return (None, "") |
759 | 779 |
|
760 | | - return response.content |
| 780 | + return (response.content, generate_run_artifact_file_name(response, run_id)) |
761 | 781 |
|
762 | 782 |
|
763 | 783 | def admin_fetch_run_group_artifact(access_token: str, run_group_id: int) -> bytes | None: |
|
0 commit comments