Skip to content

feat(ci): swap Python's JUnit XML parser for the native Rust parser#1465

Merged
mergify[bot] merged 1 commit into
mainfrom
devs/jd/worktree-rust-port/parse-junit-xml-reports-native-rust--7d0fb778
May 29, 2026
Merged

feat(ci): swap Python's JUnit XML parser for the native Rust parser#1465
mergify[bot] merged 1 commit into
mainfrom
devs/jd/worktree-rust-port/parse-junit-xml-reports-native-rust--7d0fb778

Conversation

@jd
Copy link
Copy Markdown
Member

@jd jd commented May 27, 2026

First layer of the mergify ci junit-process port — replace the
Python xml.etree.ElementTree walk in
mergify_cli/ci/junit_processing/junit.py with a call into a
new hidden Rust subcommand, mergify _internal junit-parse <FILE>,
that exposes the parser as JSON.

The Rust parser mirrors the Python implementation's accepted
dialect: <testsuites> root with nested <testsuite> children,
a bare <testsuite> root, or a <testsuite> root with nested
descendants. Within each suite, every <testcase> becomes a
typed TestCase tagged with its result and (for failures and
errors) the kind/message attributes plus the body text from the
first <failure> / <error> child.

quick-xml 0.40 splits text events around each entity reference,
so the parser accumulates body content across Text, CData,
and GeneralRef events into a per-failure buffer and trims once
at the closing tag — anything else would silently lose the chunk
before the first &gt; / &lt; / &amp;.

The subcommand emits a JSON object
{"suite_names": [...], "cases": [...]}suite_names lists
testsuites in document order (ancestors before descendants,
matching Python's findall(".//{*}testsuite") walk), cases is
a flat array of typed test cases each tagged with the closest
enclosing suite name. The Python side now iterates suite_names
to build one suite span per entry and looks up cases in a dict
keyed by suite_name — preserving the nested-suite ordering the
old ET walk produced.

This is a transitional bridge. When Phase C of the port lands
later in the stack (the native ci junit-process orchestrator
that subsumes the entire command), the Python side of
junit-process and the _internal junit-parse subcommand
both go away. Cleanup checklist for that follow-up:

  • delete Subcommands::Internal, InternalSubcommand,
    InternalJunitParseArgs, NativeCommand::InternalJunitParse,
    and the ("_internal", "junit-parse") entry in NATIVE_COMMANDS
  • delete the Serialize derive + serialize_duration_secs helper
    on the parser types (only needed for the JSON wire format)
  • drop the serde_json dep on mergify-cli
  • delete mergify_cli/ci/junit_processing/junit.py (or strip
    it down to the orchestrator pieces Phase C still needs)

Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com

@jd
Copy link
Copy Markdown
Member Author

jd commented May 27, 2026

This pull request is part of a Mergify stack:

# Pull Request Link
1 feat(ci): swap Python's JUnit XML parser for the native Rust parser #1465 👈
2 feat(ci): swap Python's OTLP encode+upload for the native Rust pipeline #1466
3 feat(ci): promote ci junit-process and its junit-upload alias to native Rust #1467

@mergify
Copy link
Copy Markdown
Contributor

mergify Bot commented May 27, 2026

Merge Protections

Your pull request matches the following merge protections and will not be merged until they are valid.

🟢 🤖 Continuous Integration

Wonderful, this rule succeeded.
  • all of:
    • check-success=ci-gate

🟢 👀 Review Requirements

Wonderful, this rule succeeded.
  • any of:
    • #approved-reviews-by>=2
    • author = dependabot[bot]
    • author = mergify-ci-bot
    • author = renovate[bot]

🟢 Enforce conventional commit

Wonderful, this rule succeeded.

Make sure that we follow https://www.conventionalcommits.org/en/v1.0.0/

  • title ~= ^(fix|feat|docs|style|refactor|perf|test|build|ci|chore|revert|ui)(?:\(.+\))?:

🟢 🔎 Reviews

Wonderful, this rule succeeded.
  • #changes-requested-reviews-by = 0
  • #review-requested = 0
  • #review-threads-unresolved = 0

🟢 📕 PR description

Wonderful, this rule succeeded.
  • body ~= (?ms:.{48,})

@mergify mergify Bot requested a review from a team May 27, 2026 08:08
@jd jd force-pushed the devs/jd/worktree-rust-port/port-ci-scopes-native-rust--635d39bc branch from b1b850b to d3fd85c Compare May 27, 2026 08:27
@jd jd force-pushed the devs/jd/worktree-rust-port/parse-junit-xml-reports-native-rust--7d0fb778 branch from 380699c to aaf35b0 Compare May 27, 2026 08:27
@jd jd temporarily deployed to func-tests-live May 27, 2026 08:27 — with GitHub Actions Inactive
@jd jd temporarily deployed to func-tests-live May 27, 2026 08:27 — with GitHub Actions Inactive
@jd
Copy link
Copy Markdown
Member Author

jd commented May 27, 2026

Revision history

# Type Changes Reason Date
1 initial 380699c 2026-05-27 08:27 UTC
2 rebase 380699c → aaf35b0 (rebase only) 2026-05-27 08:27 UTC
3 rebase aaf35b0 → 1dcc6df (rebase only) 2026-05-27 08:46 UTC
4 rebase 1dcc6df → 4778d48 (rebase only) 2026-05-27 10:04 UTC
5 rebase 4778d48 → e338014 (rebase only) 2026-05-27 10:15 UTC
6 content 23bd8a0 → 63399a1 (raw) Refactored Phase A from 'add Rust parser as library code (inert until Phase C)' into 'swap Python's XML parser for the native Rust parser via a hidden _internal junit-parse subprocess bridge'. Now … 2026-05-28 09:45 UTC
7 content 63399a1 → 73fc577 (raw) Switch the JUnit parser's text-event decoding from quick-xml's plain decode() to xml10_content() so CRLF line endings get normalized to LF per the XML 1.0 spec. Python's xml.etree.ElementTree did thi… 2026-05-29 06:35 UTC
8 rebase 73fc577 → 64fccaf (rebase only) 2026-05-29 08:31 UTC
9 rebase 64fccaf → f6a515e (rebase only) 2026-05-29 11:32 UTC

@mergify mergify Bot had a problem deploying to Mergify Merge Protections May 27, 2026 08:29 Failure
@jd jd force-pushed the devs/jd/worktree-rust-port/port-ci-scopes-native-rust--635d39bc branch from d3fd85c to 2857e8a Compare May 27, 2026 08:46
@jd jd force-pushed the devs/jd/worktree-rust-port/parse-junit-xml-reports-native-rust--7d0fb778 branch from aaf35b0 to 1dcc6df Compare May 27, 2026 08:46
@jd jd temporarily deployed to func-tests-live May 27, 2026 08:46 — with GitHub Actions Inactive
@jd jd temporarily deployed to func-tests-live May 27, 2026 08:46 — with GitHub Actions Inactive
@jd jd force-pushed the devs/jd/worktree-rust-port/port-ci-scopes-native-rust--635d39bc branch from 854f5b9 to 3cd6489 Compare May 29, 2026 06:35
@jd jd temporarily deployed to func-tests-live May 29, 2026 06:35 — with GitHub Actions Inactive
@jd jd temporarily deployed to func-tests-live May 29, 2026 06:35 — with GitHub Actions Inactive
@jd jd temporarily deployed to func-tests-live May 29, 2026 06:35 — with GitHub Actions Inactive
@mergify mergify Bot had a problem deploying to Mergify Merge Protections May 29, 2026 06:35 Failure
@jd jd force-pushed the devs/jd/worktree-rust-port/port-ci-scopes-native-rust--635d39bc branch from 3cd6489 to f13743d Compare May 29, 2026 08:31
@jd jd force-pushed the devs/jd/worktree-rust-port/parse-junit-xml-reports-native-rust--7d0fb778 branch from 73fc577 to 64fccaf Compare May 29, 2026 08:31
@jd jd temporarily deployed to func-tests-live May 29, 2026 08:31 — with GitHub Actions Inactive
@jd jd temporarily deployed to func-tests-live May 29, 2026 08:31 — with GitHub Actions Inactive
@jd jd temporarily deployed to func-tests-live May 29, 2026 08:31 — with GitHub Actions Inactive
@mergify mergify Bot had a problem deploying to Mergify Merge Protections May 29, 2026 08:31 Failure
Base automatically changed from devs/jd/worktree-rust-port/port-ci-scopes-native-rust--635d39bc to main May 29, 2026 09:52
@mergify
Copy link
Copy Markdown
Contributor

mergify Bot commented May 29, 2026

@jd this pull request is now in conflict 😩

@mergify mergify Bot added the conflict label May 29, 2026
First layer of the `mergify ci junit-process` port — replace the
Python `xml.etree.ElementTree` walk in
`mergify_cli/ci/junit_processing/junit.py` with a call into a
new hidden Rust subcommand, `mergify _internal junit-parse <FILE>`,
that exposes the parser as JSON.

The Rust parser mirrors the Python implementation's accepted
dialect: `<testsuites>` root with nested `<testsuite>` children,
a bare `<testsuite>` root, or a `<testsuite>` root with nested
descendants. Within each suite, every `<testcase>` becomes a
typed `TestCase` tagged with its result and (for failures and
errors) the kind/message attributes plus the body text from the
first `<failure>` / `<error>` child.

quick-xml 0.40 splits text events around each entity reference,
so the parser accumulates body content across `Text`, `CData`,
and `GeneralRef` events into a per-failure buffer and trims once
at the closing tag — anything else would silently lose the chunk
before the first `&gt;` / `&lt;` / `&amp;`.

The subcommand emits a JSON object
`{"suite_names": [...], "cases": [...]}` — `suite_names` lists
testsuites in *document order* (ancestors before descendants,
matching Python's `findall(".//{*}testsuite")` walk), `cases` is
a flat array of typed test cases each tagged with the closest
enclosing suite name. The Python side now iterates `suite_names`
to build one suite span per entry and looks up cases in a dict
keyed by `suite_name` — preserving the nested-suite ordering the
old ET walk produced.

This is a transitional bridge. When Phase C of the port lands
later in the stack (the native `ci junit-process` orchestrator
that subsumes the entire command), the Python side of
`junit-process` and the `_internal junit-parse` subcommand
both go away. Cleanup checklist for that follow-up:
- delete `Subcommands::Internal`, `InternalSubcommand`,
  `InternalJunitParseArgs`, `NativeCommand::InternalJunitParse`,
  and the `("_internal", "junit-parse")` entry in `NATIVE_COMMANDS`
- delete the `Serialize` derive + `serialize_duration_secs` helper
  on the parser types (only needed for the JSON wire format)
- drop the `serde_json` dep on `mergify-cli`
- delete `mergify_cli/ci/junit_processing/junit.py` (or strip
  it down to the orchestrator pieces Phase C still needs)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Change-Id: I7d0fb77860d2d5b69b9e6f9aa9b4bb5af4f8be01
@jd jd force-pushed the devs/jd/worktree-rust-port/parse-junit-xml-reports-native-rust--7d0fb778 branch from 64fccaf to f6a515e Compare May 29, 2026 11:32
@jd jd temporarily deployed to func-tests-live May 29, 2026 11:32 — with GitHub Actions Inactive
@jd jd temporarily deployed to func-tests-live May 29, 2026 11:32 — with GitHub Actions Inactive
@mergify mergify Bot deployed to Mergify Merge Protections May 29, 2026 11:33 Active
@mergify mergify Bot removed the conflict label May 29, 2026
@mergify mergify Bot requested a review from a team May 29, 2026 13:03
@mergify
Copy link
Copy Markdown
Contributor

mergify Bot commented May 29, 2026

Merge Queue Status

This pull request spent 16 minutes 14 seconds in the queue, including 15 minutes 28 seconds running CI.

Required conditions to merge

mergify Bot added a commit that referenced this pull request May 29, 2026
@mergify mergify Bot added the queued label May 29, 2026
@mergify mergify Bot merged commit 3bfb078 into main May 29, 2026
36 checks passed
@mergify mergify Bot deleted the devs/jd/worktree-rust-port/parse-junit-xml-reports-native-rust--7d0fb778 branch May 29, 2026 14:00
@mergify mergify Bot removed the queued label May 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants