diff --git a/Adaptation/FileHandlers/Markdown/FileRead.cs b/Adaptation/FileHandlers/Markdown/FileRead.cs index 23bae67..2fb2d95 100644 --- a/Adaptation/FileHandlers/Markdown/FileRead.cs +++ b/Adaptation/FileHandlers/Markdown/FileRead.cs @@ -129,13 +129,14 @@ public class FileRead : Shared.FileRead, IFileRead return result; } - private static Dictionary GetKeyValuePairs(ReadOnlyDictionary workItems, WorkItem workItem) + private static ReadOnlyCollection GetKeyValuePairs(ReadOnlyDictionary workItems, WorkItem workItem) { - Dictionary results = new(); + List results = new(); int? childId; WorkItem? childWorkItem; + WorkItem? parentWorkItem; List collection = new(); - Dictionary keyValuePairs; + ReadOnlyCollection records; if (workItem.Relations is not null && workItem.Relations.Length > 0) { collection.Clear(); @@ -149,23 +150,31 @@ public class FileRead : Shared.FileRead, IFileRead collection = (from l in collection orderby l.State != "Closed", l.Id select l).ToList(); foreach (WorkItem item in collection) { - keyValuePairs = GetKeyValuePairs(workItems, item); - results.Add(item.Id, new(item, new(keyValuePairs))); + if (item.Parent is null) + parentWorkItem = null; + else + _ = workItems.TryGetValue(item.Parent.Value, out parentWorkItem); + records = GetKeyValuePairs(workItems, item); + results.Add(new(item, parentWorkItem, records)); } } - return results; + return new(results); } - private static ReadOnlyDictionary GetWorkItemAndChildren(ReadOnlyDictionary workItems) + private static ReadOnlyCollection GetRecords(ReadOnlyDictionary workItems) { - Dictionary results = new(); - Dictionary keyValuePairs; + List results = new(); + WorkItem? parentWorkItem; + ReadOnlyCollection records; foreach (KeyValuePair keyValuePair in workItems) { - // if (keyValuePair.Key != 119185) - // continue; - keyValuePairs = GetKeyValuePairs(workItems, keyValuePair.Value); - results.Add(keyValuePair.Key, new(keyValuePair.Value, new(keyValuePairs))); + if (keyValuePair.Value.Parent is null) + parentWorkItem = null; + else + _ = workItems.TryGetValue(keyValuePair.Value.Parent.Value, out parentWorkItem); + records = GetKeyValuePairs(workItems, keyValuePair.Value); + results.Add(new(keyValuePair.Value, parentWorkItem, records)); + } return new(results); } @@ -176,50 +185,50 @@ public class FileRead : Shared.FileRead, IFileRead return result; } - private static string GetLine(List spaces, WorkItem workItem, KeyValuePair keyValuePair, bool condensed, bool sprintOnly) => + private static string GetLine(List spaces, WorkItem workItem, Record record, bool condensed, bool sprintOnly) => sprintOnly ? $"\t- [ ] {workItem.IterationPath}" : - condensed ? $"{new string(spaces.Skip(1).ToArray())}- {GetClosed(workItem)} {keyValuePair.Key} - {workItem.Title}" : - $"{new string(spaces.Skip(1).ToArray())}- {GetClosed(workItem)} {keyValuePair.Key} - {workItem.Title} ~~~ {workItem.AssignedTo} - {workItem.IterationPath.Replace('\\', '-')} - {workItem.CreatedDate} --- {workItem.ClosedDate}"; + condensed ? $"{new string(spaces.Skip(1).ToArray())}- {GetClosed(workItem)} {record.WorkItem.Id} - {workItem.Title}" : + $"{new string(spaces.Skip(1).ToArray())}- {GetClosed(workItem)} {record.WorkItem.Id} - {workItem.Title} ~~~ {workItem.AssignedTo} - {workItem.IterationPath.Replace('\\', '-')} - {workItem.CreatedDate} --- {workItem.ClosedDate}"; private static void AppendLines(List spaces, List lines, Record record, bool condensed, bool sprintOnly) { string line; spaces.Add('\t'); WorkItem workItem; - foreach (KeyValuePair keyValuePair in record.Children) + foreach (Record child in record.Children) { - workItem = keyValuePair.Value.WorkItem; - line = GetLine(spaces, workItem, keyValuePair, condensed, sprintOnly).TrimEnd(); + workItem = child.WorkItem; + line = GetLine(spaces, workItem, child, condensed, sprintOnly).TrimEnd(); lines.Add(line); - AppendLines(spaces, lines, keyValuePair.Value, condensed, sprintOnly); + AppendLines(spaces, lines, child, condensed, sprintOnly); } spaces.RemoveAt(0); } - private static void AppendLines(string url, List spaces, List lines, ReadOnlyDictionary workItemAndChildren, string workItemType) + private static void AppendLines(string url, List spaces, List lines, ReadOnlyCollection records, string workItemType) { List results = new(); WorkItem workItem; string? maxIterationPath; List distinct = new(); - foreach (KeyValuePair keyValuePair in workItemAndChildren) + foreach (Record record in records) { - workItem = keyValuePair.Value.WorkItem; - // if (keyValuePair.Key != 109724) + workItem = record.WorkItem; + // if (record.WorkItem.Id != 109724) // continue; if (workItem.WorkItemType != workItemType) continue; results.Add($"## {workItem.AssignedTo} - {workItem.Id} - {workItem.Title}"); results.Add(string.Empty); results.Add($"- [{workItem.Id}]({url}{workItem.Id})"); - if (keyValuePair.Value.Children.Count == 0) + if (record.Children.Count == 0) results.Add(string.Empty); else { - AppendLines(spaces, results, keyValuePair.Value, condensed: true, sprintOnly: false); + AppendLines(spaces, results, record, condensed: true, sprintOnly: false); results.Add(string.Empty); distinct.Clear(); - AppendLines(spaces, distinct, keyValuePair.Value, condensed: false, sprintOnly: true); + AppendLines(spaces, distinct, record, condensed: false, sprintOnly: true); if (distinct.Count > 1) { results.Add($"## Distinct Iteration Path(s) - {workItem.WorkItemType} - {workItem.AssignedTo} - {workItem.Id} - {workItem.Title} - {workItem.IterationPath}"); @@ -238,7 +247,7 @@ public class FileRead : Shared.FileRead, IFileRead } results.Add($"## Extended - {workItem.Id} - {workItem.Title}"); results.Add(string.Empty); - AppendLines(spaces, results, keyValuePair.Value, condensed: false, sprintOnly: false); + AppendLines(spaces, results, record, condensed: false, sprintOnly: false); results.Add(string.Empty); } lines.AddRange(results); @@ -246,7 +255,16 @@ public class FileRead : Shared.FileRead, IFileRead } } - private static void WriteFiles(string destinationDirectory, string fileName, ReadOnlyCollection lines, ReadOnlyCollection workItems) + private static void WriteFiles(string destinationDirectory, ReadOnlyCollection records, string fileName) + { + string json = JsonSerializer.Serialize(records, new JsonSerializerOptions() { WriteIndented = true }); + string jsonFile = Path.Combine(destinationDirectory, $"{fileName}.json"); + string jsonOld = !File.Exists(jsonFile) ? string.Empty : File.ReadAllText(jsonFile); + if (json != jsonOld) + File.WriteAllText(jsonFile, json); + } + + private static void WriteFiles(string destinationDirectory, ReadOnlyCollection lines, ReadOnlyCollection workItems, string fileName) { string text = string.Join(Environment.NewLine, lines); string markdownFile = Path.Combine(destinationDirectory, $"{fileName}.md"); @@ -258,7 +276,7 @@ public class FileRead : Shared.FileRead, IFileRead string htmlOld = !File.Exists(htmlFile) ? string.Empty : File.ReadAllText(htmlFile); if (html != htmlOld) File.WriteAllText(htmlFile, html); - string json = JsonSerializer.Serialize(workItems.ToArray(), new JsonSerializerOptions() { WriteIndented = true }); + string json = JsonSerializer.Serialize(workItems, new JsonSerializerOptions() { WriteIndented = true }); string jsonFile = Path.Combine(destinationDirectory, $"{fileName}.json"); string jsonOld = !File.Exists(jsonFile) ? string.Empty : File.ReadAllText(jsonFile); if (json != jsonOld) @@ -269,9 +287,9 @@ public class FileRead : Shared.FileRead, IFileRead { List results = new(); WorkItem workItem; - foreach (KeyValuePair keyValuePair in record.Children) + foreach (Record item in record.Children) { - workItem = keyValuePair.Value.WorkItem; + workItem = item.WorkItem; if (!workItemTypes.Contains(workItem.WorkItemType)) continue; results.Add(workItem); @@ -293,34 +311,33 @@ public class FileRead : Shared.FileRead, IFileRead return result; } - private static ReadOnlyCollection FeatureCheckIterationPath122508(string url, List lines, ReadOnlyCollection workItemTypes, ReadOnlyDictionary workItemAndChildren, string workItemType) + private static ReadOnlyCollection FeatureCheckIterationPath122508(string url, List lines, ReadOnlyCollection workItemTypes, ReadOnlyCollection records, string workItemType) { - List collection = new(); + List results = new(); WorkItem workItem; string? maxIterationPath; - List results = new(); + List collection = new(); ReadOnlyCollection childrenWorkItems; - foreach (KeyValuePair keyValuePair in workItemAndChildren) + foreach (Record record in records) { - workItem = keyValuePair.Value.WorkItem; + workItem = record.WorkItem; if (workItem.WorkItemType != workItemType) continue; - results.Clear(); - if (keyValuePair.Value.Children.Count == 0) + collection.Clear(); + if (record.Children.Count == 0) continue; - childrenWorkItems = FilterChildren(keyValuePair.Value, workItemTypes); + childrenWorkItems = FilterChildren(record, workItemTypes); maxIterationPath = GetMaxIterationPath(childrenWorkItems); if (string.IsNullOrEmpty(maxIterationPath) || workItem.IterationPath == maxIterationPath) continue; - results.Add($"## {workItem.AssignedTo} - {workItem.Id} - {workItem.Title}"); - results.Add(string.Empty); - results.Add($"- [ ] [{workItem.Id}]({url}{workItem.Id}) => {workItem.IterationPath} != {maxIterationPath}"); - results.Add(string.Empty); - lines.AddRange(results); - collection.Add(WorkItem.Get(workItem, $"IterationPath:{workItem.Id};{workItem.IterationPath} != {maxIterationPath}")); - collection.Add(workItem); + collection.Add($"## {workItem.AssignedTo} - {workItem.Id} - {workItem.Title}"); + collection.Add(string.Empty); + collection.Add($"- [ ] [{workItem.Id}]({url}{workItem.Id}) => {workItem.IterationPath} != {maxIterationPath}"); + collection.Add(string.Empty); + lines.AddRange(collection); + results.Add(WorkItem.Get(workItem, $"IterationPath:{workItem.Id};{workItem.IterationPath} != {maxIterationPath}")); } - return new(collection); + return new(results); } private static ReadOnlyCollection GetWorkItemsNotMatching(string tags, ReadOnlyCollection workItems) @@ -338,44 +355,44 @@ public class FileRead : Shared.FileRead, IFileRead return new(results); } - private static ReadOnlyCollection FeatureCheckTag122514(string url, List lines, ReadOnlyCollection workItemTypes, ReadOnlyDictionary workItemAndChildren, string workItemType) + private static ReadOnlyCollection FeatureCheckTag122514(string url, List lines, ReadOnlyCollection workItemTypes, ReadOnlyCollection records, string workItemType) { - List collection = new(); + List results = new(); WorkItem workItem; - List results = new(); + List collection = new(); List violations = new(); ReadOnlyCollection childrenWorkItems; ReadOnlyCollection workItemsNotMatching; - foreach (KeyValuePair keyValuePair in workItemAndChildren) + foreach (Record record in records) { - workItem = keyValuePair.Value.WorkItem; + workItem = record.WorkItem; if (workItem.WorkItemType != workItemType) continue; - results.Clear(); + collection.Clear(); violations.Clear(); - if (keyValuePair.Value.Children.Count == 0) + if (record.Children.Count == 0) continue; if (string.IsNullOrEmpty(workItem.Tags)) workItemsNotMatching = new(new WorkItem[] { workItem }); else { - childrenWorkItems = FilterChildren(keyValuePair.Value, workItemTypes); + childrenWorkItems = FilterChildren(record, workItemTypes); workItemsNotMatching = GetWorkItemsNotMatching(workItem.Tags, childrenWorkItems); if (!string.IsNullOrEmpty(workItem.Tags) && workItemsNotMatching.Count == 0) continue; } - results.Add($"## {workItem.AssignedTo} - {workItem.Id} - {workItem.Title}"); - results.Add(string.Empty); + collection.Add($"## {workItem.AssignedTo} - {workItem.Id} - {workItem.Title}"); + collection.Add(string.Empty); foreach (WorkItem item in workItemsNotMatching) - results.Add($"- [ ] [{item}]({url}{item}) {nameof(workItem.Tags)} != {workItem.Tags}"); - results.Add(string.Empty); - lines.AddRange(results); + collection.Add($"- [ ] [{item}]({url}{item}) {nameof(workItem.Tags)} != {workItem.Tags}"); + collection.Add(string.Empty); + lines.AddRange(collection); violations.Add($"Tag:{workItem.Tags};"); foreach (WorkItem item in workItemsNotMatching) - violations.Add($"{item.Id}:{item.Tags};"); - collection.Add(WorkItem.Get(workItem, string.Join(" ", violations))); + violations.Add($"{item.Id}:{item.Tags};"); + results.Add(WorkItem.Get(workItem, string.Join(" ", violations))); } - return new(collection); + return new(results); } private static ReadOnlyCollection GetWorkItemsNotMatching(int? priority, ReadOnlyCollection workItems) @@ -390,91 +407,160 @@ public class FileRead : Shared.FileRead, IFileRead return new(results); } - private static ReadOnlyCollection FeatureCheckPriority126169(string url, List lines, ReadOnlyCollection workItemTypes, ReadOnlyDictionary workItemAndChildren, string workItemType) + private static ReadOnlyCollection FeatureCheckPriority126169(string url, List lines, ReadOnlyCollection workItemTypes, ReadOnlyCollection records, string workItemType) { - List collection = new(); + List results = new(); WorkItem workItem; - List results = new(); + List collection = new(); List violations = new(); ReadOnlyCollection childrenWorkItems; ReadOnlyCollection workItemsNotMatching; - foreach (KeyValuePair keyValuePair in workItemAndChildren) + foreach (Record record in records) { - workItem = keyValuePair.Value.WorkItem; + workItem = record.WorkItem; if (workItem.WorkItemType != workItemType) continue; - results.Clear(); + collection.Clear(); violations.Clear(); - if (keyValuePair.Value.Children.Count == 0) + if (record.Children.Count == 0) continue; - childrenWorkItems = FilterChildren(keyValuePair.Value, workItemTypes); + childrenWorkItems = FilterChildren(record, workItemTypes); workItemsNotMatching = GetWorkItemsNotMatching(workItem.Priority, childrenWorkItems); if (workItemsNotMatching.Count == 0) continue; - results.Add($"## {workItem.AssignedTo} - {workItem.Id} - {workItem.Title}"); - results.Add(string.Empty); - results.Add($"- [{workItem.Id}]({url}{workItem.Id})"); + collection.Add($"## {workItem.AssignedTo} - {workItem.Id} - {workItem.Title}"); + collection.Add(string.Empty); + collection.Add($"- [{workItem.Id}]({url}{workItem.Id})"); foreach (WorkItem item in workItemsNotMatching) - results.Add($"- [ ] [{item}]({url}{item}) {nameof(workItem.Priority)} != {workItem.Priority}"); - results.Add(string.Empty); - lines.AddRange(results); + collection.Add($"- [ ] [{item.Id}]({url}{item.Id}) {nameof(workItem.Priority)} != {workItem.Priority}"); + collection.Add(string.Empty); + lines.AddRange(collection); violations.Add($"Priority:{workItem.Priority};"); foreach (WorkItem item in workItemsNotMatching) - violations.Add($"{item.Id}:{item.Priority};"); - collection.Add(WorkItem.Get(workItem, string.Join(" ", violations))); + violations.Add($"{item.Id}:{item.Priority};"); + results.Add(WorkItem.Get(workItem, string.Join(" ", violations))); } - return new(collection); + return new(results); + } + + private static ReadOnlyCollection GetWorkItemsNotMatching(int state, ReadOnlyCollection workItems) + { + List results = new(); + int check; + List> collection = new(); + foreach (WorkItem workItem in workItems) + { + check = GetState(workItem); + if (check != state) + continue; + collection.Add(new(check, workItem)); + } + foreach (KeyValuePair keyValuePair in collection.OrderByDescending(l => l.Key)) + results.Add(keyValuePair.Value); + return new(results); + } + + private static int GetState(WorkItem workItem) => + workItem.State switch + { + "New" => 1, + "Active" => 2, + "Resolved" => 3, + "Closed" => 4, + "Removed" => 5, + _ => 8 + }; + + private static ReadOnlyCollection FeatureCheckState123066(string url, List lines, ReadOnlyCollection workItemTypes, ReadOnlyCollection records, string workItemType) + { + List results = new(); + int state; + WorkItem workItem; + List collection = new(); + List violations = new(); + ReadOnlyCollection childrenWorkItems; + ReadOnlyCollection workItemsNotMatching; + foreach (Record record in records) + { + workItem = record.WorkItem; + if (workItem.WorkItemType != workItemType) + continue; + collection.Clear(); + violations.Clear(); + if (record.Children.Count == 0) + continue; + state = GetState(workItem); + childrenWorkItems = FilterChildren(record, workItemTypes); + workItemsNotMatching = GetWorkItemsNotMatching(state, childrenWorkItems); + if (workItemsNotMatching.Count == 0) + continue; + collection.Add($"## {workItem.AssignedTo} - {workItem.Id} - {workItem.Title}"); + collection.Add(string.Empty); + collection.Add($"- [{workItem.Id}]({url}{workItem.Id})"); + foreach (WorkItem item in workItemsNotMatching) + collection.Add($"- [ ] [{item.Id}]({url}{item.Id}) {nameof(workItem.State)} != {workItem.State}"); + collection.Add(string.Empty); + lines.AddRange(collection); + violations.Add($"State:{workItem.State};"); + foreach (WorkItem item in workItemsNotMatching) + violations.Add($"{item.Id}:{item.State};"); + results.Add(WorkItem.Get(workItem, string.Join(" ", violations))); + } + return new(results); } private static void WriteFiles(FileConnectorConfiguration fileConnectorConfiguration, string url, ReadOnlyCollection workItemTypes, ReadOnlyCollection workItems) { - string json; List spaces = new(); List lines = new(); ReadOnlyCollection results; ReadOnlyDictionary collection = GetWorkItems(workItems); - ReadOnlyDictionary keyValuePairs = GetWorkItemAndChildren(collection); + ReadOnlyCollection records = GetRecords(collection); ReadOnlyCollection bugUserStoryWorkItemTypes = new(new string[] { "Bug", "User Story" }); ReadOnlyCollection bugUserStoryTaskWorkItemTypes = new(new string[] { "Bug", "User Story", "Task" }); if (!Directory.Exists(fileConnectorConfiguration.TargetFileLocation)) _ = Directory.CreateDirectory(fileConnectorConfiguration.TargetFileLocation); - if (keyValuePairs.Count == -1) - { - json = JsonSerializer.Serialize(keyValuePairs, new JsonSerializerOptions() { WriteIndented = true }); - File.WriteAllText(Path.Combine(fileConnectorConfiguration.TargetFileLocation, ".json"), json); - } + WriteFiles(fileConnectorConfiguration.TargetFileLocation, records, "with-parents"); foreach (string workItemType in workItemTypes) { lines.Clear(); lines.Add($"# {workItemType}"); lines.Add(string.Empty); - AppendLines(url, spaces, lines, keyValuePairs, workItemType); + AppendLines(url, spaces, lines, records, workItemType); results = new(Array.Empty()); - WriteFiles(fileConnectorConfiguration.TargetFileLocation, workItemType, new(lines), results); + WriteFiles(fileConnectorConfiguration.TargetFileLocation, new(lines), results, workItemType); } { lines.Clear(); string workItemType = "Feature"; lines.Add($"# {nameof(FeatureCheckIterationPath122508)}"); lines.Add(string.Empty); - results = FeatureCheckIterationPath122508(url, lines, bugUserStoryTaskWorkItemTypes, keyValuePairs, workItemType); - WriteFiles(fileConnectorConfiguration.TargetFileLocation, "check-122508", new(lines), results); + results = FeatureCheckIterationPath122508(url, lines, bugUserStoryTaskWorkItemTypes, records, workItemType); + WriteFiles(fileConnectorConfiguration.TargetFileLocation, new(lines), results, "check-122508"); } { lines.Clear(); string workItemType = "Feature"; lines.Add($"# {nameof(FeatureCheckTag122514)}"); lines.Add(string.Empty); - results = FeatureCheckTag122514(url, lines, bugUserStoryWorkItemTypes, keyValuePairs, workItemType); - WriteFiles(fileConnectorConfiguration.TargetFileLocation, "check-122514", new(lines), results); + results = FeatureCheckTag122514(url, lines, bugUserStoryWorkItemTypes, records, workItemType); + WriteFiles(fileConnectorConfiguration.TargetFileLocation, new(lines), results, "check-122514"); } { lines.Clear(); string workItemType = "Feature"; lines.Add($"# {nameof(FeatureCheckPriority126169)}"); lines.Add(string.Empty); - results = FeatureCheckPriority126169(url, lines, bugUserStoryWorkItemTypes, keyValuePairs, workItemType); - WriteFiles(fileConnectorConfiguration.TargetFileLocation, "check-126169", new(lines), results); + results = FeatureCheckPriority126169(url, lines, bugUserStoryWorkItemTypes, records, workItemType); + WriteFiles(fileConnectorConfiguration.TargetFileLocation, new(lines), results, "check-126169"); + } + { + lines.Clear(); + string workItemType = "Feature"; + lines.Add($"# {nameof(FeatureCheckState123066)}"); + lines.Add(string.Empty); + results = FeatureCheckState123066(url, lines, bugUserStoryTaskWorkItemTypes, records, workItemType); + WriteFiles(fileConnectorConfiguration.TargetFileLocation, new(lines), results, "check-123066"); } } diff --git a/Adaptation/FileHandlers/json/WorkItems/Record.cs b/Adaptation/FileHandlers/json/WorkItems/Record.cs index 7711541..21196ef 100644 --- a/Adaptation/FileHandlers/json/WorkItems/Record.cs +++ b/Adaptation/FileHandlers/json/WorkItems/Record.cs @@ -7,13 +7,15 @@ public class Record #nullable enable - public Record(WorkItem workItem, ReadOnlyDictionary children) + public Record(WorkItem workItem, WorkItem? parent, ReadOnlyCollection children) { WorkItem = workItem; + Parent = parent; Children = children; } public WorkItem WorkItem { get; set; } - public ReadOnlyDictionary Children { get; set; } + public WorkItem? Parent { get; set; } + public ReadOnlyCollection Children { get; set; } } \ No newline at end of file