feat(ci): swap Python's JUnit XML parser for the native Rust parser#1465
Merged
mergify[bot] merged 1 commit intoMay 29, 2026
Conversation
This was referenced May 27, 2026
Member
Author
|
This pull request is part of a Mergify stack:
|
This was referenced May 27, 2026
Contributor
Merge ProtectionsYour pull request matches the following merge protections and will not be merged until they are valid. 🟢 🤖 Continuous IntegrationWonderful, this rule succeeded.
🟢 👀 Review RequirementsWonderful, this rule succeeded.
🟢 Enforce conventional commitWonderful, this rule succeeded.Make sure that we follow https://www.conventionalcommits.org/en/v1.0.0/
🟢 🔎 ReviewsWonderful, this rule succeeded.
🟢 📕 PR descriptionWonderful, this rule succeeded.
|
b1b850b to
d3fd85c
Compare
380699c to
aaf35b0
Compare
Member
Author
Revision history
|
d3fd85c to
2857e8a
Compare
aaf35b0 to
1dcc6df
Compare
854f5b9 to
3cd6489
Compare
3cd6489 to
f13743d
Compare
73fc577 to
64fccaf
Compare
Base automatically changed from
devs/jd/worktree-rust-port/port-ci-scopes-native-rust--635d39bc
to
main
May 29, 2026 09:52
Contributor
|
@jd this pull request is now in conflict 😩 |
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 `>` / `<` / `&`.
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
64fccaf to
f6a515e
Compare
JulianMaurin
approved these changes
May 29, 2026
sileht
approved these changes
May 29, 2026
Contributor
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
|
36 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
First layer of the
mergify ci junit-processport — replace thePython
xml.etree.ElementTreewalk inmergify_cli/ci/junit_processing/junit.pywith a call into anew 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 nesteddescendants. Within each suite, every
<testcase>becomes atyped
TestCasetagged with its result and (for failures anderrors) 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
GeneralRefevents into a per-failure buffer and trims onceat the closing tag — anything else would silently lose the chunk
before the first
>/</&.The subcommand emits a JSON object
{"suite_names": [...], "cases": [...]}—suite_namesliststestsuites in document order (ancestors before descendants,
matching Python's
findall(".//{*}testsuite")walk),casesisa flat array of typed test cases each tagged with the closest
enclosing suite name. The Python side now iterates
suite_namesto build one suite span per entry and looks up cases in a dict
keyed by
suite_name— preserving the nested-suite ordering theold ET walk produced.
This is a transitional bridge. When Phase C of the port lands
later in the stack (the native
ci junit-processorchestratorthat subsumes the entire command), the Python side of
junit-processand the_internal junit-parsesubcommandboth go away. Cleanup checklist for that follow-up:
Subcommands::Internal,InternalSubcommand,InternalJunitParseArgs,NativeCommand::InternalJunitParse,and the
("_internal", "junit-parse")entry inNATIVE_COMMANDSSerializederive +serialize_duration_secshelperon the parser types (only needed for the JSON wire format)
serde_jsondep onmergify-climergify_cli/ci/junit_processing/junit.py(or stripit down to the orchestrator pieces Phase C still needs)
Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com