From 3d114918e4c25089c07e20d6ddc16e18a31501e4 Mon Sep 17 00:00:00 2001 From: Mike Phares Date: Fri, 4 Oct 2024 18:10:30 -0700 Subject: [PATCH] FeatureCheckTag --- .vscode/launch.json | 17 +-- Day/Q32024/Helper-2024-09-11.cs | 243 +++++++++++++++++++++++++++----- 2 files changed, 216 insertions(+), 44 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index c54e5d4..16716f4 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -13,16 +13,13 @@ "args": [ "s", "X", - "D:/EC_Shares/EC_SPC_Si/SPC/Projects/Active", - "Day-Helper-2024-10-02", - "14 point thickness.BAK_241001115400", - "DE_TS_", - "DE_TS_EQU", - "L:/DevOps/Mesa_FI/File-Folder-Helper/.vscode/helper/iqs", - "666", - "777", - "888", - "999" + "D:/5-Other-Small/Kanban-messa010ec/Kanban/Work-Items", + "Day-Helper-2024-09-11", + "*.json", + ".kanbn", + "Epic|Feature|User Story", + "L:/DevOps/Mesa_FI/File-Folder-Helper/.vscode/helper/tfs", + "https://tfs.intra.infineon.com/tfs/FactoryIntegration/ART%20SPS/_workitems/edit/" ], "cwd": "${workspaceFolder}", "console": "integratedTerminal", diff --git a/Day/Q32024/Helper-2024-09-11.cs b/Day/Q32024/Helper-2024-09-11.cs index 1b2fd6a..4bb891f 100644 --- a/Day/Q32024/Helper-2024-09-11.cs +++ b/Day/Q32024/Helper-2024-09-11.cs @@ -158,8 +158,9 @@ internal static partial class Helper20240911 spaces.RemoveAt(0); } - private static void AppendLines(List spaces, List lines, ReadOnlyDictionary workItemAndChildren, string workItemType) + private static void AppendLines(string url, List spaces, List lines, ReadOnlyDictionary workItemAndChildren, string workItemType) { + List results = []; WorkItem workItem; string? maxIterationPath; List distinct = []; @@ -170,47 +171,203 @@ internal static partial class Helper20240911 // continue; if (workItem.WorkItemType != workItemType) continue; - lines.Add($"## {workItem.AssignedTo} - {workItem.Id} - {workItem.Title}"); - lines.Add(string.Empty); - lines.Add($"- [{workItem.Id}](https://tfs.intra.infineon.com/tfs/FactoryIntegration/ART%20SPS/_workitems/edit/{workItem.Id})"); + 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) - lines.Add(string.Empty); + results.Add(string.Empty); else { - AppendLines(spaces, lines, keyValuePair.Value, condensed: true, sprintOnly: false); - lines.Add(string.Empty); + AppendLines(spaces, results, keyValuePair.Value, condensed: true, sprintOnly: false); + results.Add(string.Empty); distinct.Clear(); AppendLines(spaces, distinct, keyValuePair.Value, condensed: false, sprintOnly: true); if (distinct.Count > 1) { - lines.Add($"## Distinct Iteration Path(s) - {workItem.WorkItemType} - {workItem.AssignedTo} - {workItem.Id} - {workItem.Title} - {workItem.IterationPath}"); - lines.Add(string.Empty); - lines.Add($"- [{workItem.Id}](https://tfs.intra.infineon.com/tfs/FactoryIntegration/ART%20SPS/_workitems/edit/{workItem.Id})"); + results.Add($"## Distinct Iteration Path(s) - {workItem.WorkItemType} - {workItem.AssignedTo} - {workItem.Id} - {workItem.Title} - {workItem.IterationPath}"); + results.Add(string.Empty); + results.Add($"- [{workItem.Id}]({url}{workItem.Id})"); distinct.Sort(); distinct = (from l in distinct select l.Trim()).Distinct().ToList(); - lines.AddRange(distinct); - lines.Add(string.Empty); + results.AddRange(distinct); + results.Add(string.Empty); maxIterationPath = distinct.Max(); if (!string.IsNullOrEmpty(maxIterationPath) && maxIterationPath.Contains("] ") && maxIterationPath.Split(']')[1].Trim() != workItem.IterationPath) { - lines.Add($"### Sync to Distinct Max Iteration Path => {maxIterationPath} - {workItem.Id} - {workItem.Title}"); - lines.Add(string.Empty); + results.Add($"### Sync to Distinct Max Iteration Path => {maxIterationPath} - {workItem.Id} - {workItem.Title}"); + results.Add(string.Empty); } } - lines.Add($"## Extended - {workItem.Id} - {workItem.Title}"); - lines.Add(string.Empty); - AppendLines(spaces, lines, keyValuePair.Value, condensed: false, sprintOnly: false); - lines.Add(string.Empty); + results.Add($"## Extended - {workItem.Id} - {workItem.Title}"); + results.Add(string.Empty); + AppendLines(spaces, results, keyValuePair.Value, condensed: false, sprintOnly: false); + results.Add(string.Empty); } + lines.AddRange(results); + results.Clear(); + } + } + + private static void WriteFiles(string destinationDirectory, string fileName, ReadOnlyCollection lines) + { + string text = string.Join(Environment.NewLine, lines); + string markdownFile = Path.Combine(destinationDirectory, $"{fileName}.md"); + string textOld = !File.Exists(markdownFile) ? string.Empty : File.ReadAllText(markdownFile); + if (text != textOld) + File.WriteAllText(markdownFile, text); + string html = CommonMark.CommonMarkConverter.Convert(text); + string htmlFile = Path.Combine(destinationDirectory, $"{fileName}.html"); + string htmlOld = !File.Exists(htmlFile) ? string.Empty : File.ReadAllText(htmlFile); + if (html != htmlOld) + File.WriteAllText(htmlFile, html); + } + + private static ReadOnlyCollection FilterChildren(Record record, ReadOnlyCollection workItemTypes) + { + List results = []; + WorkItem workItem; + foreach (KeyValuePair keyValuePair in record.Children) + { + workItem = keyValuePair.Value.WorkItem; + if (!workItemTypes.Contains(workItem.WorkItemType)) + continue; + results.Add(workItem); + } + return new(results); + } + + private static string? GetMaxIterationPath(ReadOnlyCollection workItems) + { + string? result; + List results = []; + foreach (WorkItem workItem in workItems) + { + if (results.Contains(workItem.IterationPath)) + continue; + results.Add(workItem.IterationPath); + } + result = results.Count == 0 ? null : results.Max(); + return result; + } + + private static void FeatureCheckIterationPath(string url, List lines, ReadOnlyCollection workItemTypes, ReadOnlyDictionary workItemAndChildren, string workItemType) + { + WorkItem workItem; + string? maxIterationPath; + List results = []; + ReadOnlyCollection workItems; + foreach (KeyValuePair keyValuePair in workItemAndChildren) + { + workItem = keyValuePair.Value.WorkItem; + if (workItem.WorkItemType != workItemType) + continue; + results.Clear(); + if (keyValuePair.Value.Children.Count == 0) + continue; + workItems = FilterChildren(keyValuePair.Value, workItemTypes); + maxIterationPath = GetMaxIterationPath(workItems); + 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})"); + results.Add($"- [ ] {workItem.Id} => {workItem.IterationPath} != {maxIterationPath}"); + results.Add(string.Empty); + lines.AddRange(results); + } + } + + private static ReadOnlyCollection GetIdsNotMatching(string tags, ReadOnlyCollection workItems) + { + List results = []; + string[] segments; + string[] parentTags = tags.Split(';'); + foreach (WorkItem workItem in workItems) + { + segments = tags.Split(';'); + if (segments.Length > 0 && parentTags.Any(l => segments.Contains(l))) + continue; + results.Add(workItem.Id); + } + return new(results); + } + + private static void FeatureCheckTag(string url, List lines, ReadOnlyCollection workItemTypes, ReadOnlyDictionary workItemAndChildren, string workItemType) + { + WorkItem workItem; + List results = []; + ReadOnlyCollection idsNotMatching; + ReadOnlyCollection workItems; + foreach (KeyValuePair keyValuePair in workItemAndChildren) + { + workItem = keyValuePair.Value.WorkItem; + if (workItem.WorkItemType != workItemType) + continue; + results.Clear(); + if (keyValuePair.Value.Children.Count == 0) + continue; + if (string.IsNullOrEmpty(workItem.Tags)) + idsNotMatching = new([workItem.Id]); + else + { + workItems = FilterChildren(keyValuePair.Value, workItemTypes); + idsNotMatching = GetIdsNotMatching(workItem.Tags, workItems); + if (!string.IsNullOrEmpty(workItem.Tags) && idsNotMatching.Count == 0) + continue; + } + results.Add($"## {workItem.AssignedTo} - {workItem.Id} - {workItem.Title}"); + results.Add(string.Empty); + results.Add($"- [{workItem.Id}]({url}{workItem.Id})"); + foreach (int id in idsNotMatching) + results.Add($"- [ ] {id} {nameof(workItem.Tags)} != {workItem.Tags}"); + results.Add(string.Empty); + lines.AddRange(results); + } + } + + private static ReadOnlyCollection GetIdsNotMatching(int? priority, ReadOnlyCollection workItems) + { + List results = []; + foreach (WorkItem workItem in workItems) + { + if (workItem.Priority == priority) + continue; + results.Add(workItem.Id); + } + return new(results); + } + + private static void FeatureCheckPriority(string url, List lines, ReadOnlyCollection workItemTypes, ReadOnlyDictionary workItemAndChildren, string workItemType) + { + WorkItem workItem; + List results = []; + ReadOnlyCollection idsNotMatching; + ReadOnlyCollection workItems; + foreach (KeyValuePair keyValuePair in workItemAndChildren) + { + workItem = keyValuePair.Value.WorkItem; + if (workItem.WorkItemType != workItemType) + continue; + results.Clear(); + if (keyValuePair.Value.Children.Count == 0) + continue; + workItems = FilterChildren(keyValuePair.Value, workItemTypes); + idsNotMatching = GetIdsNotMatching(workItem.Priority, workItems); + if (idsNotMatching.Count == 0) + continue; + results.Add($"## {workItem.AssignedTo} - {workItem.Id} - {workItem.Title}"); + results.Add(string.Empty); + results.Add($"- [{workItem.Id}]({url}{workItem.Id})"); + foreach (int id in idsNotMatching) + results.Add($"- [ ] {id} {nameof(workItem.Priority)} != {workItem.Priority}"); + results.Add(string.Empty); + lines.AddRange(results); } } internal static void WriteMarkdown(ILogger logger, List args) { - string old; - string html; - string text; - string checkFile; + string url = args[6]; List spaces = []; List lines = []; string searchPattern = args[2]; @@ -220,6 +377,8 @@ internal static partial class Helper20240911 string destinationDirectory = Path.GetFullPath(args[5]); if (!Directory.Exists(destinationDirectory)) _ = Directory.CreateDirectory(destinationDirectory); + ReadOnlyCollection userStoryWorkItemTypes = new(["User Story"]); + ReadOnlyCollection userStoryTaskWorkItemTypes = new(["User Story", "Task"]); string[] files = Directory.GetFiles(sourceDirectory, searchPattern, SearchOption.AllDirectories); logger.LogInformation("With search pattern '{SearchPattern}' found {files} file(s)", searchPattern, files.Length); ReadOnlyDictionary workItems = GetWorkItems(filterDirectory, files); @@ -234,18 +393,34 @@ internal static partial class Helper20240911 foreach (string workItemType in workItemTypes) { lines.Clear(); - lines.AddRange(["# WorkItems", string.Empty]); - AppendLines(spaces, lines, workItemAndChildren, workItemType); - checkFile = Path.Combine(destinationDirectory, $"{workItemType}.md"); - text = string.Join(Environment.NewLine, lines); - old = !File.Exists(checkFile) ? string.Empty : File.ReadAllText(checkFile); - if (text != old) - File.WriteAllText(checkFile, text); - checkFile = Path.Combine(destinationDirectory, $"{workItemType}.html"); - html = CommonMark.CommonMarkConverter.Convert(text); - old = !File.Exists(checkFile) ? string.Empty : File.ReadAllText(checkFile); - if (html != old) - File.WriteAllText(checkFile, html); + lines.Add("# WorkItems"); + lines.Add(string.Empty); + AppendLines(url, spaces, lines, workItemAndChildren, workItemType); + WriteFiles(destinationDirectory, workItemType, new(lines)); + } + { + lines.Clear(); + string workItemType = "Feature"; + lines.Add($"# {nameof(FeatureCheckIterationPath)}"); + lines.Add(string.Empty); + FeatureCheckIterationPath(url, lines, userStoryTaskWorkItemTypes, workItemAndChildren, workItemType); + WriteFiles(destinationDirectory, $"{nameof(FeatureCheckIterationPath)}", new(lines)); + } + { + lines.Clear(); + string workItemType = "Feature"; + lines.Add($"# {nameof(FeatureCheckTag)}"); + lines.Add(string.Empty); + FeatureCheckTag(url, lines, userStoryWorkItemTypes, workItemAndChildren, workItemType); + WriteFiles(destinationDirectory, $"{nameof(FeatureCheckTag)}", new(lines)); + } + { + lines.Clear(); + string workItemType = "Feature"; + lines.Add($"# {nameof(FeatureCheckPriority)}"); + lines.Add(string.Empty); + FeatureCheckPriority(url, lines, userStoryWorkItemTypes, workItemAndChildren, workItemType); + WriteFiles(destinationDirectory, $"{nameof(FeatureCheckPriority)}", new(lines)); } }