file-folder-helper/ADO2024/PI4/Helper-2024-11-08.cs
2024-11-22 17:09:25 -07:00

364 lines
18 KiB
C#

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,
[property: JsonPropertyName("parameterTitle")] string? ParameterTitle,
[property: JsonPropertyName("state")] string? State,
[property: JsonPropertyName("workItemType")] string? WorkItemType);
private record Relation([property: JsonPropertyName("attributes")] Attribute Attributes,
[property: JsonPropertyName("id")] int Id,
[property: JsonPropertyName("rel")] string Rel);
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 Get(WorkItem workItem, Relation[] relations)
{
WorkItem result = 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,
relations,
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;
}
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, null, null, null);
return result;
}
private static Record Get(Record record, bool keepRelations)
{
Record result;
Record[]? childRecords;
Record[]? relatedRecords;
Record[]? successorRecords;
List<Record> relationRecords;
WorkItem? parentWorkItem = keepRelations ? record.Parent : WorkItem.GetWithOutRelations(record.Parent);
WorkItem? workItem = keepRelations ? record.WorkItem : WorkItem.GetWithOutRelations(record.WorkItem) ?? throw new Exception();
if (record.Children is null)
childRecords = null;
else
{
relationRecords = [];
foreach (Record r in record.Children)
relationRecords.Add(Get(r, keepRelations));
childRecords = relationRecords.ToArray();
}
if (record.Related is null)
relatedRecords = null;
else
{
relationRecords = [];
foreach (Record r in record.Related)
relationRecords.Add(Get(r, keepRelations));
relatedRecords = relationRecords.ToArray();
}
if (record.Successors is null)
successorRecords = null;
else
{
relationRecords = [];
foreach (Record r in record.Successors)
relationRecords.Add(Get(r, keepRelations));
successorRecords = relationRecords.ToArray();
}
result = new(workItem, parentWorkItem, childRecords, relatedRecords, successorRecords);
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;
}
internal static ReadOnlyCollection<Record> GetKeyValuePairs(ReadOnlyDictionary<int, WorkItem> keyValuePairs, WorkItem workItem, string relationName, List<bool> nests, bool keepRelations)
{
List<Record> results = [];
Record record;
nests.Add(true);
WorkItem? parentWorkItem;
WorkItem? relationWorkItem;
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)
{
if (relation.Attributes.Name != relationName)
continue;
if (workItem.Parent is not null && relation.Id == workItem.Parent.Value)
continue;
if (!keyValuePairs.TryGetValue(relation.Id, out relationWorkItem))
continue;
collection.Add(relationWorkItem);
}
collection = (from l in collection orderby l.State != "Closed", l.Id select l).ToList();
foreach (WorkItem w in collection)
{
if (nests.Count > 500)
break;
if (w.Parent is null)
parentWorkItem = null;
else
_ = keyValuePairs.TryGetValue(w.Parent.Value, out parentWorkItem);
childRecords = GetKeyValuePairs(keyValuePairs, w, "Child", nests, keepRelations); // Forward
relatedRecords = null; // GetKeyValuePairs(keyValuePairs, w, "Related", nests, keepRelations); // Related
successorRecords = null; // GetKeyValuePairs(keyValuePairs, w, "Successor", nests, keepRelations); // Forward
// predecessorRecords = GetKeyValuePairs(keyValuePairs, w, "Predecessor", nests, keepRelations); // Reverse
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 ReadOnlyCollection<WorkItem>? GetWorkItems(string fileName, string sourceDirectory)
{
WorkItem[]? results;
string? checkFile = null;
string? checkDirectory = sourceDirectory;
string? pathRoot = Path.GetPathRoot(sourceDirectory);
for (int i = 0; i < int.MaxValue; i++)
{
checkDirectory = Path.GetDirectoryName(checkDirectory);
if (string.IsNullOrEmpty(checkDirectory) || checkDirectory == pathRoot)
break;
checkFile = Path.Combine(checkDirectory, fileName);
if (File.Exists(checkFile))
break;
checkFile = null;
}
if (checkFile is null)
results = null;
else
{
string json = File.ReadAllText(checkFile);
results = JsonSerializer.Deserialize<WorkItem[]>(json);
}
return results is null ? null : new(results);
}
internal static void WriteMarkdown(ILogger<Worker> logger, List<string> args)
{
// string url = args[5];
bool keepRelations = true;
string fileName = args[2];
string sourceDirectory = Path.GetFullPath(args[0]);
string sourceDirectoryName = Path.GetFileName(sourceDirectory);
string idCheck = sourceDirectoryName.Split('-', StringSplitOptions.None)[0];
if (!int.TryParse(idCheck, out int id))
logger.LogInformation("Not valid directory!");
else
{
ReadOnlyCollection<WorkItem>? workItems = GetWorkItems(fileName, sourceDirectory);
if (workItems is null)
logger.LogInformation("No file found!");
else
{
Record? record;
ReadOnlyDictionary<int, Record> keyValuePairs = GetWorkItems(workItems, keepRelations);
logger.LogInformation("Found {keyValuePairs}", keyValuePairs.Count);
if (!keyValuePairs.TryGetValue(id, out record))
logger.LogInformation($"Id {id} not found!");
else
{
logger.LogInformation($"Id {id} found with title {record.WorkItem.Title}!");
}
}
}
}
}