Skip to content

Enforce case-insensitive behaviour for matching and replacement in TfsNodeStructureTool#3130

Merged
MrHinsh merged 2 commits into
mainfrom
copilot/enforce-case-insensitive-mapping
Apr 10, 2026
Merged

Enforce case-insensitive behaviour for matching and replacement in TfsNodeStructureTool#3130
MrHinsh merged 2 commits into
mainfrom
copilot/enforce-case-insensitive-mapping

Conversation

Copilot AI commented Apr 10, 2026

Copy link
Copy Markdown
Contributor

TfsNodeStructureTool.GetNewNodeName matched mapping rules with RegexOptions.IgnoreCase but performed the replacement without it — causing silent failures where a rule matched but the transformation was never applied when casing differed.

Changes

  • TfsNodeStructureTool.cs: Added RegexOptions.IgnoreCase to both Regex.Replace calls in GetNewNodeName:
    • Mapper rule replacement (was missing the flag while IsMatch had it)
    • Last-resort rule replacement (same inconsistency)
// Before
string replacement = Regex.Replace(sourceNodePath, mapper.Match, mapper.Replacement);
return Regex.Replace(sourceNodePath, lastResortRule.Key, lastResortRule.Value);

// After
string replacement = Regex.Replace(sourceNodePath, mapper.Match, mapper.Replacement, RegexOptions.IgnoreCase);
return Regex.Replace(sourceNodePath, lastResortRule.Key, lastResortRule.Value, RegexOptions.IgnoreCase);
  • TfsNodeStructureTests.cs: Added GetNewNodeName_WithCaseDifferenceInSourcePath_AppliesMappingConsistently — verifies that a lowercase source path is correctly transformed by a mixed-case Match pattern.

Things to be aware of

  • Logging uses serilog - All Logging should be in the format "My message that contains {item} and {item2}", item, item2! Do not use $"My message that contains {item} and {item2}" to pass text into the log strings as this disables Serilog's ability to pass that data as telemetry to Application Insights and for log highlighting.

Type of change

  • Bug fix (non-breaking change which fixes an issue)

How Has This Been Tested?

  • GetNewNodeName_WithCaseDifferenceInSourcePath_AppliesMappingConsistently — new unit test covering the case-insensitive replacement path
  • Existing TfsNodeStructureToolTests L0/L1 tests confirm no regression in normal-casing scenarios

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

Copilot AI changed the title [WIP] Fix case sensitivity in TfsNodeStructureTool mapping Enforce case-insensitive behaviour for matching and replacement in TfsNodeStructureTool Apr 10, 2026
Copilot AI requested a review from MrHinsh April 10, 2026 16:19
@MrHinsh MrHinsh requested review from Copilot and satano April 10, 2026 17:26
@MrHinsh MrHinsh marked this pull request as ready for review April 10, 2026 17:27
@MrHinsh MrHinsh enabled auto-merge April 10, 2026 17:27
@nkdagility-actions-bot

Copy link
Copy Markdown

Azure Static Web Apps: Your stage site is ready! Visit it here: https://blue-river-093197403-3130.westeurope.5.azurestaticapps.net

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Fixes a bug in TfsNodeStructureTool.GetNewNodeName where mapping rules could match case-insensitively but fail to apply because the actual replacements were case-sensitive.

Changes:

  • Apply RegexOptions.IgnoreCase consistently to both mapper-rule and last-resort Regex.Replace calls.
  • Add an L0 unit test verifying that a mixed-case mapping rule correctly transforms a differently-cased source path.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/MigrationTools.Clients.TfsObjectModel/Tools/TfsNodeStructureTool.cs Makes regex replacement behavior case-insensitive to match the existing case-insensitive matching behavior.
src/MigrationTools.Clients.TfsObjectModel.Tests/Tools/TfsNodeStructureTests.cs Adds a regression test covering case-insensitive replacement for node path mappings.

Comment on lines 113 to +117
Log.LogDebug("NodeStructureEnricher.GetNewNodeName::Mappers::{key}", mapper.Match);
if (Regex.IsMatch(sourceNodePath, mapper.Match, RegexOptions.IgnoreCase))
{
Log.LogDebug("NodeStructureEnricher.GetNewNodeName::Mappers::{key}::Match", mapper.Match);
string replacement = Regex.Replace(sourceNodePath, mapper.Match, mapper.Replacement);
string replacement = Regex.Replace(sourceNodePath, mapper.Match, mapper.Replacement, RegexOptions.IgnoreCase);

Copilot AI Apr 10, 2026

Copy link

Choose a reason for hiding this comment

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

The mapping regex patterns (mapper.Match) come from configuration. Using Regex.IsMatch/Regex.Replace without a match timeout can allow pathological patterns to cause excessive CPU (catastrophic backtracking) during migrations. Consider using the Regex.* overloads that accept a TimeSpan matchTimeout (for both IsMatch and Replace) and handling RegexMatchTimeoutException to surface a clear configuration error.

Copilot uses AI. Check for mistakes.
@MrHinsh MrHinsh merged commit b43c267 into main Apr 10, 2026
19 checks passed
@MrHinsh MrHinsh deleted the copilot/enforce-case-insensitive-mapping branch April 10, 2026 17:34
Sign up for free to 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.

Enforce case-insensitive behaviour for matching and replacement in TfsNodeStructureTool

3 participants