From a08d806a485547adddf73a0329dccdab2ad1cecb Mon Sep 17 00:00:00 2001 From: Maria A Nunez Date: Thu, 11 Jun 2026 10:20:27 -0400 Subject: [PATCH] Fix flaky-test Mattermost table for colspan section rows (#36993) * Fix flaky table conversion for colspan section rows The mikepenz flaky_summary HTML contains per-suite section-header rows (...) that markdown tables cannot represent. The sed pipeline only matched bare / with text-only content, so those rows leaked raw HTML and broke the rendered table in Mattermost. Replace the sed/awk conversion with an inline python3 HTML parser that keeps only rows matching the header column count (dropping the section-header rows), unescapes HTML entities, escapes in-cell pipes, and emits a flat markdown table. Co-authored-by: Maria A Nunez * Collapse whitespace in flaky table cells str.strip() only trims leading/trailing whitespace, so an embedded newline (including one decoded from an entity like ) would remain and break the single-line markdown table row. Collapse all internal whitespace to single spaces when rendering each cell. Co-authored-by: Maria A Nunez --------- Co-authored-by: Cursor Agent --- .github/workflows/server-ci-report.yml | 72 +++++++++++++++++++++----- 1 file changed, 59 insertions(+), 13 deletions(-) diff --git a/.github/workflows/server-ci-report.yml b/.github/workflows/server-ci-report.yml index 2d07ee869ed..1927328902a 100644 --- a/.github/workflows/server-ci-report.yml +++ b/.github/workflows/server-ci-report.yml @@ -155,19 +155,65 @@ jobs: PR_URL="${SERVER_URL}/${REPO}/pull/${PR_NUMBER}" # Convert the HTML flaky summary into a Mattermost markdown table. - # Escape content pipes FIRST (HTML tags contain no '|', so any '|' is cell - # text), then strip tags, decode entities, and build delimiters. - TABLE_MD=$(printf '%s' "$FLAKY_SUMMARY" \ - | sed -E 's#\|#\\|#g' \ - | sed -E 's##\n#g; s###g; s###g' \ - | sed -E 's###g' \ - | sed -E 's#<#<#g; s#>#>#g; s#&#\&#g; s#"#"#g' \ - | sed -E 's##| \1 #g; s##| \1 #g' \ - | sed -E 's#[[:space:]]*$# |#' \ - | sed '/^[[:space:]|]*$/d') - # Insert markdown header separator after the first (header) row - TABLE_MD=$(printf '%s' "$TABLE_MD" \ - | awk 'NR==1{print; print "|---|---|"; next} {print}') + # The summary contains a header row plus, per suite, a section-header row + # () that markdown tables cannot + # represent. Parse the HTML, keep only rows matching the header's column + # count (dropping section-header rows), and emit a flat markdown table. + TABLE_MD=$(python3 - <<'PY' + import os, html + from html.parser import HTMLParser + + + class FlakyTableParser(HTMLParser): + def __init__(self): + super().__init__() + self.rows = [] + self.row = None + self.cell = None + + def handle_starttag(self, tag, attrs): + if tag == "tr": + self.row = [] + elif tag in ("td", "th"): + self.cell = [] + + def handle_endtag(self, tag): + if tag in ("td", "th") and self.cell is not None: + self.row.append("".join(self.cell)) + self.cell = None + elif tag == "tr" and self.row is not None: + self.rows.append(self.row) + self.row = None + + def handle_data(self, data): + if self.cell is not None: + self.cell.append(data) + + + parser = FlakyTableParser() + parser.feed(os.environ.get("FLAKY_SUMMARY", "")) + + rows = parser.rows + if rows: + width = len(rows[0]) + # Keep header + data rows; drop colspan section-header rows. + rows = [r for r in rows if len(r) == width] + + + def cell(text): + # Collapse all whitespace (incl. newlines) so a cell stays on one + # line; otherwise an embedded newline would break the markdown row. + text = " ".join(html.unescape(text).split()) + return text.replace("|", "\\|") + + + if len(rows) >= 2: + lines = ["| " + " | ".join(cell(c) for c in rows[0]) + " |", + "|" + "|".join(["---"] * width) + "|"] + lines += ["| " + " | ".join(cell(c) for c in r) + " |" for r in rows[1:]] + print("\n".join(lines)) + PY + ) # Use real newlines; a literal "\n" renders verbatim in Mattermost. NL=$'\n'
([^<]*)([^<]*)...