Skip to content

Bump .NET SDK to 11.0.100-preview.7.26376.106 and nest merged TRX reports - #10277

Merged
Evangelink merged 5 commits into
mainfrom
dev/amauryleve/bump-sdk-enable-artifact-post-merge
Jul 28, 2026
Merged

Bump .NET SDK to 11.0.100-preview.7.26376.106 and nest merged TRX reports#10277
Evangelink merged 5 commits into
mainfrom
dev/amauryleve/bump-sdk-enable-artifact-post-merge

Conversation

@Evangelink

@Evangelink Evangelink commented Jul 28, 2026

Copy link
Copy Markdown
Member

Bumps the .NET SDK to a build that carries the SDK-side artifact post-processing orchestration, so RFC 018 phase 2 actually runs for this repo, and fixes a problem that enabling it surfaced.

Why now

The SDK-side orchestration (dotnet/sdk#55419) was backported to release/11.0.1xx-preview7 as dotnet/sdk#55453 and flowed into the VMR via [release/11.0.1xx-preview7] Source code updates from dotnet/sdk (dotnet/dotnet#7944). The first published SDK containing it is 11.0.100-preview.7.26376.106, so no wait for rc1 is needed.

Verified by scanning that SDK's dotnet.dll: ArtifactPostProcessingManager, ArtifactPostProcessingPlanner, SupportedPostProcessorKinds, SupportedPostProcessorExtensionsLegacy and IsArtifactPostProcessing are all present (all absent from the previously pinned 26366.102).

The problem enabling it surfaced

The SDK points the processor's output directory at the run's --results-directory, which already holds the per-module reports the merge consumed. TrxArtifactPostProcessor was therefore writing the merged report as a sibling of its own inputs.

Collecting a results directory with a non-recursive *.trx glob is near-universal: Arcade's "Publish TRX Test Results" step (eng/common/core-templates/job/job.yml, testResultsFiles: '*.trx'), the PublishTestResults@2 defaults, typical ReportGenerator setups. Every one of those would ingest the merged report and the reports it summarizes, double-counting every test. For this repo that also means feeding duplicated data to the --report-azdo-slow-test-history / --report-azdo-flaky-history options we run against our own pipeline history.

The fix

TrxArtifactPostProcessor now writes to <outputDirectory>/merged/, keeping the merged report out of those globs by construction instead of asking every consumer to special-case the merged file name. This is a one-line change to the output path plus a doc note; TRX is currently the only registered IArtifactPostProcessor.

Nesting also keeps the report co-located with its attachments, which a CI-side move could not. MergeToFileAsync derives the attachment deployment root from the output path and records it in the TRX as a relative runDeploymentRoot, so the report and its attachment tree must stay in the same directory for those references to resolve. Writing the report into the subdirectory moves both together.

RFC 018 gains a section (7.13) documenting the decision and its rationale.

Verification

End to end on the repo's own pinned SDK (no side-by-side SDK, no global.json override):

Out of process file artifacts produced:
  - artifacts\TestResults\...\merged\merged-4fbd4d3d91374b516991a76502a4442a.trx
TRX total
…DotnetTestProtocolContract.UnitTests_net8.0_x64.trx (root) 23
…TerminalReporterContract.UnitTests_net8.0_x64.trx (root) 2
merged/merged-4fbd4d3d….trx 25

A non-recursive *.trx glob at the results-directory root now sees only the two per-module reports.

New unit test ProcessAsync_NestsAttachmentDeploymentRootBesideTheMergedReport builds two inputs with colliding attachments, then resolves the merged TRX's recorded runDeploymentRoot the way a consumer would (relative to the report's own directory) and asserts both attachments are readable, that the report sits in merged/, and that neither a *.trx nor the deployment root is left in the results-directory root. Microsoft.Testing.Extensions.UnitTests: 787 total, 782 passed, 5 skipped, 0 failed. Full build.cmd -c Debug green (0 warnings, 0 errors).

Notes for reviewers

  • Earlier revision of this PR solved the double-publish with a park-merged-trx.yml pipeline step that moved the merged report after the fact. That has been dropped: Copilot's review correctly pointed out it would strand the attachment deployment root, and having CI chase the TRX's internal layout was the wrong layer. The current fix makes that class of bug impossible and touches no pipeline files.
  • The merged report is intentionally not published to the Tests tab; per-module reports remain the source of truth there and the merged view rides out in the Publish Test Results folders artifact.
  • Related: RFC 018, dotnet/sdk#47613, #7345.

Copilot AI review requested due to automatic review settings July 28, 2026 07:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Bumps the pinned .NET SDK to activate RFC 018 artifact post-processing and prevents merged TRX results from being double-published in CI.

Changes:

  • Updates the SDK to 11.0.100-preview.7.26376.106.
  • Adds cross-platform handling that logs and parks merged TRX reports.
  • Integrates the parking step into Windows, Linux, and macOS pipelines.
Show a summary per file
File Description
global.json Updates the pinned SDK version.
azure-pipelines.yml Adds merged-TRX handling to Windows jobs.
eng/pipelines/steps/test-non-windows.yml Adds merged-TRX handling to Linux/macOS jobs.
eng/pipelines/steps/park-merged-trx.yml Logs and relocates merged TRX reports.

Review details

  • Files reviewed: 4/4 changed files
  • Comments generated: 1
  • Review effort level: Medium

Comment thread eng/pipelines/steps/park-merged-trx.yml Outdated
@Evangelink
Evangelink enabled auto-merge (squash) July 28, 2026 07:33
@Evangelink Evangelink added the state/needs-review Awaiting review from the team. label Jul 28, 2026
Copilot AI review requested due to automatic review settings July 28, 2026 07:59
@Evangelink
Evangelink force-pushed the dev/amauryleve/bump-sdk-enable-artifact-post-merge branch from 9baffec to 9dbd93e Compare July 28, 2026 07:59
@Evangelink Evangelink changed the title Bump .NET SDK to 11.0.100-preview.7.26376.106 and enable artifact post-merge validation Bump .NET SDK to 11.0.100-preview.7.26376.106 and nest merged TRX reports Jul 28, 2026
@github-actions

This comment has been minimized.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

Comments suppressed due to low confidence (4)

docs/RFCs/018-Artifact-Post-Processing.md:461

  • Section 7.13 now makes nested output a processor requirement, but Appendix A.1 still tells implementers to use Path.Combine(outputDirectory, "merged.trx") (line 593), producing the sibling layout this section forbids. Update the illustrative output to <outputDirectory>/merged/merged.trx so the RFC is internally consistent.
Processors therefore write into a `merged/` subdirectory of the supplied output directory (`<outputDirectory>/merged/merged-<runId>.trx`). This keeps the merged artifact out of those globs by construction rather than requiring every consumer to special-case the merged file name.

src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxArtifactPostProcessor.cs:60

  • Before using this fixed child directory, reject a pre-existing symlink or junction. MergeToFileAsync treats Path.GetDirectoryName(outputPath) as its confinement base and checks reparse points only below that base, while dispatcher validation is lexical. Consequently, <outputDirectory>/merged -> outside redirects both report and attachment writes outside the supplied output directory and is still accepted. Please create and validate a real directory before merging.
        string outputPath = Path.Combine(outputDirectory, MergedReportDirectoryName, $"merged-{runId:N}.trx");

src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxArtifactPostProcessor.cs:56

  • These examples are inaccurate: PublishTestResults@2 defaults to the recursive **/TEST-*.xml pattern, not *.trx, and ReportGenerator consumes coverage reports rather than TRX test results. Arcade's explicit *.trx setting already demonstrates the actual issue; removing the unsupported examples keeps this rationale factual.
        // per-module reports, and the usual way those get consumed is a non-recursive '*.trx' glob (Arcade's
        // "Publish TRX Test Results" step, the PublishTestResults@2 defaults, ReportGenerator setups, ...).

docs/RFCs/018-Artifact-Post-Processing.md:459

  • PublishTestResults@2 does not default to *.trx; its default is the recursive **/TEST-*.xml, and ReportGenerator does not consume TRX files. Please retain the verified Arcade example but avoid presenting these tools as non-recursive TRX defaults.

This issue also appears on line 461 of the same file.

Orchestrators hand the processor an output directory, and `dotnet test` sets that to the run's `--results-directory` — the same directory that already holds the per-module reports the merge consumed. A processor that wrote its output directly there would make the merged artifact a **sibling of its own inputs**, which breaks the near-universal convention of collecting a results directory with a non-recursive glob (Arcade's "Publish TRX Test Results" step uses `*.trx`, as do the `PublishTestResults@2` defaults and typical ReportGenerator setups). Such a consumer would ingest the merged report *and* the reports it summarizes, double-counting every test.
  • Files reviewed: 4/4 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

@github-actions

This comment has been minimized.

Copilot AI review requested due to automatic review settings July 28, 2026 08:43

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

  • Files reviewed: 4/4 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

@github-actions

This comment has been minimized.

Evangelink and others added 2 commits July 28, 2026 10:53
…orts

Bumps global.json (tools.dotnet + sdk.version) to 11.0.100-preview.7.26376.106.
That build carries the SDK-side artifact post-processing orchestration
(dotnet/sdk#55419, backported to release/11.0.1xx-preview7 as dotnet/sdk#55453),
which flowed into the VMR via '[release/11.0.1xx-preview7] Source code updates
from dotnet/sdk' (dotnet/dotnet#7944), so RFC 018 phase 2 now actually runs for
this repo's multi-module 'dotnet test' invocations.

Enabling it surfaced a problem that is not specific to this repo. The SDK points
the processor's output directory at the run's --results-directory, which already
holds the per-module reports the merge consumed, so TrxArtifactPostProcessor was
writing the merged report as a sibling of its own inputs. Collecting a results
directory with a non-recursive '*.trx' glob is near-universal (Arcade's 'Publish
TRX Test Results' step, the PublishTestResults@2 defaults, typical
ReportGenerator setups), and every such consumer would ingest both the merged
report and the reports it summarizes, double-counting every test.

TrxArtifactPostProcessor now writes to '<outputDirectory>/merged/', which keeps
the merged report out of those globs by construction instead of asking each
consumer to special-case the merged file name.

Nesting also keeps the report co-located with its attachments, which a
CI-side move could not. MergeToFileAsync derives the attachment deployment root
from the output path and records it in the TRX as a relative runDeploymentRoot,
so the report and its attachment tree have to stay in the same directory for
those references to resolve; writing the report into the subdirectory moves both
together. Adds a regression test covering that, and asserting nothing of the
merged report is left in the results-directory root.

Verified end to end on this SDK: two MTP modules (23 + 2 tests) run through
'dotnet test' with a shared --results-directory produce
'merged/merged-<runId>.trx' with total=25, reported back over the existing pipe
as an out-of-process file artifact, with the per-module reports left intact at
the root and nothing else matching a non-recursive '*.trx' glob there.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4a6c06b2-7dcb-407e-bb9e-ca0c8302fa93
…rationale

Follow-up to the nesting change, addressing low-confidence review observations
that hold up on inspection.

'merged' is a fixed, predictable child name, and MergeToFileAsync confines its
writes to Path.GetDirectoryName(outputPath). A symlink/junction planted at that
name would therefore become the confinement base itself and silently redirect
both the report and its attachment tree outside the orchestrator-supplied output
directory, since Directory.CreateDirectory succeeds on an existing link and the
engine's existing reparse-point checks only cover components strictly below its
base. Materialize the directory in the processor and return null rather than
merge through a reparse point, which leaves the per-module reports untouched and
keeps the never-fail-the-run invariant. Covered by a new test that plants a
directory symlink and asserts nothing is written through it (NETCOREAPP only, as
Directory.CreateSymbolicLink is not available on net4x).

Also corrects the justification in both the code comment and RFC 018 section
7.13: PublishTestResults@2 defaults to the recursive '**/TEST-*.xml', not
'*.trx', and ReportGenerator consumes coverage reports rather than TRX, so those
two examples did not support the claim. Arcade's explicit
testResultsFiles: '*.trx' does, and is now the only example cited. Updates the
Appendix A.1 sketch, which still showed the sibling layout that 7.13 forbids.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4a6c06b2-7dcb-407e-bb9e-ca0c8302fa93
Copilot AI review requested due to automatic review settings July 28, 2026 08:55
@Evangelink
Evangelink force-pushed the dev/amauryleve/bump-sdk-enable-artifact-post-merge branch from bee0b88 to d37d73c Compare July 28, 2026 08:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

  • Files reviewed: 4/4 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

@github-actions

This comment has been minimized.

ProcessAsync_WithTwoInputs_WritesUniquelyNamedMergedReport had grown to cover
two unrelated concerns after the nesting assertions were added: where the merged
report is written, and that reprocessing the same inputs in a different order
reproduces it byte for byte. Splitting them keeps each test focused and makes a
failure point at one concern rather than both.

The extracted test is named for what it actually verifies - the inputs are
reordered, not merely repeated - and additionally asserts the output path is
unchanged, since the run id is derived from the ordered inputs and a reordering
regression would otherwise surface only as a byte mismatch.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4a6c06b2-7dcb-407e-bb9e-ca0c8302fa93
Copilot AI review requested due to automatic review settings July 28, 2026 09:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

  • Files reviewed: 4/4 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

@github-actions

This comment has been minimized.

@github-actions

Copy link
Copy Markdown
Contributor

❌ Build Failure Analysis

Root cause: The .xlf localization files in src/Analyzers/MSTest.Analyzers/xlf/ are out-of-date with Resources.resx.

The global.json SDK bump (from 11.0.100-preview.7.26359.11011.0.100-preview.7.26376.106) pulled in a newer microsoft.dotnet.xlifftasks package (11.0.0-beta.26377.3). This version detects that at least Resources.fr.xlf (and likely other *.xlf files) no longer match the current Resources.resx, causing the build to fail across all legs (Linux Release/Debug, macOS Debug/Release, Windows Debug/Release).

Error (same on every leg):

'xlf/Resources.fr.xlf' is out-of-date with 'Resources.resx'.
Run `msbuild /t:UpdateXlf` to update .xlf files
Project: src/Analyzers/MSTest.Analyzers/MSTest.Analyzers.csproj

Fix: Regenerate all XLF files for the analyzer project by running:

dotnet msbuild src/Analyzers/MSTest.Analyzers/MSTest.Analyzers.csproj /t:UpdateXlf

Then commit the updated src/Analyzers/MSTest.Analyzers/xlf/*.xlf files.

Note: Per repo guidelines, never manually edit .xlf files — always regenerate them with the UpdateXlf target.

🤖 Automated content by GitHub Copilot. Generated by the Build Failure Analysis workflow. · sonnet46 23.7 AIC · ⌖ 4.14 AIC · ⊞ 8K · [◷]( · )

@Evangelink

Copy link
Copy Markdown
Member Author

Correcting the automated root-cause analysis above, since it has now been posted twice and the suggested fix would discard translations.

The global.json SDK bump (from 11.0.100-preview.7.26359.11011.0.100-preview.7.26376.106) pulled in a newer microsoft.dotnet.xlifftasks package (11.0.0-beta.26377.3).

That is not where xlifftasks comes from. Its version tracks the Arcade SDK, not sdk.version. This branch pins "Microsoft.DotNet.Arcade.Sdk": "11.0.0-beta.26377.3", which is byte-identical to main and was set by 3e888dcc7 (#10273), not by anything in this PR. The only global.json difference between this branch and main is the two .NET SDK version lines.

The failure is pre-existing on main: build 1529393 on refs/heads/main (commit 0b557345, containing none of this PR's changes) fails with the byte-identical error.

Actual root cause: the neutral Resources.resx has a blank line where the French <target> carries a stray {0} placeholder, so XliffTasks reports the .xlf as stale.

Running /t:UpdateXlf here would not be a safe fix. It does not merely refresh formatting: it resets that unit to state="new" with the English source, discarding the French translation. That is a localization regression, and it would be masking a repo-wide breakage inside an unrelated SDK-bump PR.

#10281 ("Restore localization filters after #10268") already fixes exactly this, across the same file set. This PR is simply waiting on it; once it merges this branch picks it up and CI should clear. No action needed here.

Copilot AI review requested due to automatic review settings July 28, 2026 10:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

  • Files reviewed: 4/4 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

@github-actions

This comment has been minimized.

Copilot AI review requested due to automatic review settings July 28, 2026 11:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

  • Files reviewed: 4/4 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test quality grade — PR #10277

GradeTestMutationNotesHow to improve
A (90–100) mod TrxArtifactPostProcessorTests.
ProcessAsync_
WithTwoInputs_
WritesUniquelyNamedMergedReport
3/3 killed New assertions protect all three observable behaviors: directory name, parent path, and absence of TRX files in root.
A (90–100) new TrxArtifactPostProcessorTests.
ProcessAsync_
WithReorderedInputs_
ProducesIdenticalOutput
2/2 killed Clear AAA; path-equality and byte-equality assertions together kill ordering-stability and content-change mutations.
A (90–100) new TrxArtifactPostProcessorTests.
ProcessAsync_
NestsAttachmentDeploymentRootBesideTheMergedReport
3/3 killed Resolves the deployment root exactly as a consumer would and checks real attachment content; kills placement, relative-path, and content mutations.
A (90–100) new TrxArtifactPostProcessorTests.
ProcessAsync_
WhenMergedDirectoryIsAReparsePoint_
DoesNotMerge
2/2 killed Null-return and empty-outside-dir assertions together kill the guard-bypass mutation and the writes-through-symlink mutation.

This advisory comment was generated automatically. Grades are heuristic and informational — they do not block merging. Re-run with /grade-tests.

🤖 Automated content by GitHub Copilot. Generated by the Grade Tests on PR (on open / sync) workflow. · sonnet46 44 AIC · ⌖ 5.85 AIC · ⊞ 10.3K · [◷]( · )

@Evangelink
Evangelink merged commit 1da7d5e into main Jul 28, 2026
26 checks passed
@Evangelink
Evangelink deleted the dev/amauryleve/bump-sdk-enable-artifact-post-merge branch July 28, 2026 12:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state/needs-review Awaiting review from the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants