Skip to content

Commit 2151432

Browse files
committed
Allow to create new root structure nodes (areas, iterations)
This allows to create new area even if there are not any in the source project. So it is possible to have some new area in target if there is no area in source.
1 parent 39a1814 commit 2151432

File tree

1 file changed

+22
-11
lines changed

1 file changed

+22
-11
lines changed

src/MigrationTools.Clients.TfsObjectModel/Tools/TfsNodeStructureTool.cs

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,22 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Linq;
4-
using System.Text;
54
using System.Text.RegularExpressions;
65
using System.Xml;
76
using Microsoft.Extensions.DependencyInjection;
87
using Microsoft.Extensions.Logging;
98
using Microsoft.Extensions.Options;
109
using Microsoft.TeamFoundation.Common;
1110
using Microsoft.TeamFoundation.Server;
12-
using Microsoft.TeamFoundation.Work.WebApi;
1311
using MigrationTools.Clients;
1412
using MigrationTools.DataContracts;
1513
using MigrationTools.Endpoints;
16-
using MigrationTools.Enrichers;
1714
using MigrationTools.Exceptions;
1815
using MigrationTools.FieldMaps;
19-
using MigrationTools.Processors;
2016
using MigrationTools.Processors.Infrastructure;
2117
using MigrationTools.Services;
2218
using MigrationTools.Tools.Infrastructure;
2319
using Newtonsoft.Json;
24-
using Serilog.Context;
25-
using Serilog.Events;
26-
using static Microsoft.TeamFoundation.WorkItemTracking.Client.Node;
2720
using ILogger = Serilog.ILogger;
2821

2922

@@ -199,7 +192,6 @@ private NodeInfo GetOrCreateNode(string nodePath, DateTime? startDate, DateTime?
199192
Log.LogDebug(" Not Found:", currentAncestorPath);
200193
parentNode = null;
201194
}
202-
203195
}
204196
}
205197
else
@@ -286,7 +278,8 @@ public void ProcessorExecutionBegin(TfsProcessor processor)
286278
Log.LogInformation("Migrating all Nodes before the Processor run.");
287279
MigrateAllNodeStructures();
288280
RefreshForProcessorType(processor);
289-
} else
281+
}
282+
else
290283
{
291284
Log.LogInformation("SKIP: Migrating all Nodes before the Processor run.");
292285
}
@@ -397,13 +390,15 @@ private string GetSystemPath(string newUserPath, TfsNodeStructureType structureT
397390
private static string GetUserFriendlyPath(string systemNodePath)
398391
{
399392
// Shape of the path is \SourceProject\StructureType\Rest\Of\The\Path, user-friendly shape skips StructureType and initial \
400-
var match = Regex.Match(systemNodePath, @"^\\(?<sourceProject>[^\\]+)\\[^\\]+\\(?<restOfThePath>.*)$");
393+
var match = Regex.Match(systemNodePath, @"^\\(?<sourceProject>[^\\]+)\\[^\\]+(\\(?<restOfThePath>.*))?$");
401394
if (!match.Success)
402395
{
403396
throw new InvalidOperationException($"This path is not a valid area or iteration path: {systemNodePath}");
404397
}
398+
string sourceProject = match.Groups["sourceProject"].Value;
399+
string restOfThePath = match.Groups["restOfThePath"].Success ? match.Groups["restOfThePath"].Value : string.Empty;
405400

406-
return $"{match.Groups["sourceProject"].Value}\\{match.Groups["restOfThePath"].Value}";
401+
return restOfThePath == string.Empty ? sourceProject : $"{sourceProject}\\{restOfThePath}";
407402
}
408403

409404
private void MigrateAllNodeStructures()
@@ -471,6 +466,8 @@ private void ProcessCommonStructure(string treeTypeSource, string localizedTreeT
471466

472467
_pathToKnownNodeMap[structureParent.Path] = structureParent;
473468

469+
XmlElement mainNode = sourceTree.ChildNodes.OfType<XmlElement>().First();
470+
CreateNewRootNode(mainNode, nodeStructureType);
474471
if (sourceTree.ChildNodes[0].HasChildNodes)
475472
{
476473
// The XPath would look like this: /Nodes/Node[Name=Area]/Children/...
@@ -479,6 +476,20 @@ private void ProcessCommonStructure(string treeTypeSource, string localizedTreeT
479476
}
480477
}
481478

479+
private void CreateNewRootNode(XmlElement node, TfsNodeStructureType nodeStructureType)
480+
{
481+
string userFriendlyPath = GetUserFriendlyPath(node.Attributes["Path"].Value);
482+
string newUserPath = GetNewNodeName(userFriendlyPath, nodeStructureType);
483+
string newSystemPath = GetSystemPath(newUserPath, nodeStructureType, _targetLanguageMaps);
484+
if (!Regex.IsMatch(newSystemPath, @"\\" + nodeStructureType + @"\\?$"))
485+
{
486+
// Do not do anything if there is no node name after structure type for the new (target) node.
487+
// For example, if the path is just "\Project\Area" or "\Project\Iteration".
488+
// This will happen if there are no mappings for nodes.
489+
GetOrCreateNode(newSystemPath, null, null);
490+
}
491+
}
492+
482493
private List<string> _matchedPath = new List<string>();
483494

484495
/// <summary>

0 commit comments

Comments
 (0)