Still Testing

This commit is contained in:
Mike Phares 2024-11-08 17:59:42 -07:00
parent 68c2a34096
commit dc9327274b
11 changed files with 439 additions and 20 deletions

24
.vscode/launch.json vendored
View File

@ -13,12 +13,24 @@
"args": [
"s",
"X",
"D:/Tmp/phares/Production__v2_57_0__HGCV1__pcl__Normal",
"D:/5-Other-Small/Kanban-mestsa003/ART-SPS/2024/PI4/Sprint-4.1/126996-User-Story",
"Day-Helper-2024-11-08",
"Bug|User Story",
"D:/5-Other-Small/Kanban-mestsa003/ART-SPS",
"444",
"555",
"666",
"777",
"888",
"999",
"s",
"X",
"D:/5-Other-Small/Kanban-mestsa003/ART-SPS/2024/PI4/Sprint-4.1/126448-User-Story/.files/Production__v2_57_0__HGCV1__pcl__Normal",
"Day-Helper-2024-10-30",
"*.txt",
"s",
"X",
"D:/Tmp/phares/Production__v2_57_0__CDE6__RsM__Normal",
"D:/5-Other-Small/Kanban-mestsa003/ART-SPS/2024/PI4/Sprint-4.1/126448-User-Story/.files/Production__v2_57_0__CDE6__RsM__Normal",
"Day-Helper-2024-10-31",
"*.RsM",
"s",
@ -61,10 +73,10 @@
"request": "attach"
},
{
"type": "node",
"request": "launch",
"name": "node Launch Current Opened File",
"program": "${file}"
"type": "node",
"request": "launch",
"name": "node Launch Current Opened File",
"program": "${file}"
}
]
}

8
.vscode/mklink.md vendored
View File

@ -18,11 +18,11 @@ mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.kanbn" "D:\5-Other-Small\Kanban
del "L:\DevOps\Mesa_FI\File-Folder-Helper\.extensions-vscode"
del "L:\DevOps\Mesa_FI\File-Folder-Helper\.extensions-vscode-oss"
del "L:\DevOps\Mesa_FI\File-Folder-Helper\.extensions-vscode-insiders"
mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.extensions-vscode" "C:\Users\phares\.vscode\extensions\ifx.type-script-helper-1.7.0"
mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.extensions-vscode-oss" "C:\Users\phares\.vscode-oss\extensions\ifx.type-script-helper-1.7.0"
mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.extensions-vscode-insiders" "C:\Users\phares\.vscode-insiders\extensions\ifx.type-script-helper-1.7.0"
mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.extensions-vscode" "C:\Users\phares\.vscode\extensions\ifx.type-script-helper-1.8.0"
mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.extensions-vscode-oss" "C:\Users\phares\.vscode-oss\extensions\ifx.type-script-helper-1.8.0"
mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.extensions-vscode-insiders" "C:\Users\phares\.vscode-insiders\extensions\ifx.type-script-helper-1.8.0"
```
```bash Thu Jul 18 2024 13:47:40 GMT-0700 (Mountain Standard Time)
mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.vscode\.UserSecrets" "L:\Git\Notes-User-Secrets\.UserSecrets\8da397d4-13ec-4576-9722-3c79cad25563"
mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.vscode\.UserSecrets" "C:\Users\phares\AppData\Roaming\Microsoft\UserSecrets\8da397d4-13ec-4576-9722-3c79cad25563"
```

5
.vscode/tasks.json vendored
View File

@ -132,6 +132,11 @@
"type": "shell",
"command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe",
"args": [
"s",
"X",
"T:/MESAFIBACKLOG/06_SourceCode/MESAFIBACKLOG",
"Day-Helper-2024-01-08",
"T:/MESAFIBACKLOG/06_SourceCode/MESAFIBACKLOG/Adaptation/FileHandlers/ADO",
"s",
"X",
"T:/MESAFIBACKLOG/06_SourceCode/MESAFIBACKLOG",

View File

@ -1,6 +1,6 @@
#if WorkItems
using File_Folder_Helper.Day.Q32024.ConvertExcelToJson;
using File_Folder_Helper.Day.Q32024.WorkItems;
using File_Folder_Helper.ADO2024.PI3.WorkItems;
using File_Folder_Helper.Models;
#endif
using Microsoft.Extensions.Logging;

View File

@ -78,7 +78,7 @@ internal static partial class Helper20240911
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(WorkItem[]))]
private partial class WorkItemSourceGenerationContext : JsonSerializerContext
private partial class WorkItemCollectionSourceGenerationContext : JsonSerializerContext
{
}
@ -355,7 +355,7 @@ internal static partial class Helper20240911
if (productionJSON.Result != developmentJSON.Result)
logger.LogWarning("productionJSON doesn't match developmentJSON");
}
WorkItem[]? workItems = JsonSerializer.Deserialize(developmentJSON.Result, WorkItemSourceGenerationContext.Default.WorkItemArray);
WorkItem[]? workItems = JsonSerializer.Deserialize(developmentJSON.Result, WorkItemCollectionSourceGenerationContext.Default.WorkItemArray);
if (workItems is null)
logger.LogWarning("workItems is null");
else
@ -400,7 +400,7 @@ internal static partial class Helper20240911
string htmlOld = !File.Exists(htmlFile) ? string.Empty : File.ReadAllText(htmlFile);
if (html != htmlOld)
File.WriteAllText(htmlFile, html);
string json = JsonSerializer.Serialize(workItems.ToArray(), WorkItemSourceGenerationContext.Default.WorkItemArray);
string json = JsonSerializer.Serialize(workItems.ToArray(), WorkItemCollectionSourceGenerationContext.Default.WorkItemArray);
string jsonFile = Path.Combine(destinationDirectory, $"{fileName}.json");
string jsonOld = !File.Exists(jsonFile) ? string.Empty : File.ReadAllText(jsonFile);
if (json != jsonOld)
@ -704,7 +704,6 @@ internal static partial class Helper20240911
ReadOnlyDictionary<int, Record> keyValuePairs = GetWorkItems(logger, args[2], args[3]);
WriteFileStructure(destinationDirectory, keyValuePairs);
ReadOnlyCollection<Record> records = new(keyValuePairs.Values.ToArray());
logger.LogInformation("Found {workItems} workItemAndChildren", records.Count);
ReadOnlyCollection<string> bugUserStoryWorkItemTypes = new(new string[] { "Bug", "User Story" });
ReadOnlyCollection<string> bugUserStoryTaskWorkItemTypes = new(new string[] { "Bug", "User Story", "Task" });
WriteFiles(destinationDirectory, records, "with-parents");

View File

@ -420,8 +420,12 @@ internal static partial class Helper20241030
internal static void GetComplete(ILogger<Worker> logger, List<string> args)
{
logger.LogError("GetComplete is not available in CDE {args[0]}", args[0]);
logger.LogError("GetComplete is not available in CDE {args[1]}", args[1]);
string searchPattern = args[2];
string sourceDirectory = Path.GetFullPath(args[0]);
string[] files = Directory.GetFiles(sourceDirectory, searchPattern, SearchOption.TopDirectoryOnly);
if (files.Length != 1)
logger.LogError("No files found in {sourceDirectory} with search pattern {searchPattern}", sourceDirectory, searchPattern);
logger.LogError("GetComplete is not available in HgCV {args[1]}", args[1]);
}
#endif

View File

@ -546,7 +546,11 @@ internal static partial class Helper20241031
internal static void GetComplete(ILogger<Worker> logger, List<string> args)
{
logger.LogError("GetComplete is not available in CDE {args[0]}", args[0]);
string searchPattern = args[2];
string sourceDirectory = Path.GetFullPath(args[0]);
string[] files = Directory.GetFiles(sourceDirectory, searchPattern, SearchOption.TopDirectoryOnly);
if (files.Length != 1)
logger.LogError("No files found in {sourceDirectory} with search pattern {searchPattern}", sourceDirectory, searchPattern);
logger.LogError("GetComplete is not available in CDE {args[1]}", args[1]);
}

View File

@ -0,0 +1,393 @@
using Microsoft.Extensions.Logging;
using System.Collections.ObjectModel;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace File_Folder_Helper.ADO2024.PI4;
internal static partial class Helper20241108
{
private record Attribute([property: JsonPropertyName("isLocked")] bool IsLocked,
[property: JsonPropertyName("name")] string Name);
private record Relation([property: JsonPropertyName("rel")] string Type,
[property: JsonPropertyName("url")] string URL,
[property: JsonPropertyName("attributes")] Attribute Attributes);
private record WorkItem(DateTime? ActivatedDate,
string AreaPath,
string? AssignedTo,
long? BusinessValue,
DateTime ChangedDate,
DateTime? ClosedDate,
int CommentCount,
DateTime CreatedDate,
string Description,
long? Effort,
int Id,
string IterationPath,
int? Parent,
int? Priority,
Relation[]? Relations,
string? Requester,
DateTime? ResolvedDate,
int Revision,
long? RiskReductionMinusOpportunityEnablement,
DateTime? StartDate,
string State,
string Tags,
DateTime? TargetDate,
long? TimeCriticality,
string Title,
string? Violation,
long? WeightedShortestJobFirst,
string WorkItemType)
{
public override string ToString() => $"{Id} - {WorkItemType} - {Title}";
public static WorkItem? GetWithOutRelations(WorkItem? workItem)
{
WorkItem? result = workItem is null ? null : new(workItem.ActivatedDate,
workItem.AreaPath,
workItem.AssignedTo,
workItem.BusinessValue,
workItem.ChangedDate,
workItem.ClosedDate,
workItem.CommentCount,
workItem.CreatedDate,
workItem.Description,
workItem.Effort,
workItem.Id,
workItem.IterationPath,
workItem.Parent,
workItem.Priority,
Array.Empty<Relation>(),
workItem.Requester,
workItem.ResolvedDate,
workItem.Revision,
workItem.RiskReductionMinusOpportunityEnablement,
workItem.StartDate,
workItem.State,
workItem.Tags,
workItem.TargetDate,
workItem.TimeCriticality,
workItem.Title,
workItem.Violation,
workItem.WeightedShortestJobFirst,
workItem.WorkItemType);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(WorkItem))]
private partial class WorkItemSourceGenerationContext : JsonSerializerContext
{
}
private record Record(WorkItem WorkItem, WorkItem? Parent, Record[] Children, Record[] Related, Record[] Successors)
{
internal static Record GetWithoutNesting(Record record, string? violation)
{
Record result;
WorkItem workItem = new(record.WorkItem.ActivatedDate,
record.WorkItem.AreaPath,
record.WorkItem.AssignedTo,
record.WorkItem.BusinessValue,
record.WorkItem.ChangedDate,
record.WorkItem.ClosedDate,
record.WorkItem.CommentCount,
record.WorkItem.CreatedDate,
record.WorkItem.Description,
record.WorkItem.Effort,
record.WorkItem.Id,
record.WorkItem.IterationPath,
record.WorkItem.Parent,
record.WorkItem.Priority,
record.WorkItem.Relations,
record.WorkItem.Requester,
record.WorkItem.ResolvedDate,
record.WorkItem.Revision,
record.WorkItem.RiskReductionMinusOpportunityEnablement,
record.WorkItem.StartDate,
record.WorkItem.State,
record.WorkItem.Tags,
record.WorkItem.TargetDate,
record.WorkItem.TimeCriticality,
record.WorkItem.Title,
record.WorkItem.Violation is null ? violation : record.WorkItem.Violation,
record.WorkItem.WeightedShortestJobFirst,
record.WorkItem.WorkItemType);
result = new(workItem, record.Parent, [], [], []);
return result;
}
private static Record Get(Record record, bool keepRelations)
{
Record result;
WorkItem? parentWorkItem = keepRelations ? record.Parent : WorkItem.GetWithOutRelations(record.Parent);
WorkItem? workItem = keepRelations ? record.WorkItem : WorkItem.GetWithOutRelations(record.WorkItem) ?? throw new Exception();
List<Record> childRecords = [];
List<Record> relatedRecords = [];
List<Record> successorRecords = [];
foreach (Record r in record.Children)
childRecords.Add(Get(r, keepRelations));
foreach (Record r in record.Related)
relatedRecords.Add(Get(r, keepRelations));
foreach (Record r in record.Successors)
successorRecords.Add(Get(r, keepRelations));
result = new(workItem, parentWorkItem, childRecords.ToArray(), relatedRecords.ToArray(), successorRecords.ToArray());
return result;
}
internal static Record Get(WorkItem workItem, WorkItem? parent, ReadOnlyCollection<Record> children, ReadOnlyCollection<Record> related, ReadOnlyCollection<Record> successors, bool keepRelations)
{
Record result;
Record record = new(workItem, parent, children.ToArray(), related.ToArray(), successors.ToArray());
result = Get(record, keepRelations);
return result;
}
private static int? GetIdFromUrl(string relationName, Relation relation)
{
int? result;
string[] segments = relation?.Attributes is null || relation.Attributes.Name != relationName ? [] : relation.URL.Split('/');
if (segments.Length < 2)
result = null;
else
{
if (!int.TryParse(segments[^1], out int id))
result = null;
else
result = id;
}
return result;
}
internal static ReadOnlyCollection<Record> GetKeyValuePairs(ReadOnlyDictionary<int, WorkItem> keyValuePairs, WorkItem workItem, string relationName, List<bool> nests, bool keepRelations)
{
List<Record> results = [];
int? childId;
Record record;
nests.Add(true);
WorkItem? childWorkItem;
WorkItem? parentWorkItem;
List<WorkItem> collection = [];
ReadOnlyCollection<Record> childRecords;
ReadOnlyCollection<Record> relatedRecords;
ReadOnlyCollection<Record> successorRecords;
if (workItem.Relations is not null && workItem.Relations.Length > 0)
{
collection.Clear();
foreach (Relation relation in workItem.Relations)
{
childId = GetIdFromUrl(relationName, relation);
if (childId is not null && workItem.Parent is not null && relation?.URL is not null && relation.URL.Contains(workItem.Parent.Value.ToString()))
continue;
if (childId is null || !keyValuePairs.TryGetValue(childId.Value, out childWorkItem))
continue;
collection.Add(childWorkItem);
}
collection = (from l in collection orderby l.State != "Closed", l.Id select l).ToList();
foreach (WorkItem w in collection)
{
if (nests.Count > 99)
break;
if (w.Parent is null)
parentWorkItem = null;
else
_ = keyValuePairs.TryGetValue(w.Parent.Value, out parentWorkItem);
childRecords = GetKeyValuePairs(keyValuePairs, w, "Child", nests, keepRelations); // Forward
// records = GetKeyValuePairs(keyValuePairs, w, "Predecessor", nests); // Reverse
// successorRecords = GetKeyValuePairs(keyValuePairs, w, "Successor", nests); // Forward
// if (successorRecords.Count > 0)
// {
// if (successorRecords.Count > 0)
// { }
// }
successorRecords = new([]);
relatedRecords = GetKeyValuePairs(keyValuePairs, w, "Related", nests, keepRelations); // Related
record = Get(w, parentWorkItem, childRecords, relatedRecords, successorRecords, keepRelations);
results.Add(record);
}
}
return new(results);
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(Record[]))]
private partial class RecordCollectionBCommonSourceGenerationContext : JsonSerializerContext
{
}
private static ReadOnlyDictionary<int, Record> GetKeyValuePairs(ReadOnlyDictionary<int, WorkItem> keyValuePairs, bool keepRelations)
{
Dictionary<int, Record> results = [];
Record record;
List<bool> nests = [];
WorkItem? parentWorkItem;
ReadOnlyCollection<Record> childRecords;
ReadOnlyCollection<Record> relatedRecords;
ReadOnlyCollection<Record> successorRecords;
foreach (KeyValuePair<int, WorkItem> keyValuePair in keyValuePairs)
{
nests.Clear();
if (keyValuePair.Value.Parent is null)
parentWorkItem = null;
else
_ = keyValuePairs.TryGetValue(keyValuePair.Value.Parent.Value, out parentWorkItem);
try
{
childRecords = Record.GetKeyValuePairs(keyValuePairs, keyValuePair.Value, "Child", nests, keepRelations); // Forward
// records = Record.GetKeyValuePairs(keyValuePairs, keyValuePair.Value, "Predecessor", nests, keepRelations); // Reverse
relatedRecords = Record.GetKeyValuePairs(keyValuePairs, keyValuePair.Value, "Related", nests, keepRelations); // Related
successorRecords = Record.GetKeyValuePairs(keyValuePairs, keyValuePair.Value, "Successor", nests, keepRelations); // Forward
record = Record.Get(keyValuePair.Value, parentWorkItem, childRecords, relatedRecords, successorRecords, keepRelations);
}
catch (Exception)
{
record = new(keyValuePair.Value, parentWorkItem, [], [], []);
}
results.Add(keyValuePair.Key, record);
}
return new(results);
}
private static ReadOnlyDictionary<int, Record> GetWorkItems(ReadOnlyCollection<WorkItem> workItems, bool keepRelations)
{
ReadOnlyDictionary<int, Record> results;
Dictionary<int, WorkItem> keyValuePairs = [];
foreach (WorkItem workItem in workItems)
keyValuePairs.Add(workItem.Id, workItem);
results = GetKeyValuePairs(new(keyValuePairs), keepRelations);
return results;
}
private static ReadOnlyDictionary<int, string> GetCurrentDirectories(string destinationDirectory, ReadOnlyCollection<string> bugUserStoryWorkItemTypes)
{
Dictionary<int, string> results = [];
int id;
string idCheck;
string? fileName;
string[] directories;
string[] split = ["-"];
foreach (string w in bugUserStoryWorkItemTypes)
{
directories = Directory.GetDirectories(destinationDirectory, $"*-{w.Replace(" ", "-")}", SearchOption.AllDirectories);
foreach (string directory in directories)
{
fileName = Path.GetFileName(directory);
if (string.IsNullOrEmpty(fileName))
continue;
idCheck = fileName.Split(split, StringSplitOptions.None)[0];
if (!int.TryParse(idCheck, out id))
continue;
if (!results.ContainsKey(id))
results.Add(id, directory);
else
MoveToDuplicate(destinationDirectory, directory);
}
}
return new(results);
}
private static void MoveToDuplicate(string destinationDirectory, string directory)
{
if (string.IsNullOrEmpty(destinationDirectory))
throw new ArgumentException($"'{nameof(destinationDirectory)}' cannot be null or empty.", nameof(destinationDirectory));
if (string.IsNullOrEmpty(directory))
throw new ArgumentException($"'{nameof(directory)}' cannot be null or empty.", nameof(directory));
}
private static ReadOnlyCollection<WorkItem> GetWorkItems(string sourceDirectory, ReadOnlyCollection<string> bugUserStoryWorkItemTypes)
{
List<WorkItem> results = [];
string json;
string checkFile;
WorkItem? workItem;
string directoryName;
string? checkDirectory = null;
foreach (string w in bugUserStoryWorkItemTypes)
{
directoryName = Path.GetFileName(sourceDirectory);
if (!directoryName.EndsWith(w.Replace(" ", "-")))
continue;
checkDirectory = Path.Combine(sourceDirectory, directoryName.Split('-')[0]);
if (!Directory.Exists(checkDirectory))
{
checkDirectory = null;
continue;
}
break;
}
if (!string.IsNullOrEmpty(checkDirectory))
{
checkFile = Path.Combine(checkDirectory, ".json");
if (File.Exists(checkFile))
{
json = File.ReadAllText(checkFile);
workItem = JsonSerializer.Deserialize(json, WorkItemSourceGenerationContext.Default.WorkItem);
if (workItem is not null)
results.Add(workItem);
}
}
return new(results);
}
private static ReadOnlyCollection<WorkItem> GetWorkItems(ReadOnlyDictionary<int, string> collection)
{
List<WorkItem> results = [];
string json;
string checkFile;
string? directory;
WorkItem? workItem;
string? checkDirectory;
foreach (KeyValuePair<int, string> keyValuePair in collection)
{
if (!collection.TryGetValue(keyValuePair.Key, out directory) || string.IsNullOrEmpty(directory))
continue;
checkDirectory = Path.Combine(directory, $"{keyValuePair.Key}");
if (!Directory.Exists(checkDirectory))
continue;
checkFile = Path.Combine(checkDirectory, ".json");
if (!File.Exists(checkFile))
continue;
json = File.ReadAllText(checkFile);
workItem = JsonSerializer.Deserialize(json, WorkItemSourceGenerationContext.Default.WorkItem);
if (workItem is null)
continue;
results.Add(workItem);
}
return new(results);
}
private static ReadOnlyCollection<WorkItem> GetWorkItems(string sourceDirectory, ReadOnlyCollection<string> bugUserStoryWorkItemTypes, ReadOnlyDictionary<int, string> collection)
{
ReadOnlyCollection<WorkItem> results;
if (collection.Count > 0)
results = GetWorkItems(collection);
else
results = GetWorkItems(sourceDirectory, bugUserStoryWorkItemTypes);
return results;
}
internal static void WriteMarkdown(ILogger<Worker> logger, List<string> args)
{
// string url = args[5];
bool keepRelations = true;
string sourceDirectory = Path.GetFullPath(args[0]);
ReadOnlyCollection<string> bugUserStoryWorkItemTypes = args[2].Split('|').ToArray().AsReadOnly();
// ReadOnlyCollection<string> bugUserStoryTaskWorkItemTypes = new(new string[] { "Bug", "User Story", "Task" });
ReadOnlyDictionary<int, string> collection = GetCurrentDirectories(sourceDirectory, bugUserStoryWorkItemTypes);
ReadOnlyCollection<WorkItem> workItems = GetWorkItems(sourceDirectory, bugUserStoryWorkItemTypes, collection);
ReadOnlyDictionary<int, Record> keyValuePairs = GetWorkItems(workItems, keepRelations);
logger.LogInformation("Found {keyValuePairs}", keyValuePairs.Count);
}
}

View File

@ -115,6 +115,8 @@ internal static class HelperDay
ADO2024.PI3.Helper20241030.GetComplete(logger, args);
else if (args[1] == "Day-Helper-2024-10-31")
ADO2024.PI3.Helper20241031.GetComplete(logger, args);
else if (args[1] == "Day-Helper-2024-11-08")
ADO2024.PI4.Helper20241108.WriteMarkdown(logger, args);
else
throw new Exception(appSettings.Company);
}

View File

@ -1,5 +1,5 @@
#if WorkItems
using File_Folder_Helper.Day.Q32024.WorkItems;
using File_Folder_Helper.ADO2024.PI3.WorkItems;
using System.Text.Json.Serialization;
namespace File_Folder_Helper.Models;

View File

@ -1,5 +1,5 @@
#if WorkItems
using File_Folder_Helper.Day.Q32024.WorkItems;
using File_Folder_Helper.ADO2024.PI3.WorkItems;
using System.Text.Json.Serialization;
namespace File_Folder_Helper.Models;