Unify template-resolve-and-sanitize pipeline in ArtifactNamingHelper - #9855

Merged
Amaury Levé (Evangelink) merged 1 commit into
mainfrom
dev/amauryleve/expert-bassoon
Jul 11, 2026
Merged

Unify template-resolve-and-sanitize pipeline in ArtifactNamingHelper#9855
Amaury Levé (Evangelink) merged 1 commit into
mainfrom
dev/amauryleve/expert-bassoon

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Fixes#9841.

Problem

ArtifactNamingService.ResolveFileName (in Microsoft.Testing.Platform) and ReportFileNameHelper.ResolveAndSanitize (in SharedExtensionHelpers) implemented the same algorithm: resolve template placeholders via ArtifactNamingHelper, split the result into directory + leaf, sanitize the leaf, and reassemble the path. The only real differences were where the process name/id came from and which sanitizer was used.

Change

Applied recommendation #2 from the issue (smaller, less invasive): extracted the shared pipeline into a single static overload ArtifactNamingHelper.ResolveAndSanitize(template, processName, processId, timestamp, sanitizeLeafFileName) that takes the leaf sanitizer as a Func<string, string> delegate.

  • ArtifactNamingService.ResolveFileName now delegates, passing ArtifactFileNameSanitizer.ReplaceInvalidFileNameChars.
  • ReportFileNameHelper.ResolveAndSanitize now delegates, passing ReportFileNameSanitizer.ReplaceInvalidFileNameChars. Its public signature is unchanged (matches the shipped InternalAPI), so no shipped-API churn.
  • The non-empty leaf-name guard that only ArtifactNamingService previously had is now applied on both paths.

The two sanitizers (ArtifactFileNameSanitizer / ReportFileNameSanitizer) are intentionally left as-is and passed in as delegates — consolidating them is tracked separately (the related issue referenced in #9841).

Notes

  • The new ArtifactNamingHelper.ResolveAndSanitize member is added to the InternalAPI.Unshipped.txt of every project that links the ArtifactNamingHelper source (RS0051).

Testing

  • Microsoft.Testing.Platform.UnitTests — ArtifactNaming* tests: 24/24 passed.
  • Microsoft.Testing.Extensions.UnitTests — ReportFileName* tests: 12/12 passed.
  • Report extensions (Trx/Html/JUnit/Ctrf/…) build clean with no RS0051 warnings.

Extract the shared resolve-template/split-path/sanitize-leaf/recombine pipeline into a single static ArtifactNamingHelper.ResolveAndSanitize overload that accepts a leaf sanitizer delegate. ArtifactNamingService and ReportFileNameHelper now both delegate to it, removing the near-identical duplicated logic described in #9841. The non-empty leaf guard is now applied on both paths.
Fixes#9841
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8c5b1087-7e14-45e5-a444-daf19d40d832
CopilotAI review requested due to automatic review settings July 11, 2026 12:12

CopilotAI 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

Unifies artifact template resolution and leaf-name sanitization in ArtifactNamingHelper, resolving #9841.

Changes:

  • Extracts the shared resolve-and-sanitize pipeline.
  • Delegates platform and report naming paths to the shared helper.
  • Tracks the new internal API across all linked-source assemblies.
Show a summary per file
FileDescription
SharedExtensionHelpers/ReportFileNameHelper.csDelegates report naming to the shared pipeline.
Microsoft.Testing.Platform/Services/ArtifactNamingService.csDelegates artifact naming to the shared pipeline.
Microsoft.Testing.Platform/Services/ArtifactNamingHelper.csAdds the shared resolve-and-sanitize implementation.
Microsoft.Testing.Platform/InternalAPI/InternalAPI.Unshipped.txtTracks the new internal method.
Microsoft.Testing.Extensions.VideoRecorder/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.TrxReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.JUnitReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.HtmlReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.HangDump/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.CtrfReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.CrashDump/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.

Review details

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

@github-actionsgithub-actionsBot 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.

Note

🤖 Automated review by GitHub Copilot. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.

Review Summary

Clean, well-scoped refactoring that unifies two near-identical template-resolve-and-sanitize pipelines into a single ArtifactNamingHelper.ResolveAndSanitize method. Both callers (ArtifactNamingService.ResolveFileName and ReportFileNameHelper.ResolveAndSanitize) now delegate to it, passing their respective sanitizer functions.

#DimensionVerdict
1Algorithmic Correctness✅ Logic is identical to the extracted code. One minor behavioral tightening noted inline (empty leaf name now throws for ReportFileNameHelper path too).
2Edge Cases & Error Handling
3Concurrency & Thread SafetyN/A
4Performance & Allocations✅ No change in allocation profile
5API Design & Public Surface✅ Internal API, properly declared in InternalAPI.Unshipped.txt for all referencing projects
6Backward Compatibility✅ Internal-only change
7Cross-TFM Correctness✅ No TFM-specific code
8Security
9Naming & Conventions
10Code Style & Formatting
11Documentation✅ Thorough XML docs
12LocalizationN/A
13Testing✅ Existing tests cover both callers
14–22Remaining dimensionsN/A or ✅

Overall: This is a textbook DRY refactoring. No blocking issues found.

Comment threadsrc/Platform/SharedExtensionHelpers/ReportFileNameHelper.cs
@github-actions

Copy link
Copy Markdown
Contributor

🔴 Build Failure Analysis

Build: FAILED | Duration: 255s | Errors: 5 (4 unique) | Warnings: 1

Root Cause

All 4 compilation errors are CA1416 (platform compatibility) in test/UnitTests/Microsoft.Testing.Platform.UnitTests/Logging/FileLoggerTests.cs at lines 465 and 490 (two TFMs, so each appears twice):

error CA1416: This call site is reachable on all platforms.
'ITask.RunLongRunning(Func<Task>, string, CancellationToken)' is unsupported on: 'browser'.

The ITask.RunLongRunning method is annotated with [UnsupportedOSPlatform("browser")], and the two inner ITask wrapper classes (MonitoringTask and NeverCompletingTask) in FileLoggerTests.cs delegate to it without suppressing the warning.

Relationship to This PR

⚠️This file is not modified by this PR. These appear to be pre-existing errors on the base branch that may have been recently introduced by a prior commit adding the [UnsupportedOSPlatform] attribute to ITask.RunLongRunning, or a change that enabled CA1416 for this project.

Suggested Fix

Add [SupportedOSPlatform] or suppress CA1416 on the two wrapper classes in FileLoggerTests.cs. For example, add #pragma warning disable CA1416 around the RunLongRunning delegation calls at lines 465 and 490, since the test never actually runs on browser:

#pragma warning disable CA1416// Platform compatibility — tests don't target browserpublicTaskRunLongRunning(Func<Task>action,stringname,CancellationTokencancellationToken)=>_inner.RunLongRunning(action,name,cancellationToken);
#pragma warning restore CA1416

This fix would need to be applied to both MonitoringTask (line 465) and NeverCompletingTask (line 490).

🤖 Automated content by GitHub Copilot. Generated by the Build Failure Analysis workflow. · 53.8 AIC · ⌖ 5.67 AIC · ⊞ 7.3K · [◷]( · )

@Evangelink

Copy link
Copy Markdown
MemberAuthor

Thanks for the analysis. Confirmed these CA1416 errors are pre-existing on main and not caused by this PR — the failing file (\ est/UnitTests/Microsoft.Testing.Platform.UnitTests/Logging/FileLoggerTests.cs) is not modified here, and the \ITask.RunLongRunning\ delegations already exist on \main. They're being addressed separately, so this PR (a scoped dedup refactor) intentionally leaves them alone; CI should go green once main is fixed and this branch is rebased.

@Evangelink
Amaury Levé (Evangelink) merged commit e2d1590 into mainJul 11, 2026
28 of 35 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/expert-bassoon branch July 11, 2026 12:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[duplicate-code] Duplicate Code: Template-Resolve-and-Sanitize Pipeline in ArtifactNamingService vs ReportFileNameHelper

2 participants

@Evangelink
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Unify template-resolve-and-sanitize pipeline in ArtifactNamingHelper - #9855

Merged
Amaury Levé (Evangelink) merged 1 commit into
mainfrom
dev/amauryleve/expert-bassoon
Jul 11, 2026
Merged

Unify template-resolve-and-sanitize pipeline in ArtifactNamingHelper#9855
Amaury Levé (Evangelink) merged 1 commit into
mainfrom
dev/amauryleve/expert-bassoon

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Fixes#9841.

Problem

ArtifactNamingService.ResolveFileName (in Microsoft.Testing.Platform) and ReportFileNameHelper.ResolveAndSanitize (in SharedExtensionHelpers) implemented the same algorithm: resolve template placeholders via ArtifactNamingHelper, split the result into directory + leaf, sanitize the leaf, and reassemble the path. The only real differences were where the process name/id came from and which sanitizer was used.

Change

Applied recommendation #2 from the issue (smaller, less invasive): extracted the shared pipeline into a single static overload ArtifactNamingHelper.ResolveAndSanitize(template, processName, processId, timestamp, sanitizeLeafFileName) that takes the leaf sanitizer as a Func<string, string> delegate.

  • ArtifactNamingService.ResolveFileName now delegates, passing ArtifactFileNameSanitizer.ReplaceInvalidFileNameChars.
  • ReportFileNameHelper.ResolveAndSanitize now delegates, passing ReportFileNameSanitizer.ReplaceInvalidFileNameChars. Its public signature is unchanged (matches the shipped InternalAPI), so no shipped-API churn.
  • The non-empty leaf-name guard that only ArtifactNamingService previously had is now applied on both paths.

The two sanitizers (ArtifactFileNameSanitizer / ReportFileNameSanitizer) are intentionally left as-is and passed in as delegates — consolidating them is tracked separately (the related issue referenced in #9841).

Notes

  • The new ArtifactNamingHelper.ResolveAndSanitize member is added to the InternalAPI.Unshipped.txt of every project that links the ArtifactNamingHelper source (RS0051).

Testing

  • Microsoft.Testing.Platform.UnitTests — ArtifactNaming* tests: 24/24 passed.
  • Microsoft.Testing.Extensions.UnitTests — ReportFileName* tests: 12/12 passed.
  • Report extensions (Trx/Html/JUnit/Ctrf/…) build clean with no RS0051 warnings.

Extract the shared resolve-template/split-path/sanitize-leaf/recombine pipeline into a single static ArtifactNamingHelper.ResolveAndSanitize overload that accepts a leaf sanitizer delegate. ArtifactNamingService and ReportFileNameHelper now both delegate to it, removing the near-identical duplicated logic described in #9841. The non-empty leaf guard is now applied on both paths.
Fixes#9841
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8c5b1087-7e14-45e5-a444-daf19d40d832
CopilotAI review requested due to automatic review settings July 11, 2026 12:12

CopilotAI 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

Unifies artifact template resolution and leaf-name sanitization in ArtifactNamingHelper, resolving #9841.

Changes:

  • Extracts the shared resolve-and-sanitize pipeline.
  • Delegates platform and report naming paths to the shared helper.
  • Tracks the new internal API across all linked-source assemblies.
Show a summary per file
FileDescription
SharedExtensionHelpers/ReportFileNameHelper.csDelegates report naming to the shared pipeline.
Microsoft.Testing.Platform/Services/ArtifactNamingService.csDelegates artifact naming to the shared pipeline.
Microsoft.Testing.Platform/Services/ArtifactNamingHelper.csAdds the shared resolve-and-sanitize implementation.
Microsoft.Testing.Platform/InternalAPI/InternalAPI.Unshipped.txtTracks the new internal method.
Microsoft.Testing.Extensions.VideoRecorder/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.TrxReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.JUnitReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.HtmlReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.HangDump/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.CtrfReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.CrashDump/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.

Review details

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

@github-actionsgithub-actionsBot 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.

Note

🤖 Automated review by GitHub Copilot. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.

Review Summary

Clean, well-scoped refactoring that unifies two near-identical template-resolve-and-sanitize pipelines into a single ArtifactNamingHelper.ResolveAndSanitize method. Both callers (ArtifactNamingService.ResolveFileName and ReportFileNameHelper.ResolveAndSanitize) now delegate to it, passing their respective sanitizer functions.

#DimensionVerdict
1Algorithmic Correctness✅ Logic is identical to the extracted code. One minor behavioral tightening noted inline (empty leaf name now throws for ReportFileNameHelper path too).
2Edge Cases & Error Handling
3Concurrency & Thread SafetyN/A
4Performance & Allocations✅ No change in allocation profile
5API Design & Public Surface✅ Internal API, properly declared in InternalAPI.Unshipped.txt for all referencing projects
6Backward Compatibility✅ Internal-only change
7Cross-TFM Correctness✅ No TFM-specific code
8Security
9Naming & Conventions
10Code Style & Formatting
11Documentation✅ Thorough XML docs
12LocalizationN/A
13Testing✅ Existing tests cover both callers
14–22Remaining dimensionsN/A or ✅

Overall: This is a textbook DRY refactoring. No blocking issues found.

Comment threadsrc/Platform/SharedExtensionHelpers/ReportFileNameHelper.cs
@github-actions

Copy link
Copy Markdown
Contributor

🔴 Build Failure Analysis

Build: FAILED | Duration: 255s | Errors: 5 (4 unique) | Warnings: 1

Root Cause

All 4 compilation errors are CA1416 (platform compatibility) in test/UnitTests/Microsoft.Testing.Platform.UnitTests/Logging/FileLoggerTests.cs at lines 465 and 490 (two TFMs, so each appears twice):

error CA1416: This call site is reachable on all platforms.
'ITask.RunLongRunning(Func<Task>, string, CancellationToken)' is unsupported on: 'browser'.

The ITask.RunLongRunning method is annotated with [UnsupportedOSPlatform("browser")], and the two inner ITask wrapper classes (MonitoringTask and NeverCompletingTask) in FileLoggerTests.cs delegate to it without suppressing the warning.

Relationship to This PR

⚠️This file is not modified by this PR. These appear to be pre-existing errors on the base branch that may have been recently introduced by a prior commit adding the [UnsupportedOSPlatform] attribute to ITask.RunLongRunning, or a change that enabled CA1416 for this project.

Suggested Fix

Add [SupportedOSPlatform] or suppress CA1416 on the two wrapper classes in FileLoggerTests.cs. For example, add #pragma warning disable CA1416 around the RunLongRunning delegation calls at lines 465 and 490, since the test never actually runs on browser:

#pragma warning disable CA1416// Platform compatibility — tests don't target browserpublicTaskRunLongRunning(Func<Task>action,stringname,CancellationTokencancellationToken)=>_inner.RunLongRunning(action,name,cancellationToken);
#pragma warning restore CA1416

This fix would need to be applied to both MonitoringTask (line 465) and NeverCompletingTask (line 490).

🤖 Automated content by GitHub Copilot. Generated by the Build Failure Analysis workflow. · 53.8 AIC · ⌖ 5.67 AIC · ⊞ 7.3K · [◷]( · )

@Evangelink

Copy link
Copy Markdown
MemberAuthor

Thanks for the analysis. Confirmed these CA1416 errors are pre-existing on main and not caused by this PR — the failing file (\ est/UnitTests/Microsoft.Testing.Platform.UnitTests/Logging/FileLoggerTests.cs) is not modified here, and the \ITask.RunLongRunning\ delegations already exist on \main. They're being addressed separately, so this PR (a scoped dedup refactor) intentionally leaves them alone; CI should go green once main is fixed and this branch is rebased.

@Evangelink
Amaury Levé (Evangelink) merged commit e2d1590 into mainJul 11, 2026
28 of 35 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/expert-bassoon branch July 11, 2026 12:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[duplicate-code] Duplicate Code: Template-Resolve-and-Sanitize Pipeline in ArtifactNamingService vs ReportFileNameHelper

2 participants

@Evangelink
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Unify template-resolve-and-sanitize pipeline in ArtifactNamingHelper - #9855

Merged
Amaury Levé (Evangelink) merged 1 commit into
mainfrom
dev/amauryleve/expert-bassoon
Jul 11, 2026
Merged

Unify template-resolve-and-sanitize pipeline in ArtifactNamingHelper#9855
Amaury Levé (Evangelink) merged 1 commit into
mainfrom
dev/amauryleve/expert-bassoon

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Fixes#9841.

Problem

ArtifactNamingService.ResolveFileName (in Microsoft.Testing.Platform) and ReportFileNameHelper.ResolveAndSanitize (in SharedExtensionHelpers) implemented the same algorithm: resolve template placeholders via ArtifactNamingHelper, split the result into directory + leaf, sanitize the leaf, and reassemble the path. The only real differences were where the process name/id came from and which sanitizer was used.

Change

Applied recommendation #2 from the issue (smaller, less invasive): extracted the shared pipeline into a single static overload ArtifactNamingHelper.ResolveAndSanitize(template, processName, processId, timestamp, sanitizeLeafFileName) that takes the leaf sanitizer as a Func<string, string> delegate.

  • ArtifactNamingService.ResolveFileName now delegates, passing ArtifactFileNameSanitizer.ReplaceInvalidFileNameChars.
  • ReportFileNameHelper.ResolveAndSanitize now delegates, passing ReportFileNameSanitizer.ReplaceInvalidFileNameChars. Its public signature is unchanged (matches the shipped InternalAPI), so no shipped-API churn.
  • The non-empty leaf-name guard that only ArtifactNamingService previously had is now applied on both paths.

The two sanitizers (ArtifactFileNameSanitizer / ReportFileNameSanitizer) are intentionally left as-is and passed in as delegates — consolidating them is tracked separately (the related issue referenced in #9841).

Notes

  • The new ArtifactNamingHelper.ResolveAndSanitize member is added to the InternalAPI.Unshipped.txt of every project that links the ArtifactNamingHelper source (RS0051).

Testing

  • Microsoft.Testing.Platform.UnitTests — ArtifactNaming* tests: 24/24 passed.
  • Microsoft.Testing.Extensions.UnitTests — ReportFileName* tests: 12/12 passed.
  • Report extensions (Trx/Html/JUnit/Ctrf/…) build clean with no RS0051 warnings.

Extract the shared resolve-template/split-path/sanitize-leaf/recombine pipeline into a single static ArtifactNamingHelper.ResolveAndSanitize overload that accepts a leaf sanitizer delegate. ArtifactNamingService and ReportFileNameHelper now both delegate to it, removing the near-identical duplicated logic described in #9841. The non-empty leaf guard is now applied on both paths.
Fixes#9841
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8c5b1087-7e14-45e5-a444-daf19d40d832
CopilotAI review requested due to automatic review settings July 11, 2026 12:12

CopilotAI 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

Unifies artifact template resolution and leaf-name sanitization in ArtifactNamingHelper, resolving #9841.

Changes:

  • Extracts the shared resolve-and-sanitize pipeline.
  • Delegates platform and report naming paths to the shared helper.
  • Tracks the new internal API across all linked-source assemblies.
Show a summary per file
FileDescription
SharedExtensionHelpers/ReportFileNameHelper.csDelegates report naming to the shared pipeline.
Microsoft.Testing.Platform/Services/ArtifactNamingService.csDelegates artifact naming to the shared pipeline.
Microsoft.Testing.Platform/Services/ArtifactNamingHelper.csAdds the shared resolve-and-sanitize implementation.
Microsoft.Testing.Platform/InternalAPI/InternalAPI.Unshipped.txtTracks the new internal method.
Microsoft.Testing.Extensions.VideoRecorder/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.TrxReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.JUnitReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.HtmlReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.HangDump/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.CtrfReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.CrashDump/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.

Review details

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

@github-actionsgithub-actionsBot 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.

Note

🤖 Automated review by GitHub Copilot. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.

Review Summary

Clean, well-scoped refactoring that unifies two near-identical template-resolve-and-sanitize pipelines into a single ArtifactNamingHelper.ResolveAndSanitize method. Both callers (ArtifactNamingService.ResolveFileName and ReportFileNameHelper.ResolveAndSanitize) now delegate to it, passing their respective sanitizer functions.

#DimensionVerdict
1Algorithmic Correctness✅ Logic is identical to the extracted code. One minor behavioral tightening noted inline (empty leaf name now throws for ReportFileNameHelper path too).
2Edge Cases & Error Handling
3Concurrency & Thread SafetyN/A
4Performance & Allocations✅ No change in allocation profile
5API Design & Public Surface✅ Internal API, properly declared in InternalAPI.Unshipped.txt for all referencing projects
6Backward Compatibility✅ Internal-only change
7Cross-TFM Correctness✅ No TFM-specific code
8Security
9Naming & Conventions
10Code Style & Formatting
11Documentation✅ Thorough XML docs
12LocalizationN/A
13Testing✅ Existing tests cover both callers
14–22Remaining dimensionsN/A or ✅

Overall: This is a textbook DRY refactoring. No blocking issues found.

Comment threadsrc/Platform/SharedExtensionHelpers/ReportFileNameHelper.cs
@github-actions

Copy link
Copy Markdown
Contributor

🔴 Build Failure Analysis

Build: FAILED | Duration: 255s | Errors: 5 (4 unique) | Warnings: 1

Root Cause

All 4 compilation errors are CA1416 (platform compatibility) in test/UnitTests/Microsoft.Testing.Platform.UnitTests/Logging/FileLoggerTests.cs at lines 465 and 490 (two TFMs, so each appears twice):

error CA1416: This call site is reachable on all platforms.
'ITask.RunLongRunning(Func<Task>, string, CancellationToken)' is unsupported on: 'browser'.

The ITask.RunLongRunning method is annotated with [UnsupportedOSPlatform("browser")], and the two inner ITask wrapper classes (MonitoringTask and NeverCompletingTask) in FileLoggerTests.cs delegate to it without suppressing the warning.

Relationship to This PR

⚠️This file is not modified by this PR. These appear to be pre-existing errors on the base branch that may have been recently introduced by a prior commit adding the [UnsupportedOSPlatform] attribute to ITask.RunLongRunning, or a change that enabled CA1416 for this project.

Suggested Fix

Add [SupportedOSPlatform] or suppress CA1416 on the two wrapper classes in FileLoggerTests.cs. For example, add #pragma warning disable CA1416 around the RunLongRunning delegation calls at lines 465 and 490, since the test never actually runs on browser:

#pragma warning disable CA1416// Platform compatibility — tests don't target browserpublicTaskRunLongRunning(Func<Task>action,stringname,CancellationTokencancellationToken)=>_inner.RunLongRunning(action,name,cancellationToken);
#pragma warning restore CA1416

This fix would need to be applied to both MonitoringTask (line 465) and NeverCompletingTask (line 490).

🤖 Automated content by GitHub Copilot. Generated by the Build Failure Analysis workflow. · 53.8 AIC · ⌖ 5.67 AIC · ⊞ 7.3K · [◷]( · )

@Evangelink

Copy link
Copy Markdown
MemberAuthor

Thanks for the analysis. Confirmed these CA1416 errors are pre-existing on main and not caused by this PR — the failing file (\ est/UnitTests/Microsoft.Testing.Platform.UnitTests/Logging/FileLoggerTests.cs) is not modified here, and the \ITask.RunLongRunning\ delegations already exist on \main. They're being addressed separately, so this PR (a scoped dedup refactor) intentionally leaves them alone; CI should go green once main is fixed and this branch is rebased.

@Evangelink
Amaury Levé (Evangelink) merged commit e2d1590 into mainJul 11, 2026
28 of 35 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/expert-bassoon branch July 11, 2026 12:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[duplicate-code] Duplicate Code: Template-Resolve-and-Sanitize Pipeline in ArtifactNamingService vs ReportFileNameHelper

2 participants

@Evangelink
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Unify template-resolve-and-sanitize pipeline in ArtifactNamingHelper - #9855

Merged
Amaury Levé (Evangelink) merged 1 commit into
mainfrom
dev/amauryleve/expert-bassoon
Jul 11, 2026
Merged

Unify template-resolve-and-sanitize pipeline in ArtifactNamingHelper#9855
Amaury Levé (Evangelink) merged 1 commit into
mainfrom
dev/amauryleve/expert-bassoon

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Fixes#9841.

Problem

ArtifactNamingService.ResolveFileName (in Microsoft.Testing.Platform) and ReportFileNameHelper.ResolveAndSanitize (in SharedExtensionHelpers) implemented the same algorithm: resolve template placeholders via ArtifactNamingHelper, split the result into directory + leaf, sanitize the leaf, and reassemble the path. The only real differences were where the process name/id came from and which sanitizer was used.

Change

Applied recommendation #2 from the issue (smaller, less invasive): extracted the shared pipeline into a single static overload ArtifactNamingHelper.ResolveAndSanitize(template, processName, processId, timestamp, sanitizeLeafFileName) that takes the leaf sanitizer as a Func<string, string> delegate.

  • ArtifactNamingService.ResolveFileName now delegates, passing ArtifactFileNameSanitizer.ReplaceInvalidFileNameChars.
  • ReportFileNameHelper.ResolveAndSanitize now delegates, passing ReportFileNameSanitizer.ReplaceInvalidFileNameChars. Its public signature is unchanged (matches the shipped InternalAPI), so no shipped-API churn.
  • The non-empty leaf-name guard that only ArtifactNamingService previously had is now applied on both paths.

The two sanitizers (ArtifactFileNameSanitizer / ReportFileNameSanitizer) are intentionally left as-is and passed in as delegates — consolidating them is tracked separately (the related issue referenced in #9841).

Notes

  • The new ArtifactNamingHelper.ResolveAndSanitize member is added to the InternalAPI.Unshipped.txt of every project that links the ArtifactNamingHelper source (RS0051).

Testing

  • Microsoft.Testing.Platform.UnitTests — ArtifactNaming* tests: 24/24 passed.
  • Microsoft.Testing.Extensions.UnitTests — ReportFileName* tests: 12/12 passed.
  • Report extensions (Trx/Html/JUnit/Ctrf/…) build clean with no RS0051 warnings.

Extract the shared resolve-template/split-path/sanitize-leaf/recombine pipeline into a single static ArtifactNamingHelper.ResolveAndSanitize overload that accepts a leaf sanitizer delegate. ArtifactNamingService and ReportFileNameHelper now both delegate to it, removing the near-identical duplicated logic described in #9841. The non-empty leaf guard is now applied on both paths.
Fixes#9841
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8c5b1087-7e14-45e5-a444-daf19d40d832
CopilotAI review requested due to automatic review settings July 11, 2026 12:12

CopilotAI 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

Unifies artifact template resolution and leaf-name sanitization in ArtifactNamingHelper, resolving #9841.

Changes:

  • Extracts the shared resolve-and-sanitize pipeline.
  • Delegates platform and report naming paths to the shared helper.
  • Tracks the new internal API across all linked-source assemblies.
Show a summary per file
FileDescription
SharedExtensionHelpers/ReportFileNameHelper.csDelegates report naming to the shared pipeline.
Microsoft.Testing.Platform/Services/ArtifactNamingService.csDelegates artifact naming to the shared pipeline.
Microsoft.Testing.Platform/Services/ArtifactNamingHelper.csAdds the shared resolve-and-sanitize implementation.
Microsoft.Testing.Platform/InternalAPI/InternalAPI.Unshipped.txtTracks the new internal method.
Microsoft.Testing.Extensions.VideoRecorder/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.TrxReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.JUnitReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.HtmlReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.HangDump/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.CtrfReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.CrashDump/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.

Review details

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

@github-actionsgithub-actionsBot 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.

Note

🤖 Automated review by GitHub Copilot. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.

Review Summary

Clean, well-scoped refactoring that unifies two near-identical template-resolve-and-sanitize pipelines into a single ArtifactNamingHelper.ResolveAndSanitize method. Both callers (ArtifactNamingService.ResolveFileName and ReportFileNameHelper.ResolveAndSanitize) now delegate to it, passing their respective sanitizer functions.

#DimensionVerdict
1Algorithmic Correctness✅ Logic is identical to the extracted code. One minor behavioral tightening noted inline (empty leaf name now throws for ReportFileNameHelper path too).
2Edge Cases & Error Handling
3Concurrency & Thread SafetyN/A
4Performance & Allocations✅ No change in allocation profile
5API Design & Public Surface✅ Internal API, properly declared in InternalAPI.Unshipped.txt for all referencing projects
6Backward Compatibility✅ Internal-only change
7Cross-TFM Correctness✅ No TFM-specific code
8Security
9Naming & Conventions
10Code Style & Formatting
11Documentation✅ Thorough XML docs
12LocalizationN/A
13Testing✅ Existing tests cover both callers
14–22Remaining dimensionsN/A or ✅

Overall: This is a textbook DRY refactoring. No blocking issues found.

Comment threadsrc/Platform/SharedExtensionHelpers/ReportFileNameHelper.cs
@github-actions

Copy link
Copy Markdown
Contributor

🔴 Build Failure Analysis

Build: FAILED | Duration: 255s | Errors: 5 (4 unique) | Warnings: 1

Root Cause

All 4 compilation errors are CA1416 (platform compatibility) in test/UnitTests/Microsoft.Testing.Platform.UnitTests/Logging/FileLoggerTests.cs at lines 465 and 490 (two TFMs, so each appears twice):

error CA1416: This call site is reachable on all platforms.
'ITask.RunLongRunning(Func<Task>, string, CancellationToken)' is unsupported on: 'browser'.

The ITask.RunLongRunning method is annotated with [UnsupportedOSPlatform("browser")], and the two inner ITask wrapper classes (MonitoringTask and NeverCompletingTask) in FileLoggerTests.cs delegate to it without suppressing the warning.

Relationship to This PR

⚠️This file is not modified by this PR. These appear to be pre-existing errors on the base branch that may have been recently introduced by a prior commit adding the [UnsupportedOSPlatform] attribute to ITask.RunLongRunning, or a change that enabled CA1416 for this project.

Suggested Fix

Add [SupportedOSPlatform] or suppress CA1416 on the two wrapper classes in FileLoggerTests.cs. For example, add #pragma warning disable CA1416 around the RunLongRunning delegation calls at lines 465 and 490, since the test never actually runs on browser:

#pragma warning disable CA1416// Platform compatibility — tests don't target browserpublicTaskRunLongRunning(Func<Task>action,stringname,CancellationTokencancellationToken)=>_inner.RunLongRunning(action,name,cancellationToken);
#pragma warning restore CA1416

This fix would need to be applied to both MonitoringTask (line 465) and NeverCompletingTask (line 490).

🤖 Automated content by GitHub Copilot. Generated by the Build Failure Analysis workflow. · 53.8 AIC · ⌖ 5.67 AIC · ⊞ 7.3K · [◷]( · )

@Evangelink

Copy link
Copy Markdown
MemberAuthor

Thanks for the analysis. Confirmed these CA1416 errors are pre-existing on main and not caused by this PR — the failing file (\ est/UnitTests/Microsoft.Testing.Platform.UnitTests/Logging/FileLoggerTests.cs) is not modified here, and the \ITask.RunLongRunning\ delegations already exist on \main. They're being addressed separately, so this PR (a scoped dedup refactor) intentionally leaves them alone; CI should go green once main is fixed and this branch is rebased.

@Evangelink
Amaury Levé (Evangelink) merged commit e2d1590 into mainJul 11, 2026
28 of 35 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/expert-bassoon branch July 11, 2026 12:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[duplicate-code] Duplicate Code: Template-Resolve-and-Sanitize Pipeline in ArtifactNamingService vs ReportFileNameHelper

2 participants

@Evangelink
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Unify template-resolve-and-sanitize pipeline in ArtifactNamingHelper - #9855

Merged
Amaury Levé (Evangelink) merged 1 commit into
mainfrom
dev/amauryleve/expert-bassoon
Jul 11, 2026
Merged

Unify template-resolve-and-sanitize pipeline in ArtifactNamingHelper#9855
Amaury Levé (Evangelink) merged 1 commit into
mainfrom
dev/amauryleve/expert-bassoon

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Fixes#9841.

Problem

ArtifactNamingService.ResolveFileName (in Microsoft.Testing.Platform) and ReportFileNameHelper.ResolveAndSanitize (in SharedExtensionHelpers) implemented the same algorithm: resolve template placeholders via ArtifactNamingHelper, split the result into directory + leaf, sanitize the leaf, and reassemble the path. The only real differences were where the process name/id came from and which sanitizer was used.

Change

Applied recommendation #2 from the issue (smaller, less invasive): extracted the shared pipeline into a single static overload ArtifactNamingHelper.ResolveAndSanitize(template, processName, processId, timestamp, sanitizeLeafFileName) that takes the leaf sanitizer as a Func<string, string> delegate.

  • ArtifactNamingService.ResolveFileName now delegates, passing ArtifactFileNameSanitizer.ReplaceInvalidFileNameChars.
  • ReportFileNameHelper.ResolveAndSanitize now delegates, passing ReportFileNameSanitizer.ReplaceInvalidFileNameChars. Its public signature is unchanged (matches the shipped InternalAPI), so no shipped-API churn.
  • The non-empty leaf-name guard that only ArtifactNamingService previously had is now applied on both paths.

The two sanitizers (ArtifactFileNameSanitizer / ReportFileNameSanitizer) are intentionally left as-is and passed in as delegates — consolidating them is tracked separately (the related issue referenced in #9841).

Notes

  • The new ArtifactNamingHelper.ResolveAndSanitize member is added to the InternalAPI.Unshipped.txt of every project that links the ArtifactNamingHelper source (RS0051).

Testing

  • Microsoft.Testing.Platform.UnitTests — ArtifactNaming* tests: 24/24 passed.
  • Microsoft.Testing.Extensions.UnitTests — ReportFileName* tests: 12/12 passed.
  • Report extensions (Trx/Html/JUnit/Ctrf/…) build clean with no RS0051 warnings.

Extract the shared resolve-template/split-path/sanitize-leaf/recombine pipeline into a single static ArtifactNamingHelper.ResolveAndSanitize overload that accepts a leaf sanitizer delegate. ArtifactNamingService and ReportFileNameHelper now both delegate to it, removing the near-identical duplicated logic described in #9841. The non-empty leaf guard is now applied on both paths.
Fixes#9841
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8c5b1087-7e14-45e5-a444-daf19d40d832
CopilotAI review requested due to automatic review settings July 11, 2026 12:12

CopilotAI 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

Unifies artifact template resolution and leaf-name sanitization in ArtifactNamingHelper, resolving #9841.

Changes:

  • Extracts the shared resolve-and-sanitize pipeline.
  • Delegates platform and report naming paths to the shared helper.
  • Tracks the new internal API across all linked-source assemblies.
Show a summary per file
FileDescription
SharedExtensionHelpers/ReportFileNameHelper.csDelegates report naming to the shared pipeline.
Microsoft.Testing.Platform/Services/ArtifactNamingService.csDelegates artifact naming to the shared pipeline.
Microsoft.Testing.Platform/Services/ArtifactNamingHelper.csAdds the shared resolve-and-sanitize implementation.
Microsoft.Testing.Platform/InternalAPI/InternalAPI.Unshipped.txtTracks the new internal method.
Microsoft.Testing.Extensions.VideoRecorder/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.TrxReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.JUnitReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.HtmlReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.HangDump/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.CtrfReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.CrashDump/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.

Review details

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

@github-actionsgithub-actionsBot 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.

Note

🤖 Automated review by GitHub Copilot. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.

Review Summary

Clean, well-scoped refactoring that unifies two near-identical template-resolve-and-sanitize pipelines into a single ArtifactNamingHelper.ResolveAndSanitize method. Both callers (ArtifactNamingService.ResolveFileName and ReportFileNameHelper.ResolveAndSanitize) now delegate to it, passing their respective sanitizer functions.

#DimensionVerdict
1Algorithmic Correctness✅ Logic is identical to the extracted code. One minor behavioral tightening noted inline (empty leaf name now throws for ReportFileNameHelper path too).
2Edge Cases & Error Handling
3Concurrency & Thread SafetyN/A
4Performance & Allocations✅ No change in allocation profile
5API Design & Public Surface✅ Internal API, properly declared in InternalAPI.Unshipped.txt for all referencing projects
6Backward Compatibility✅ Internal-only change
7Cross-TFM Correctness✅ No TFM-specific code
8Security
9Naming & Conventions
10Code Style & Formatting
11Documentation✅ Thorough XML docs
12LocalizationN/A
13Testing✅ Existing tests cover both callers
14–22Remaining dimensionsN/A or ✅

Overall: This is a textbook DRY refactoring. No blocking issues found.

Comment threadsrc/Platform/SharedExtensionHelpers/ReportFileNameHelper.cs
@github-actions

Copy link
Copy Markdown
Contributor

🔴 Build Failure Analysis

Build: FAILED | Duration: 255s | Errors: 5 (4 unique) | Warnings: 1

Root Cause

All 4 compilation errors are CA1416 (platform compatibility) in test/UnitTests/Microsoft.Testing.Platform.UnitTests/Logging/FileLoggerTests.cs at lines 465 and 490 (two TFMs, so each appears twice):

error CA1416: This call site is reachable on all platforms.
'ITask.RunLongRunning(Func<Task>, string, CancellationToken)' is unsupported on: 'browser'.

The ITask.RunLongRunning method is annotated with [UnsupportedOSPlatform("browser")], and the two inner ITask wrapper classes (MonitoringTask and NeverCompletingTask) in FileLoggerTests.cs delegate to it without suppressing the warning.

Relationship to This PR

⚠️This file is not modified by this PR. These appear to be pre-existing errors on the base branch that may have been recently introduced by a prior commit adding the [UnsupportedOSPlatform] attribute to ITask.RunLongRunning, or a change that enabled CA1416 for this project.

Suggested Fix

Add [SupportedOSPlatform] or suppress CA1416 on the two wrapper classes in FileLoggerTests.cs. For example, add #pragma warning disable CA1416 around the RunLongRunning delegation calls at lines 465 and 490, since the test never actually runs on browser:

#pragma warning disable CA1416// Platform compatibility — tests don't target browserpublicTaskRunLongRunning(Func<Task>action,stringname,CancellationTokencancellationToken)=>_inner.RunLongRunning(action,name,cancellationToken);
#pragma warning restore CA1416

This fix would need to be applied to both MonitoringTask (line 465) and NeverCompletingTask (line 490).

🤖 Automated content by GitHub Copilot. Generated by the Build Failure Analysis workflow. · 53.8 AIC · ⌖ 5.67 AIC · ⊞ 7.3K · [◷]( · )

@Evangelink

Copy link
Copy Markdown
MemberAuthor

Thanks for the analysis. Confirmed these CA1416 errors are pre-existing on main and not caused by this PR — the failing file (\ est/UnitTests/Microsoft.Testing.Platform.UnitTests/Logging/FileLoggerTests.cs) is not modified here, and the \ITask.RunLongRunning\ delegations already exist on \main. They're being addressed separately, so this PR (a scoped dedup refactor) intentionally leaves them alone; CI should go green once main is fixed and this branch is rebased.

@Evangelink
Amaury Levé (Evangelink) merged commit e2d1590 into mainJul 11, 2026
28 of 35 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/expert-bassoon branch July 11, 2026 12:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[duplicate-code] Duplicate Code: Template-Resolve-and-Sanitize Pipeline in ArtifactNamingService vs ReportFileNameHelper

2 participants

@Evangelink
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Unify template-resolve-and-sanitize pipeline in ArtifactNamingHelper - #9855

Merged
Amaury Levé (Evangelink) merged 1 commit into
mainfrom
dev/amauryleve/expert-bassoon
Jul 11, 2026
Merged

Unify template-resolve-and-sanitize pipeline in ArtifactNamingHelper#9855
Amaury Levé (Evangelink) merged 1 commit into
mainfrom
dev/amauryleve/expert-bassoon

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Fixes#9841.

Problem

ArtifactNamingService.ResolveFileName (in Microsoft.Testing.Platform) and ReportFileNameHelper.ResolveAndSanitize (in SharedExtensionHelpers) implemented the same algorithm: resolve template placeholders via ArtifactNamingHelper, split the result into directory + leaf, sanitize the leaf, and reassemble the path. The only real differences were where the process name/id came from and which sanitizer was used.

Change

Applied recommendation #2 from the issue (smaller, less invasive): extracted the shared pipeline into a single static overload ArtifactNamingHelper.ResolveAndSanitize(template, processName, processId, timestamp, sanitizeLeafFileName) that takes the leaf sanitizer as a Func<string, string> delegate.

  • ArtifactNamingService.ResolveFileName now delegates, passing ArtifactFileNameSanitizer.ReplaceInvalidFileNameChars.
  • ReportFileNameHelper.ResolveAndSanitize now delegates, passing ReportFileNameSanitizer.ReplaceInvalidFileNameChars. Its public signature is unchanged (matches the shipped InternalAPI), so no shipped-API churn.
  • The non-empty leaf-name guard that only ArtifactNamingService previously had is now applied on both paths.

The two sanitizers (ArtifactFileNameSanitizer / ReportFileNameSanitizer) are intentionally left as-is and passed in as delegates — consolidating them is tracked separately (the related issue referenced in #9841).

Notes

  • The new ArtifactNamingHelper.ResolveAndSanitize member is added to the InternalAPI.Unshipped.txt of every project that links the ArtifactNamingHelper source (RS0051).

Testing

  • Microsoft.Testing.Platform.UnitTests — ArtifactNaming* tests: 24/24 passed.
  • Microsoft.Testing.Extensions.UnitTests — ReportFileName* tests: 12/12 passed.
  • Report extensions (Trx/Html/JUnit/Ctrf/…) build clean with no RS0051 warnings.

Extract the shared resolve-template/split-path/sanitize-leaf/recombine pipeline into a single static ArtifactNamingHelper.ResolveAndSanitize overload that accepts a leaf sanitizer delegate. ArtifactNamingService and ReportFileNameHelper now both delegate to it, removing the near-identical duplicated logic described in #9841. The non-empty leaf guard is now applied on both paths.
Fixes#9841
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8c5b1087-7e14-45e5-a444-daf19d40d832
CopilotAI review requested due to automatic review settings July 11, 2026 12:12

CopilotAI 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

Unifies artifact template resolution and leaf-name sanitization in ArtifactNamingHelper, resolving #9841.

Changes:

  • Extracts the shared resolve-and-sanitize pipeline.
  • Delegates platform and report naming paths to the shared helper.
  • Tracks the new internal API across all linked-source assemblies.
Show a summary per file
FileDescription
SharedExtensionHelpers/ReportFileNameHelper.csDelegates report naming to the shared pipeline.
Microsoft.Testing.Platform/Services/ArtifactNamingService.csDelegates artifact naming to the shared pipeline.
Microsoft.Testing.Platform/Services/ArtifactNamingHelper.csAdds the shared resolve-and-sanitize implementation.
Microsoft.Testing.Platform/InternalAPI/InternalAPI.Unshipped.txtTracks the new internal method.
Microsoft.Testing.Extensions.VideoRecorder/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.TrxReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.JUnitReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.HtmlReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.HangDump/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.CtrfReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.CrashDump/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.

Review details

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

@github-actionsgithub-actionsBot 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.

Note

🤖 Automated review by GitHub Copilot. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.

Review Summary

Clean, well-scoped refactoring that unifies two near-identical template-resolve-and-sanitize pipelines into a single ArtifactNamingHelper.ResolveAndSanitize method. Both callers (ArtifactNamingService.ResolveFileName and ReportFileNameHelper.ResolveAndSanitize) now delegate to it, passing their respective sanitizer functions.

#DimensionVerdict
1Algorithmic Correctness✅ Logic is identical to the extracted code. One minor behavioral tightening noted inline (empty leaf name now throws for ReportFileNameHelper path too).
2Edge Cases & Error Handling
3Concurrency & Thread SafetyN/A
4Performance & Allocations✅ No change in allocation profile
5API Design & Public Surface✅ Internal API, properly declared in InternalAPI.Unshipped.txt for all referencing projects
6Backward Compatibility✅ Internal-only change
7Cross-TFM Correctness✅ No TFM-specific code
8Security
9Naming & Conventions
10Code Style & Formatting
11Documentation✅ Thorough XML docs
12LocalizationN/A
13Testing✅ Existing tests cover both callers
14–22Remaining dimensionsN/A or ✅

Overall: This is a textbook DRY refactoring. No blocking issues found.

Comment threadsrc/Platform/SharedExtensionHelpers/ReportFileNameHelper.cs
@github-actions

Copy link
Copy Markdown
Contributor

🔴 Build Failure Analysis

Build: FAILED | Duration: 255s | Errors: 5 (4 unique) | Warnings: 1

Root Cause

All 4 compilation errors are CA1416 (platform compatibility) in test/UnitTests/Microsoft.Testing.Platform.UnitTests/Logging/FileLoggerTests.cs at lines 465 and 490 (two TFMs, so each appears twice):

error CA1416: This call site is reachable on all platforms.
'ITask.RunLongRunning(Func<Task>, string, CancellationToken)' is unsupported on: 'browser'.

The ITask.RunLongRunning method is annotated with [UnsupportedOSPlatform("browser")], and the two inner ITask wrapper classes (MonitoringTask and NeverCompletingTask) in FileLoggerTests.cs delegate to it without suppressing the warning.

Relationship to This PR

⚠️This file is not modified by this PR. These appear to be pre-existing errors on the base branch that may have been recently introduced by a prior commit adding the [UnsupportedOSPlatform] attribute to ITask.RunLongRunning, or a change that enabled CA1416 for this project.

Suggested Fix

Add [SupportedOSPlatform] or suppress CA1416 on the two wrapper classes in FileLoggerTests.cs. For example, add #pragma warning disable CA1416 around the RunLongRunning delegation calls at lines 465 and 490, since the test never actually runs on browser:

#pragma warning disable CA1416// Platform compatibility — tests don't target browserpublicTaskRunLongRunning(Func<Task>action,stringname,CancellationTokencancellationToken)=>_inner.RunLongRunning(action,name,cancellationToken);
#pragma warning restore CA1416

This fix would need to be applied to both MonitoringTask (line 465) and NeverCompletingTask (line 490).

🤖 Automated content by GitHub Copilot. Generated by the Build Failure Analysis workflow. · 53.8 AIC · ⌖ 5.67 AIC · ⊞ 7.3K · [◷]( · )

@Evangelink

Copy link
Copy Markdown
MemberAuthor

Thanks for the analysis. Confirmed these CA1416 errors are pre-existing on main and not caused by this PR — the failing file (\ est/UnitTests/Microsoft.Testing.Platform.UnitTests/Logging/FileLoggerTests.cs) is not modified here, and the \ITask.RunLongRunning\ delegations already exist on \main. They're being addressed separately, so this PR (a scoped dedup refactor) intentionally leaves them alone; CI should go green once main is fixed and this branch is rebased.

@Evangelink
Amaury Levé (Evangelink) merged commit e2d1590 into mainJul 11, 2026
28 of 35 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/expert-bassoon branch July 11, 2026 12:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[duplicate-code] Duplicate Code: Template-Resolve-and-Sanitize Pipeline in ArtifactNamingService vs ReportFileNameHelper

2 participants

@Evangelink
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Unify template-resolve-and-sanitize pipeline in ArtifactNamingHelper - #9855

Merged
Amaury Levé (Evangelink) merged 1 commit into
mainfrom
dev/amauryleve/expert-bassoon
Jul 11, 2026
Merged

Unify template-resolve-and-sanitize pipeline in ArtifactNamingHelper#9855
Amaury Levé (Evangelink) merged 1 commit into
mainfrom
dev/amauryleve/expert-bassoon

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Fixes#9841.

Problem

ArtifactNamingService.ResolveFileName (in Microsoft.Testing.Platform) and ReportFileNameHelper.ResolveAndSanitize (in SharedExtensionHelpers) implemented the same algorithm: resolve template placeholders via ArtifactNamingHelper, split the result into directory + leaf, sanitize the leaf, and reassemble the path. The only real differences were where the process name/id came from and which sanitizer was used.

Change

Applied recommendation #2 from the issue (smaller, less invasive): extracted the shared pipeline into a single static overload ArtifactNamingHelper.ResolveAndSanitize(template, processName, processId, timestamp, sanitizeLeafFileName) that takes the leaf sanitizer as a Func<string, string> delegate.

  • ArtifactNamingService.ResolveFileName now delegates, passing ArtifactFileNameSanitizer.ReplaceInvalidFileNameChars.
  • ReportFileNameHelper.ResolveAndSanitize now delegates, passing ReportFileNameSanitizer.ReplaceInvalidFileNameChars. Its public signature is unchanged (matches the shipped InternalAPI), so no shipped-API churn.
  • The non-empty leaf-name guard that only ArtifactNamingService previously had is now applied on both paths.

The two sanitizers (ArtifactFileNameSanitizer / ReportFileNameSanitizer) are intentionally left as-is and passed in as delegates — consolidating them is tracked separately (the related issue referenced in #9841).

Notes

  • The new ArtifactNamingHelper.ResolveAndSanitize member is added to the InternalAPI.Unshipped.txt of every project that links the ArtifactNamingHelper source (RS0051).

Testing

  • Microsoft.Testing.Platform.UnitTests — ArtifactNaming* tests: 24/24 passed.
  • Microsoft.Testing.Extensions.UnitTests — ReportFileName* tests: 12/12 passed.
  • Report extensions (Trx/Html/JUnit/Ctrf/…) build clean with no RS0051 warnings.

Extract the shared resolve-template/split-path/sanitize-leaf/recombine pipeline into a single static ArtifactNamingHelper.ResolveAndSanitize overload that accepts a leaf sanitizer delegate. ArtifactNamingService and ReportFileNameHelper now both delegate to it, removing the near-identical duplicated logic described in #9841. The non-empty leaf guard is now applied on both paths.
Fixes#9841
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8c5b1087-7e14-45e5-a444-daf19d40d832
CopilotAI review requested due to automatic review settings July 11, 2026 12:12

CopilotAI 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

Unifies artifact template resolution and leaf-name sanitization in ArtifactNamingHelper, resolving #9841.

Changes:

  • Extracts the shared resolve-and-sanitize pipeline.
  • Delegates platform and report naming paths to the shared helper.
  • Tracks the new internal API across all linked-source assemblies.
Show a summary per file
FileDescription
SharedExtensionHelpers/ReportFileNameHelper.csDelegates report naming to the shared pipeline.
Microsoft.Testing.Platform/Services/ArtifactNamingService.csDelegates artifact naming to the shared pipeline.
Microsoft.Testing.Platform/Services/ArtifactNamingHelper.csAdds the shared resolve-and-sanitize implementation.
Microsoft.Testing.Platform/InternalAPI/InternalAPI.Unshipped.txtTracks the new internal method.
Microsoft.Testing.Extensions.VideoRecorder/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.TrxReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.JUnitReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.HtmlReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.HangDump/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.CtrfReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.CrashDump/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.

Review details

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

@github-actionsgithub-actionsBot 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.

Note

🤖 Automated review by GitHub Copilot. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.

Review Summary

Clean, well-scoped refactoring that unifies two near-identical template-resolve-and-sanitize pipelines into a single ArtifactNamingHelper.ResolveAndSanitize method. Both callers (ArtifactNamingService.ResolveFileName and ReportFileNameHelper.ResolveAndSanitize) now delegate to it, passing their respective sanitizer functions.

#DimensionVerdict
1Algorithmic Correctness✅ Logic is identical to the extracted code. One minor behavioral tightening noted inline (empty leaf name now throws for ReportFileNameHelper path too).
2Edge Cases & Error Handling
3Concurrency & Thread SafetyN/A
4Performance & Allocations✅ No change in allocation profile
5API Design & Public Surface✅ Internal API, properly declared in InternalAPI.Unshipped.txt for all referencing projects
6Backward Compatibility✅ Internal-only change
7Cross-TFM Correctness✅ No TFM-specific code
8Security
9Naming & Conventions
10Code Style & Formatting
11Documentation✅ Thorough XML docs
12LocalizationN/A
13Testing✅ Existing tests cover both callers
14–22Remaining dimensionsN/A or ✅

Overall: This is a textbook DRY refactoring. No blocking issues found.

Comment threadsrc/Platform/SharedExtensionHelpers/ReportFileNameHelper.cs
@github-actions

Copy link
Copy Markdown
Contributor

🔴 Build Failure Analysis

Build: FAILED | Duration: 255s | Errors: 5 (4 unique) | Warnings: 1

Root Cause

All 4 compilation errors are CA1416 (platform compatibility) in test/UnitTests/Microsoft.Testing.Platform.UnitTests/Logging/FileLoggerTests.cs at lines 465 and 490 (two TFMs, so each appears twice):

error CA1416: This call site is reachable on all platforms.
'ITask.RunLongRunning(Func<Task>, string, CancellationToken)' is unsupported on: 'browser'.

The ITask.RunLongRunning method is annotated with [UnsupportedOSPlatform("browser")], and the two inner ITask wrapper classes (MonitoringTask and NeverCompletingTask) in FileLoggerTests.cs delegate to it without suppressing the warning.

Relationship to This PR

⚠️This file is not modified by this PR. These appear to be pre-existing errors on the base branch that may have been recently introduced by a prior commit adding the [UnsupportedOSPlatform] attribute to ITask.RunLongRunning, or a change that enabled CA1416 for this project.

Suggested Fix

Add [SupportedOSPlatform] or suppress CA1416 on the two wrapper classes in FileLoggerTests.cs. For example, add #pragma warning disable CA1416 around the RunLongRunning delegation calls at lines 465 and 490, since the test never actually runs on browser:

#pragma warning disable CA1416// Platform compatibility — tests don't target browserpublicTaskRunLongRunning(Func<Task>action,stringname,CancellationTokencancellationToken)=>_inner.RunLongRunning(action,name,cancellationToken);
#pragma warning restore CA1416

This fix would need to be applied to both MonitoringTask (line 465) and NeverCompletingTask (line 490).

🤖 Automated content by GitHub Copilot. Generated by the Build Failure Analysis workflow. · 53.8 AIC · ⌖ 5.67 AIC · ⊞ 7.3K · [◷]( · )

@Evangelink

Copy link
Copy Markdown
MemberAuthor

Thanks for the analysis. Confirmed these CA1416 errors are pre-existing on main and not caused by this PR — the failing file (\ est/UnitTests/Microsoft.Testing.Platform.UnitTests/Logging/FileLoggerTests.cs) is not modified here, and the \ITask.RunLongRunning\ delegations already exist on \main. They're being addressed separately, so this PR (a scoped dedup refactor) intentionally leaves them alone; CI should go green once main is fixed and this branch is rebased.

@Evangelink
Amaury Levé (Evangelink) merged commit e2d1590 into mainJul 11, 2026
28 of 35 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/expert-bassoon branch July 11, 2026 12:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[duplicate-code] Duplicate Code: Template-Resolve-and-Sanitize Pipeline in ArtifactNamingService vs ReportFileNameHelper

2 participants

@Evangelink
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Unify template-resolve-and-sanitize pipeline in ArtifactNamingHelper - #9855

Merged
Amaury Levé (Evangelink) merged 1 commit into
mainfrom
dev/amauryleve/expert-bassoon
Jul 11, 2026
Merged

Unify template-resolve-and-sanitize pipeline in ArtifactNamingHelper#9855
Amaury Levé (Evangelink) merged 1 commit into
mainfrom
dev/amauryleve/expert-bassoon

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Fixes#9841.

Problem

ArtifactNamingService.ResolveFileName (in Microsoft.Testing.Platform) and ReportFileNameHelper.ResolveAndSanitize (in SharedExtensionHelpers) implemented the same algorithm: resolve template placeholders via ArtifactNamingHelper, split the result into directory + leaf, sanitize the leaf, and reassemble the path. The only real differences were where the process name/id came from and which sanitizer was used.

Change

Applied recommendation #2 from the issue (smaller, less invasive): extracted the shared pipeline into a single static overload ArtifactNamingHelper.ResolveAndSanitize(template, processName, processId, timestamp, sanitizeLeafFileName) that takes the leaf sanitizer as a Func<string, string> delegate.

  • ArtifactNamingService.ResolveFileName now delegates, passing ArtifactFileNameSanitizer.ReplaceInvalidFileNameChars.
  • ReportFileNameHelper.ResolveAndSanitize now delegates, passing ReportFileNameSanitizer.ReplaceInvalidFileNameChars. Its public signature is unchanged (matches the shipped InternalAPI), so no shipped-API churn.
  • The non-empty leaf-name guard that only ArtifactNamingService previously had is now applied on both paths.

The two sanitizers (ArtifactFileNameSanitizer / ReportFileNameSanitizer) are intentionally left as-is and passed in as delegates — consolidating them is tracked separately (the related issue referenced in #9841).

Notes

  • The new ArtifactNamingHelper.ResolveAndSanitize member is added to the InternalAPI.Unshipped.txt of every project that links the ArtifactNamingHelper source (RS0051).

Testing

  • Microsoft.Testing.Platform.UnitTests — ArtifactNaming* tests: 24/24 passed.
  • Microsoft.Testing.Extensions.UnitTests — ReportFileName* tests: 12/12 passed.
  • Report extensions (Trx/Html/JUnit/Ctrf/…) build clean with no RS0051 warnings.

Extract the shared resolve-template/split-path/sanitize-leaf/recombine pipeline into a single static ArtifactNamingHelper.ResolveAndSanitize overload that accepts a leaf sanitizer delegate. ArtifactNamingService and ReportFileNameHelper now both delegate to it, removing the near-identical duplicated logic described in #9841. The non-empty leaf guard is now applied on both paths.
Fixes#9841
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8c5b1087-7e14-45e5-a444-daf19d40d832
CopilotAI review requested due to automatic review settings July 11, 2026 12:12

CopilotAI 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

Unifies artifact template resolution and leaf-name sanitization in ArtifactNamingHelper, resolving #9841.

Changes:

  • Extracts the shared resolve-and-sanitize pipeline.
  • Delegates platform and report naming paths to the shared helper.
  • Tracks the new internal API across all linked-source assemblies.
Show a summary per file
FileDescription
SharedExtensionHelpers/ReportFileNameHelper.csDelegates report naming to the shared pipeline.
Microsoft.Testing.Platform/Services/ArtifactNamingService.csDelegates artifact naming to the shared pipeline.
Microsoft.Testing.Platform/Services/ArtifactNamingHelper.csAdds the shared resolve-and-sanitize implementation.
Microsoft.Testing.Platform/InternalAPI/InternalAPI.Unshipped.txtTracks the new internal method.
Microsoft.Testing.Extensions.VideoRecorder/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.TrxReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.JUnitReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.HtmlReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.HangDump/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.CtrfReport/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.
Microsoft.Testing.Extensions.CrashDump/InternalAPI/InternalAPI.Unshipped.txtTracks the linked method.

Review details

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

@github-actionsgithub-actionsBot 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.

Note

🤖 Automated review by GitHub Copilot. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.

Review Summary

Clean, well-scoped refactoring that unifies two near-identical template-resolve-and-sanitize pipelines into a single ArtifactNamingHelper.ResolveAndSanitize method. Both callers (ArtifactNamingService.ResolveFileName and ReportFileNameHelper.ResolveAndSanitize) now delegate to it, passing their respective sanitizer functions.

#DimensionVerdict
1Algorithmic Correctness✅ Logic is identical to the extracted code. One minor behavioral tightening noted inline (empty leaf name now throws for ReportFileNameHelper path too).
2Edge Cases & Error Handling
3Concurrency & Thread SafetyN/A
4Performance & Allocations✅ No change in allocation profile
5API Design & Public Surface✅ Internal API, properly declared in InternalAPI.Unshipped.txt for all referencing projects
6Backward Compatibility✅ Internal-only change
7Cross-TFM Correctness✅ No TFM-specific code
8Security
9Naming & Conventions
10Code Style & Formatting
11Documentation✅ Thorough XML docs
12LocalizationN/A
13Testing✅ Existing tests cover both callers
14–22Remaining dimensionsN/A or ✅

Overall: This is a textbook DRY refactoring. No blocking issues found.

Comment threadsrc/Platform/SharedExtensionHelpers/ReportFileNameHelper.cs
@github-actions

Copy link
Copy Markdown
Contributor

🔴 Build Failure Analysis

Build: FAILED | Duration: 255s | Errors: 5 (4 unique) | Warnings: 1

Root Cause

All 4 compilation errors are CA1416 (platform compatibility) in test/UnitTests/Microsoft.Testing.Platform.UnitTests/Logging/FileLoggerTests.cs at lines 465 and 490 (two TFMs, so each appears twice):

error CA1416: This call site is reachable on all platforms.
'ITask.RunLongRunning(Func<Task>, string, CancellationToken)' is unsupported on: 'browser'.

The ITask.RunLongRunning method is annotated with [UnsupportedOSPlatform("browser")], and the two inner ITask wrapper classes (MonitoringTask and NeverCompletingTask) in FileLoggerTests.cs delegate to it without suppressing the warning.

Relationship to This PR

⚠️This file is not modified by this PR. These appear to be pre-existing errors on the base branch that may have been recently introduced by a prior commit adding the [UnsupportedOSPlatform] attribute to ITask.RunLongRunning, or a change that enabled CA1416 for this project.

Suggested Fix

Add [SupportedOSPlatform] or suppress CA1416 on the two wrapper classes in FileLoggerTests.cs. For example, add #pragma warning disable CA1416 around the RunLongRunning delegation calls at lines 465 and 490, since the test never actually runs on browser:

#pragma warning disable CA1416// Platform compatibility — tests don't target browserpublicTaskRunLongRunning(Func<Task>action,stringname,CancellationTokencancellationToken)=>_inner.RunLongRunning(action,name,cancellationToken);
#pragma warning restore CA1416

This fix would need to be applied to both MonitoringTask (line 465) and NeverCompletingTask (line 490).

🤖 Automated content by GitHub Copilot. Generated by the Build Failure Analysis workflow. · 53.8 AIC · ⌖ 5.67 AIC · ⊞ 7.3K · [◷]( · )

@Evangelink

Copy link
Copy Markdown
MemberAuthor

Thanks for the analysis. Confirmed these CA1416 errors are pre-existing on main and not caused by this PR — the failing file (\ est/UnitTests/Microsoft.Testing.Platform.UnitTests/Logging/FileLoggerTests.cs) is not modified here, and the \ITask.RunLongRunning\ delegations already exist on \main. They're being addressed separately, so this PR (a scoped dedup refactor) intentionally leaves them alone; CI should go green once main is fixed and this branch is rebased.

@Evangelink
Amaury Levé (Evangelink) merged commit e2d1590 into mainJul 11, 2026
28 of 35 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/expert-bassoon branch July 11, 2026 12:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[duplicate-code] Duplicate Code: Template-Resolve-and-Sanitize Pipeline in ArtifactNamingService vs ReportFileNameHelper

2 participants

@Evangelink