diff --git a/Migrators/AllureExporter/App.cs b/Migrators/AllureExporter/App.cs index 4a009c2..08669f2 100644 --- a/Migrators/AllureExporter/App.cs +++ b/Migrators/AllureExporter/App.cs @@ -19,7 +19,15 @@ public void Run(string[] args) { _logger.LogInformation("Starting application"); - _exportService.ExportProject().Wait(); + try + { + _exportService.ExportProject().Wait(); + } + catch (Exception e) + { + _logger.LogError(e, "Error occurred during export"); + throw; + } _logger.LogInformation("Ending application"); } diff --git a/Migrators/AzureExporter/App.cs b/Migrators/AzureExporter/App.cs index d39ef69..9e5a852 100644 --- a/Migrators/AzureExporter/App.cs +++ b/Migrators/AzureExporter/App.cs @@ -19,7 +19,15 @@ public void Run(string[] args) { _logger.LogInformation("Starting application"); - _service.ExportProject().Wait(); + try + { + _service.ExportProject().Wait(); + } + catch (Exception e) + { + _logger.LogError(e, "Error occurred during export"); + throw; + } _logger.LogInformation("Ending application"); } diff --git a/Migrators/AzureExporter/Client/Client.cs b/Migrators/AzureExporter/Client/Client.cs index 9f196db..3f10898 100644 --- a/Migrators/AzureExporter/Client/Client.cs +++ b/Migrators/AzureExporter/Client/Client.cs @@ -7,7 +7,6 @@ using Microsoft.TeamFoundation.WorkItemTracking.WebApi; using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models; using Microsoft.VisualStudio.Services.Common; -using Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi; using Microsoft.VisualStudio.Services.WebApi; namespace AzureExporter.Client; @@ -17,7 +16,6 @@ public class Client : IClient private readonly ILogger _logger; private readonly ProjectHttpClient _projectClient; - private readonly TestPlanHttpClient _testPlanClient; private readonly WorkItemTrackingHttpClient _workItemTrackingClient; private readonly WorkHttpClient _workHttpClient; private readonly string _projectName; @@ -52,7 +50,6 @@ public Client(ILogger logger, IConfiguration configuration) var connection = new VssConnection(new Uri(url), new VssBasicCredential(string.Empty, token)); _projectClient = connection.GetClient(); - _testPlanClient = connection.GetClient(); _workItemTrackingClient = connection.GetClient(); _workHttpClient = connection.GetClient(); } @@ -75,29 +72,6 @@ public async Task GetProject() }; } - public async Task> GetTestPlansByProjectId(Guid id) - { - var testPlans = _testPlanClient.GetTestPlansAsync(project: id).Result; - - return testPlans; - } - - public async Task> GetTestSuitesByProjectIdAndTestPlanId(Guid projectId, int planId) - { - var testSuites = _testPlanClient.GetTestSuitesForPlanAsync(project: projectId, planId: planId).Result; - - return testSuites; - } - - public async Task> GetTestCaseListByProjectIdAndTestPlanIdAndSuiteId(Guid projectId, int planId, - int suiteId) - { - var testCases = _testPlanClient.GetTestCaseListAsync(project: projectId, planId: planId, suiteId: suiteId) - .Result; - - return testCases; - } - public async Task> GetWorkItemIds(string workItemType) { var wiql = new Wiql @@ -115,9 +89,13 @@ public async Task> GetWorkItemIds(string workItemType) public async Task GetWorkItemById(int id) { + _logger.LogInformation("Getting work item with ID {Id}", id); + var workItem = _workItemTrackingClient.GetWorkItemAsync(_projectName, id, expand: WorkItemExpand.All).Result; - var result = new AzureWorkItem() + _logger.LogDebug("Work item: {@WorkItem}", workItem); + + var result = new AzureWorkItem { Id = workItem.Id!.Value, Title = GetValueOfField(workItem.Fields, "System.Title"), @@ -127,22 +105,26 @@ public async Task GetWorkItemById(int id) Steps = GetValueOfField(workItem.Fields, "Microsoft.VSTS.TCM.Steps"), IterationPath = GetValueOfField(workItem.Fields, "System.IterationPath"), Tags = GetValueOfField(workItem.Fields, "System.Tags"), - Links = workItem.Relations - .Where(r => r.Rel == "ArtifactLink") - .Select(r => new AzureLink - { - Title = GetValueOfField(r.Attributes, "name"), - Url = r.Url - }) - .ToList(), - Attachments = workItem.Relations - .Where(r => r.Rel == "AttachedFile") - .Select(r => new AzureAttachment - { - Id = new Guid(r.Url[^36..]), - Name = GetValueOfField(r.Attributes, "name"), - }) - .ToList(), + Links = workItem.Relations == null + ? new List() + : workItem.Relations + .Where(r => r.Rel == "ArtifactLink") + .Select(r => new AzureLink + { + Title = GetValueOfField(r.Attributes, "name"), + Url = r.Url + }) + .ToList(), + Attachments = workItem.Relations == null + ? new List() + : workItem.Relations + .Where(r => r.Rel == "AttachedFile") + .Select(r => new AzureAttachment + { + Id = new Guid(r.Url[^36..]), + Name = GetValueOfField(r.Attributes, "name"), + }) + .ToList(), Parameters = new AzureParameters { Keys = GetValueOfField(workItem.Fields, "Microsoft.VSTS.TCM.Parameters"), @@ -155,11 +137,16 @@ public async Task GetWorkItemById(int id) public async Task> GetIterations(Guid projectId) { - var iterations = _workHttpClient.GetTeamIterationsAsync(new TeamContext(projectId)).Result; + _logger.LogInformation("Getting iterations"); - return iterations + var iterations = _workHttpClient.GetTeamIterationsAsync(new TeamContext(projectId)).Result; + var paths = iterations .Select(i => i.Path) .ToList(); + + _logger.LogDebug("Got iterations: {@Iterations}", paths); + + return paths; } public async Task GetAttachmentById(Guid id) diff --git a/Migrators/AzureExporter/Services/AttributeService.cs b/Migrators/AzureExporter/Services/AttributeService.cs index e0d91ce..a8dcbe9 100644 --- a/Migrators/AzureExporter/Services/AttributeService.cs +++ b/Migrators/AzureExporter/Services/AttributeService.cs @@ -1,4 +1,3 @@ -using AzureExporter.Client; using Microsoft.Extensions.Logging; using Models; using Attribute = Models.Attribute; @@ -9,70 +8,44 @@ namespace AzureExporter.Services; public class AttributeService : IAttributeService { private readonly ILogger _logger; - private readonly IClient _client; - public AttributeService(ILogger logger, IClient client) + public AttributeService(ILogger logger) { _logger = logger; - _client = client; } public async Task> GetCustomAttributes(Guid projectId) { _logger.LogInformation("Getting custom attributes"); - var attributes = new List(); - - var iterations = await _client.GetIterations(projectId); - - attributes.Add(new Attribute - { - Id = Guid.NewGuid(), - Name = Constants.IterationAttributeName, - Type = AttributeType.Options, - IsActive = true, - IsRequired = false, - Options = ConvertIterations(iterations) - }); - - attributes.Add(new Attribute - { - Id = Guid.NewGuid(), - Name = Constants.StateAttributeName, - Type = AttributeType.Options, - IsActive = true, - IsRequired = false, - Options = new List - { - "Active", - "Closed", - "Design", - "Ready" - } - }); - - return attributes; - } - - private static List ConvertIterations(IEnumerable iterations) - { - var iterationList = new List(); - - foreach (var iteration in iterations) + var attributes = new List { - var iter = iteration.Split('\\'); - if (iter.Length == 1) + new() { - iterationList.Add(iteration); - continue; - } - - for (var i = iter.Length; i > 1; i--) + Id = Guid.NewGuid(), + Name = Constants.IterationAttributeName, + Type = AttributeType.String, + IsActive = true, + IsRequired = false, + Options = new List() + }, + new() { - iterationList.Add(string.Join("\\", iter.Take(i))); + Id = Guid.NewGuid(), + Name = Constants.StateAttributeName, + Type = AttributeType.Options, + IsActive = true, + IsRequired = false, + Options = new List + { + "Active", + "Closed", + "Design", + "Ready" + } } - } + }; - return iterationList; + return attributes; } } diff --git a/Migrators/AzureExporter/Services/LinkService.cs b/Migrators/AzureExporter/Services/LinkService.cs index d26644e..6840e4c 100644 --- a/Migrators/AzureExporter/Services/LinkService.cs +++ b/Migrators/AzureExporter/Services/LinkService.cs @@ -38,22 +38,51 @@ public LinkService(ILogger logger, IConfiguration configuration) public List CovertLinks(IEnumerable links) { + _logger.LogInformation("Converting links: {@Links}", links); + var convertedLinks = new List(); foreach (var link in links) { var decodedUrl = HttpUtility.UrlDecode(link.Url); + while (decodedUrl.Contains('%')) + { + decodedUrl = HttpUtility.UrlDecode(decodedUrl); + } + var urlParts = decodedUrl.Split('/'); - var project = urlParts[6]; - var suffix = link.Title.Equals("Branch") - ? $"?version={urlParts[^1]}" - : $"/commit/{urlParts[^1]}"; - var convertedLink = new Link + Link convertedLink; + if (link.Url.Contains("VersionControl/Changeset")) { - Url = $"{_url}/{_projectName}/_git/{project}{suffix}", - Title = link.Title - }; + convertedLink = new Link + { + Url = $"{_url}/{_projectName}/_versionControl/changeset/{urlParts.Last()}", + Title = link.Title + }; + } + else if (link.Url.Contains("VersionControl/VersionedItem")) + { + convertedLink = new Link + { + Url = + $"{_url}/{_projectName}/_versionControl/?path=${decodedUrl.Split("VersionControl/VersionedItem/$").Last().Replace("changesetVersion", "version").Replace("deletionId=0", "_a=contents")}", + Title = link.Title + }; + } + else + { + var project = urlParts[6]; + var suffix = link.Title.Equals("Branch") + ? $"?version={urlParts[^1]}" + : $"/commit/{urlParts[^1]}"; + + convertedLink = new Link + { + Url = $"{_url}/{_projectName}/_git/{project}{suffix}", + Title = link.Title + }; + } _logger.LogDebug("Converted link {@OldLink}: {@Link}", link, convertedLink); diff --git a/Migrators/AzureExporter/Services/ParameterService.cs b/Migrators/AzureExporter/Services/ParameterService.cs index 78ca0df..1993c81 100644 --- a/Migrators/AzureExporter/Services/ParameterService.cs +++ b/Migrators/AzureExporter/Services/ParameterService.cs @@ -19,7 +19,7 @@ public List> ConvertParameters(AzureParameters parame _logger.LogInformation("Converting parameters"); _logger.LogDebug("Parameters: {@Parameters}", parameters); - if (string.IsNullOrWhiteSpace(parameters.Keys)) + if (string.IsNullOrWhiteSpace(parameters.Keys) || !parameters.Keys.Contains('<')) { _logger.LogDebug("No keys found in parameters"); @@ -53,14 +53,20 @@ private static List ParseParameterKeys(string content) private static List> ParseParameterValues(string content) { - var xmlDoc = XDocument.Parse(content); - - var parameters = xmlDoc.Descendants("Table1") - .Select(table1Node => table1Node.Elements() - .ToDictionary(element => element.Name.LocalName, - element => string.IsNullOrWhiteSpace(element.Value) ? "Empty" : element.Value.Trim())) - .ToList(); - - return parameters; + try + { + var xmlDoc = XDocument.Parse(content); + var parameters = xmlDoc.Descendants("Table1") + .Select(table1Node => table1Node.Elements() + .ToDictionary(element => element.Name.LocalName, + element => string.IsNullOrWhiteSpace(element.Value) ? "Empty" : element.Value.Trim())) + .ToList(); + + return parameters; + } + catch (Exception) + { + return new List>(); + } } } diff --git a/Migrators/AzureExporter/Services/SharedStepService.cs b/Migrators/AzureExporter/Services/SharedStepService.cs index 49a2bab..90d9ab5 100644 --- a/Migrators/AzureExporter/Services/SharedStepService.cs +++ b/Migrators/AzureExporter/Services/SharedStepService.cs @@ -32,7 +32,7 @@ public async Task> ConvertSharedSteps(Guid projectId var workItemIds = await _client.GetWorkItemIds(Constants.SharedStepType); - _logger.LogDebug("Found {@WorkItems} shared steps", workItemIds.Count); + _logger.LogDebug("Found {Count} shared steps: {@WorkItems}", workItemIds.Count, workItemIds); var sharedSteps = new Dictionary(); @@ -40,7 +40,7 @@ public async Task> ConvertSharedSteps(Guid projectId { var sharedStep = await _client.GetWorkItemById(workItemId); - _logger.LogDebug("Found shared step: {Id}", sharedStep.Id); + _logger.LogDebug("Found shared step with {Id}: {@SharedStep}", sharedStep.Id, sharedStep); var steps = _stepService.ConvertSteps(sharedStep.Steps, new Dictionary()); diff --git a/Migrators/AzureExporter/Services/TestCaseService.cs b/Migrators/AzureExporter/Services/TestCaseService.cs index 431713e..b8dee4f 100644 --- a/Migrators/AzureExporter/Services/TestCaseService.cs +++ b/Migrators/AzureExporter/Services/TestCaseService.cs @@ -41,6 +41,9 @@ public async Task> ConvertTestCases(Guid projectId, Dictionary(() => parameterService.ConvertParameters(parameters)); + var result = parameterService.ConvertParameters(parameters); + + // Assert + Assert.That(result, Is.Empty); } } diff --git a/Migrators/TestLinkExporter/TestLinkExporter.csproj b/Migrators/TestLinkExporter/TestLinkExporter.csproj index 2021938..04acaa2 100644 --- a/Migrators/TestLinkExporter/TestLinkExporter.csproj +++ b/Migrators/TestLinkExporter/TestLinkExporter.csproj @@ -11,13 +11,15 @@ - - - - - - - + + + + + + + + +