[code-simplifier] Deduplicate exit-code explanation formatting in AzureDevOpsSummaryReporter
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 25/100
Research direction
The duplicated exit-code segment sits in AppendModuleDiagnostics and AppendStatusStrip in src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/AzureDevOpsSummaryReporter.Markdown.cs, and the issue proposes a shared AppendExitCodeExplanation helper. A patch already exists on the branch copilot/simplify-azdo-exit-code-formatting-6abedbdc5994b9cf, so review that branch rather than starting fresh. Done means the rendered Markdown is byte-identical and AzureDevOpsSummaryReporterTests in Microsoft.Testing.Extensions.UnitTests still pass.
Written by the indexing model from the issue text.
Description
[!TIP]
Your pull request is ready to create! 🎉 ✅Everything is OK—the changes have been pushed to branch
copilot/simplify-azdo-exit-code-formatting-6abedbdc5994b9cf. Please review the changes, including any protected files, before creating the pull request.The original pull request description is below.
Code Simplification - 2026-10-16
This PR simplifies code recently added in #11970 (Improve Azure DevOps summary reports with exit code explanations) to reduce duplication while preserving all functionality.
Files Simplified
src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/AzureDevOpsSummaryReporter.Markdown.cs- Extracted a privateAppendExitCodeExplanationhelper that renders the"Name — Reason"segment, which was duplicated verbatim betweenAppendModuleDiagnosticsandAppendStatusStrip.
Improvements Made
-
Reduced Duplication
- Both methods previously repeated the identical three-call chain (
CiRunSummaryExitCode.GetName(...)," — ",CiRunSummaryExitCode.GetReason(..., AzureDevOpsResources.ResourceManager)). This is now a single shared private method.
- Both methods previously repeated the identical three-call chain (
-
Enhanced Clarity
- Each call site now reads as "append the surrounding markup, then append the exit-code explanation", making the structure of the rendered string easier to follow.
Changes Based On
Recent changes from:
- #11970 - [WIP] Improve Azure DevOps summary reports with exit code explanations
Testing
- ✅
dotnet buildofMicrosoft.Testing.Extensions.AzureDevOpsReport(all target frameworks) succeeds with 0 warnings/errors - ✅
Microsoft.Testing.Extensions.UnitTests→AzureDevOpsSummaryReporterTests(24 tests) all pass - ✅ No functional changes - the rendered Markdown output is byte-for-byte identical (same string literals in the same order)
Review Focus
Please verify:
- The extracted helper preserves identical output ordering and punctuation
- No other duplicate instances of this pattern were missed
[!NOTE]
GitHub Actions is not permitted to create or approve pull requests in this repository.
The changes have been pushed to branch
copilot/simplify-azdo-exit-code-formatting-6abedbdc5994b9cfand are ready to review.
To fix the permissions issue, go to Settings → Actions → General and enable Allow GitHub Actions to create and approve pull requests. See also: gh-aw FAQ
Show patch preview (32 of 56 lines)
From e42cbf728142b7b748ca3642bd2b0cb71c83e752 Mon Sep 17 00:00:00 2001
X-GH-AW-Base-Commit: 88788a9eb5b067b3b96e3c5ad16511231a2fb463
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Fri, 16 Oct 2026 13:28:53 +0000
Subject: [PATCH] Extract AppendExitCodeExplanation helper to deduplicate
exit-code formatting
Co-authored-by: Copilot <[email protected]>
---
.../AzureDevOpsSummaryReporter.Markdown.cs | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/AzureDevOpsSummaryReporter.Markdown.cs b/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/AzureDevOpsSummaryReporter.Markdown.cs
index 2636d7c..a340b32 100644
--- a/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/AzureDevOpsSummaryReporter.Markdown.cs
+++ b/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/AzureDevOpsSummaryReporter.Markdown.cs
@@ -189,9 +189,9 @@ private static int AppendModuleDiagnostics(
string heading = new('#', headingLevel);
if (includeExitCode && module.ExitCode != 0)
{
- builder.Append("> Module exit code: `").Append(module.ExitCode.ToString(CultureInfo.InvariantCulture)).Append("` (")
- .Append(CiRunSummaryExitCode.GetName(module.ExitCode)).Append(" — ")
- .Append(CiRunSummaryExitCode.GetReason(module.ExitCode, AzureDevOpsResources.ResourceManager)).Append(")\n\n");
+ builder.Append("> Module exit code: `").Append(module.ExitCode.ToString(CultureInfo.InvariantCulture)).Append("` (");
+ AppendExitCodeExplanation(builder, module.ExitCode);
+ builder.Append(")\n\n");
}
if (module.TopFailingClasses.Length > 0)
@@ -428,14 +428,19 @@ private static void AppendStatusStrip(
builder.Append(" · ⏱ **").Append(duration is { } value ? FormatDuration(value) : "Unavailable").Append("**");
... (truncated)
[!WARNING]
Firewall blocked 88 domains
The following domains were blocked by the firewall during workflow execution:
0t3vsblobprodcus362.vsblob.vsassets.io11vvsblobprodcus336.vsblob.vsassets.io1javsblobprodcus364.vsblob.vsassets.io1k9vsblobprodcus379.vsblob.vsassets.io1oavsblobprodcus350.vsblob.vsassets.io1p7vsblobprodcus324.vsblob.vsassets.io1s1vsblobprodcus386.vsblob.vsassets.io37bvsblobprodcus311.vsblob.vsassets.io37cvsblobprodcus359.vsblob.vsassets.io4m6vsblobprodcus384.vsblob.vsassets.io4myvsblobprodcus32.vsblob.vsassets.io4vyvsblobprodcus361.vsblob.vsassets.io4zjvsblobprodcus390.vsblob.vsassets.io51yvsblobprodcus36.vsblob.vsassets.io5dkvsblobprodcus355.vsblob.vsassets.io5rqvsblobprodcus385.vsblob.vsassets.io6s7vsblobprodcus313.vsblob.vsassets.io7k6vsblobprodcus337.vsblob.vsassets.io7tjvsblobprodcus341.vsblob.vsassets.io80zvsblobprodcus35.vsblob.vsassets.io8xbvsblobprodcus382.vsblob.vsassets.io96bvsblobprodcus338.vsblob.vsassets.ioajhvsblobprodcus363.vsblob.vsassets.iobcnvsblobprodcus378.vsblob.vsassets.iobuilds.dotnet.microsoft.comc78vsblobprodcus322.vsblob.vsassets.iocflvsblobprodcus383.vsblob.vsassets.ioci.dot.netckzvsblobprodcus347.vsblob.vsassets.iod0svsblobprodcus381.vsblob.vsassets.iodata.nuget.orgdlbvsblobprodcus316.vsblob.vsassets.ioe7bvsblobprodcus348.vsblob.vsassets.iofdpvsblobprodcus345.vsblob.vsassets.iofrdvsblobprodcus327.vsblob.vsassets.iogbsvsblobprodcus365.vsblob.vsassets.iogervsblobprodcus329.vsblob.vsassets.ioh6tvsblobprodcus346.vsblob.vsassets.ioi1qvsblobprodcus353.vsblob.vsassets.ioimzvsblobprodcus368.vsblob.vsassets.iojd4vsblobprodcus366.vsblob.vsassets.iojosvsblobprodcus372.vsblob.vsassets.iojrqvsblobprodcus343.vsblob.vsassets.iok0ivsblobprodcus356.vsblob.vsassets.iok4kvsblobprodcus344.vsblob.vsassets.iokgfvsblobprodcus314.vsblob.vsassets.iokh4vsblobprodcus325.vsblob.vsassets.iokijvsblobprodcus387.vsblob.vsassets.iokmuvsblobprodcus389.vsblob.vsassets.iokxqvsblobprodcus376.vsblob.vsassets.iol49vsblobprodcus358.vsblob.vsassets.iol7avsblobprodcus319.vsblob.vsassets.ioljcvsblobprodcus317.vsblob.vsassets.iolylvsblobprodcus31.vsblob.vsassets.iom16vsblobprodcus374.vsblob.vsassets.iom6xvsblobprodcus342.vsblob.vsassets.iom8dvsblobprodcus37.vsblob.vsassets.iomfjvsblobprodcus373.vsblob.vsassets.ion3kvsblobprodcus335.vsblob.vsassets.ionn8vsblobprodcus340.vsblob.vsassets.ioo3svsblobprodcus318.vsblob.vsassets.ioofvvsblobprodcus315.vsblob.vsassets.iop2ovsblobprodcus312.vsblob.vsassets.iopc2vsblobprodcus360.vsblob.vsassets.iopdfvsblobprodcus380.vsblob.vsassets.iope3vsblobprodcus354.vsblob.vsassets.iope4vsblobprodcus351.vsblob.vsassets.iopkgs.dev.azure.compkvvsblobprodcus321.vsblob.vsassets.iorcxvsblobprodcus328.vsblob.vsassets.ios4uvsblobprodcus326.vsblob.vsassets.ios8mvsblobprodcus38.vsblob.vsassets.iose1vsblobprodcus349.vsblob.vsassets.iosqdvsblobprodcus333.vsblob.vsassets.iost8vsblobprodcus339.vsblob.vsassets.iotphvsblobprodcus375.vsblob.vsassets.iou3hvsblobprodcus371.vsblob.vsassets.iou6ovsblobprodcus377.vsblob.vsassets.ioukkvsblobprodcus352.vsblob.vsassets.iouy6vsblobprodcus34.vsblob.vsassets.iov53vsblobprodcus320.vsblob.vsassets.iovb4vsblobprodcus33.vsblob.vsassets.iovwvvsblobprodcus334.vsblob.vsassets.iox3yvsblobprodcus370.vsblob.vsassets.ioxupvsblobprodcus332.vsblob.vsassets.ioyluvsblobprodcus367.vsblob.vsassets.ioyttvsblobprodcus357.vsblob.vsassets.ioytvvsblobprodcus310.vsblob.vsassets.ioTo allow these domains, add them to the
network.allowedlist in your workflow frontmatter:network: allowed: - defaults - "0t3vsblobprodcus362.vsblob.vsassets.io" - "11vvsblobprodcus336.vsblob.vsassets.io" - "1javsblobprodcus364.vsblob.vsassets.io" - "1k9vsblobprodcus379.vsblob.vsassets.io" - "1oavsblobprodcus350.vsblob.vsassets.io" - "1p7vsblobprodcus324.vsblob.vsassets.io" - "1s1vsblobprodcus386.vsblob.vsassets.io" - "37bvsblobprodcus311.vsblob.vsassets.io" - "37cvsblobprodcus359.vsblob.vsassets.io" - "4m6vsblobprodcus384.vsblob.vsassets.io" - "4myvsblobprodcus32.vsblob.vsassets.io" - "4vyvsblobprodcus361.vsblob.vsassets.io" - "4zjvsblobprodcus390.vsblob.vsassets.io" - "51yvsblobprodcus36.vsblob.vsassets.io" - "5dkvsblobprodcus355.vsblob.vsassets.io" - "5rqvsblobprodcus385.vsblob.vsassets.io" - "6s7vsblobprodcus313.vsblob.vsassets.io" - "7k6vsblobprodcus337.vsblob.vsassets.io" - "7tjvsblobprodcus341.vsblob.vsassets.io" - "80zvsblobprodcus35.vsblob.vsassets.io" - "8xbvsblobprodcus382.vsblob.vsassets.io" - "96bvsblobprodcus338.vsblob.vsassets.io" - "ajhvsblobprodcus363.vsblob.vsassets.io" - "bcnvsblobprodcus378.vsblob.vsassets.io" - "builds.dotnet.microsoft.com" - "c78vsblobprodcus322.vsblob.vsassets.io" - "cflvsblobprodcus383.vsblob.vsassets.io" - "ci.dot.net" - "ckzvsblobprodcus347.vsblob.vsassets.io" - "d0svsblobprodcus381.vsblob.vsassets.io" - "data.nuget.org" - "dlbvsblobprodcus316.vsblob.vsassets.io" - "e7bvsblobprodcus348.vsblob.vsassets.io" - "fdpvsblobprodcus345.vsblob.vsassets.io" - "frdvsblobprodcus327.vsblob.vsassets.io" - "gbsvsblobprodcus365.vsblob.vsassets.io" - "gervsblobprodcus329.vsblob.vsassets.io" - "h6tvsblobprodcus346.vsblob.vsassets.io" - "i1qvsblobprodcus353.vsblob.vsassets.io" - "imzvsblobprodcus368.vsblob.vsassets.io" - "jd4vsblobprodcus366.vsblob.vsassets.io" - "josvsblobprodcus372.vsblob.vsassets.io" - "jrqvsblobprodcus343.vsblob.vsassets.io" - "k0ivsblobprodcus356.vsblob.vsassets.io" - "k4kvsblobprodcus344.vsblob.vsassets.io" - "kgfvsblobprodcus314.vsblob.vsassets.io" - "kh4vsblobprodcus325.vsblob.vsassets.io" - "kijvsblobprodcus387.vsblob.vsassets.io" - "kmuvsblobprodcus389.vsblob.vsassets.io" - "kxqvsblobprodcus376.vsblob.vsassets.io" - "l49vsblobprodcus358.vsblob.vsassets.io" - "l7avsblobprodcus319.vsblob.vsassets.io" - "ljcvsblobprodcus317.vsblob.vsassets.io" - "lylvsblobprodcus31.vsblob.vsassets.io" - "m16vsblobprodcus374.vsblob.vsassets.io" - "m6xvsblobprodcus342.vsblob.vsassets.io" - "m8dvsblobprodcus37.vsblob.vsassets.io" - "mfjvsblobprodcus373.vsblob.vsassets.io" - "n3kvsblobprodcus335.vsblob.vsassets.io" - "nn8vsblobprodcus340.vsblob.vsassets.io" - "o3svsblobprodcus318.vsblob.vsassets.io" - "ofvvsblobprodcus315.vsblob.vsassets.io" - "p2ovsblobprodcus312.vsblob.vsassets.io" - "pc2vsblobprodcus360.vsblob.vsassets.io" - "pdfvsblobprodcus380.vsblob.vsassets.io" - "pe3vsblobprodcus354.vsblob.vsassets.io" - "pe4vsblobprodcus351.vsblob.vsassets.io" - "pkgs.dev.azure.com" - "pkvvsblobprodcus321.vsblob.vsassets.io" - "rcxvsblobprodcus328.vsblob.vsassets.io" - "s4uvsblobprodcus326.vsblob.vsassets.io" - "s8mvsblobprodcus38.vsblob.vsassets.io" - "se1vsblobprodcus349.vsblob.vsassets.io" - "sqdvsblobprodcus333.vsblob.vsassets.io" - "st8vsblobprodcus339.vsblob.vsassets.io" - "tphvsblobprodcus375.vsblob.vsassets.io" - "u3hvsblobprodcus371.vsblob.vsassets.io" - "u6ovsblobprodcus377.vsblob.vsassets.io" - "ukkvsblobprodcus352.vsblob.vsassets.io" - "uy6vsblobprodcus34.vsblob.vsassets.io" - "v53vsblobprodcus320.vsblob.vsassets.io" - "vb4vsblobprodcus33.vsblob.vsassets.io" - "vwvvsblobprodcus334.vsblob.vsassets.io" - "x3yvsblobprodcus370.vsblob.vsassets.io" - "xupvsblobprodcus332.vsblob.vsassets.io" - "yluvsblobprodcus367.vsblob.vsassets.io" - "yttvsblobprodcus357.vsblob.vsassets.io" - "ytvvsblobprodcus310.vsblob.vsassets.io"See Network Configuration for more information.
🤖 Automated content by GitHub Copilot. Generated by the Code Simplifier workflow. · copilot · auto · 108.4 AIC · ⌖ 14.8 AIC · ⊞ 14.8K · [◷]( · ◷)
Add this agentic workflow to your repo
To install this agentic workflow, run
gh aw add githubnext/agentics/workflows/code-simplifier.md@main
- expires on Oct 17, 2026, 1:31 PM UTC
- Dominant language
- C#
- Stars
- 1.1k
- Forks
- 312
- Avg merge
- 9h 13m
- Merged PRs (30d)
- 411
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from microsoft/testfx
-
agentic-workflows area/performance type/automation
Difficulty 4/5 3-5 days Newbie friendliness 15/100
Maintainers usually reply within 1 day
-
[duplicate-code] Duplicate `HasDuplicateModuleIdentity` logic between AzureDevOps and GitHub Actions reportersPossibly taken @Evangelink claimed this today. Opentype/automation type/tech-debt
microsoft/testfx#12000 · 1 reaction · 2 assignees ·
Maintainers usually reply within 1 day
-
[test-improver] Add unit tests for DotnetTestConnection.StartServerControlChannelAsync guard conditionsPossibly taken @Evangelink claimed this today. Openarea/mtp needs/triage
microsoft/testfx#11998 · 1 reaction · 2 assignees ·
Maintainers usually reply within 1 day
-
area/mtp-github-actions-report external/dotnet-test needs/triage
Difficulty 4/5 3-5 days Newbie friendliness 56/100
Maintainers usually reply within 1 day
-
Allow a trailing CancellationToken parameter on MSTest test methodsPossibly taken @Evangelink claimed this 2 days ago. Openarea/mstest area/parameterized-tests needs/triage
Difficulty 4/5 3-5 days Newbie friendliness 22/100
Maintainers usually reply within 1 day
All issues in microsoft/testfx
Similar issues
-
bug priority: P2
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
:watch: Not Triaged dotnet-csharp/svc fundamentals/subsvc
Difficulty 1/5 Under an hour Newbie friendliness 88/100
Maintainers usually reply within 1 day
-
Wrong values of Kernel32.FileShare.Delete and Kernel32.FileAttributes.PosixSemanticsPossibly taken @ElectLive claimed this today. Openbug good first issue help wanted
Difficulty 1/5 Under an hour Newbie friendliness 83/100
ForNeVeR/TruePath#241 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
files-community/Files#19047 ·
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day