Compare commits

...

8 Commits

Author SHA1 Message Date
d20e55d694 try catch 2025-11-05 08:07:05 -08:00
892bca899e use filelock to prevent multiple uploads 2025-11-04 14:31:38 -08:00
3c31b47e09 comment 2025-11-04 13:33:46 -08:00
6117a8b924 hide imports of some functions 2025-11-04 13:29:39 -08:00
c0d5cac11b only do if ci and upload while running 2025-11-04 13:29:39 -08:00
e9fbb79f43 more path stuff 2025-11-04 13:29:39 -08:00
526350579f some path stuff 2025-11-04 13:29:39 -08:00
c4e46911eb upload jsons while running 2025-11-04 13:29:39 -08:00
3 changed files with 90 additions and 4 deletions

View File

@ -73,7 +73,22 @@ from tools.testing.test_selections import (
ShardedTest,
THRESHOLD,
)
from tools.testing.upload_artifacts import zip_and_upload_artifacts
try:
from tools.testing.upload_artifacts import (
parse_xml_and_upload_json,
zip_and_upload_artifacts,
)
except ImportError:
# some imports in those files might fail, e.g., boto3 not installed. These
# functions are only needed under specific circumstances (CI) so we can
# define dummy functions here.
def parse_xml_and_upload_json():
pass
def zip_and_upload_artifacts(failed: bool):
pass
# Make sure to remove REPO_ROOT after import is done
@ -1887,6 +1902,7 @@ def run_tests(
def handle_complete(failure: Optional[TestFailure]):
failed = failure is not None
if IS_CI and options.upload_artifacts_while_running:
parse_xml_and_upload_json()
zip_and_upload_artifacts(failed)
if not failed:
return False

View File

@ -24,12 +24,14 @@ def parse_xml_report(
report: Path,
workflow_id: int,
workflow_run_attempt: int,
job_id: int | None = None,
) -> list[dict[str, Any]]:
"""Convert a test report xml file into a JSON-serializable list of test cases."""
print(f"Parsing {tag}s for test report: {report}")
job_id = get_job_id(report)
print(f"Found job id: {job_id}")
if job_id is None:
job_id = get_job_id(report)
print(f"Found job id: {job_id}")
test_cases: list[dict[str, Any]] = []

View File

@ -1,11 +1,16 @@
import glob
import gzip
import json
import os
import time
import zipfile
from functools import lru_cache
from pathlib import Path
from typing import Any
from typing import Any, Optional
from filelock import FileLock, Timeout
from tools.stats.upload_test_stats import parse_xml_report
REPO_ROOT = Path(__file__).resolve().parent.parent.parent
@ -140,3 +145,66 @@ def trigger_upload_test_stats_intermediate_workflow() -> None:
},
)
print(x.text)
def parse_xml_and_upload_json() -> None:
"""
Parse xml test reports that do not yet have a corresponding json report
uploaded to s3, and upload the json reports to s3. Use filelock to avoid
uploading the same file from multiple processes.
"""
try:
job_id: Optional[int] = int(os.environ.get("JOB_ID", 0))
if job_id == 0:
job_id = None
except (ValueError, TypeError):
job_id = None
try:
for xml_file in glob.glob(
f"{REPO_ROOT}/test/test-reports/**/*.xml", recursive=True
):
xml_path = Path(xml_file)
json_file = xml_path.with_suffix(".json")
lock = FileLock(str(json_file) + ".lock")
try:
lock.acquire(timeout=0) # immediately fails if already locked
if json_file.exists():
continue # already uploaded
test_cases = parse_xml_report(
"testcase",
xml_path,
int(os.environ.get("GITHUB_RUN_ID", "0")),
int(os.environ.get("GITHUB_RUN_ATTEMPT", "0")),
job_id,
)
line_by_line_jsons = "\n".join([json.dumps(tc) for tc in test_cases])
gzipped = gzip.compress(line_by_line_jsons.encode("utf-8"))
s3_key = (
json_file.relative_to(REPO_ROOT / "test/test-reports")
.as_posix()
.replace("/", "_")
)
get_s3_resource().put_object(
Body=gzipped,
Bucket="gha-artifacts",
Key=f"test_jsons_while_running/{os.environ.get('GITHUB_RUN_ID')}/{job_id}/{s3_key}",
ContentType="application/json",
ContentEncoding="gzip",
)
# We don't need to save the json file locally, but doing so lets us
# track which ones have been uploaded already. We could probably also
# check S3
with open(json_file, "w") as f:
f.write(line_by_line_jsons)
except Timeout:
continue # another process is working on this file
finally:
if lock.is_locked:
lock.release()
except Exception as e:
print(f"Failed to parse and upload json test reports: {e}")