Add per-spec fallback for categorized watcher grouped summaries

- update the categorized watcher to fall back to earlier per-spec Run Finished entries when a grouped Cloud Run Finished section is present but does not contain host rows
- broaden duration parsing so colon-form timings like 13:59 and 15:32 from per-spec Cypress summaries are converted into seconds correctly
- make grouped Mattermost posting resilient across categorized batches whose cloud-summary output is incomplete or inconsistent, not just a single distro family
This commit is contained in:
2026-03-26 21:28:27 -04:00
parent 3431c40af7
commit 4b3ed8cccd

View File

@@ -265,6 +265,14 @@ def extract_check_xml_timestamp_from_file(xml_path: Path) -> Optional[datetime]:
def parse_duration_seconds(raw: str) -> Optional[float]:
raw = " ".join(raw.split())
if re.fullmatch(r"\d+:\d+(?::\d+)?", raw):
parts = [int(part) for part in raw.split(":")]
if len(parts) == 2:
minutes, seconds = parts
return minutes * 60 + seconds
if len(parts) == 3:
hours, minutes, seconds = parts
return hours * 3600 + minutes * 60 + seconds
match = re.search(r"(?:(\d+)h\s+)?(?:(\d+)m\s+)?(\d+(?:\.\d+)?)(?:s)?", raw)
if not match:
return None
@@ -274,22 +282,11 @@ def parse_duration_seconds(raw: str) -> Optional[float]:
return hours * 3600 + minutes * 60 + seconds
def extract_completed_subrun_summaries(log_text: str, inventory: Dict[str, str]) -> List[Dict[str, object]]:
summaries: List[Dict[str, object]] = []
cloud_blocks = list(
re.finditer(
r"Cloud Run Finished(.*?)(?:🏁 Recorded Run:\s*(https://\S+)|\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3} - INFO - Detected 'Recorded Run' after 'Cloud Run Finished' - results uploaded successfully\.)",
log_text,
re.S,
)
)
for block in cloud_blocks:
block_text = block.group(1)
currents_url = block.group(2)
normalized = re.sub(r"\n\s*│\s*s\s*│", "s", block_text)
def extract_host_results_from_run_finished_segment(segment_text: str, inventory: Dict[str, str]) -> Dict[str, HostResult]:
host_results: Dict[str, HostResult] = {}
normalized = re.sub(r"\n\s*│\s*s\s*│", "s", segment_text)
for host_match in re.finditer(
r"\s+(atvm[^\s]+)\.ts\s+([0-9hms.\s]+?)\s+(\d+)\s+(\d+)\s+([-\d]+)\s+([-\d]+)\s+([-\d]+)",
r"\s+(atvm[^\s]+)\.ts\s+([0-9:hms.\s]+?)\s+(\d+)\s+(\d+)\s+([-\d]+)\s+([-\d]+)\s+([-\d]+)",
normalized,
re.S,
):
@@ -309,7 +306,28 @@ def extract_completed_subrun_summaries(log_text: str, inventory: Dict[str, str])
failures=failing,
duration_seconds=duration_seconds,
)
return host_results
def extract_completed_subrun_summaries(log_text: str, inventory: Dict[str, str]) -> List[Dict[str, object]]:
summaries: List[Dict[str, object]] = []
cloud_blocks = list(
re.finditer(
r"Cloud Run Finished(.*?)(?:🏁 Recorded Run:\s*(https://\S+)|\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3} - INFO - Detected 'Recorded Run' after 'Cloud Run Finished' - results uploaded successfully\.)",
log_text,
re.S,
)
)
previous_block_end = 0
for block in cloud_blocks:
block_text = block.group(1)
currents_url = block.group(2)
host_results = extract_host_results_from_run_finished_segment(block_text, inventory)
if not host_results:
prior_segment = log_text[previous_block_end:block.start()]
host_results = extract_host_results_from_run_finished_segment(prior_segment, inventory)
if not host_results:
previous_block_end = block.end()
continue
summaries.append(
{
@@ -317,6 +335,7 @@ def extract_completed_subrun_summaries(log_text: str, inventory: Dict[str, str])
"currents_url": currents_url,
}
)
previous_block_end = block.end()
return summaries