SetSyncTag

This commit is contained in:
Mike Phares 2023-10-07 13:57:40 -07:00
parent b943a882cb
commit 7d8f409ff3
4 changed files with 221 additions and 35 deletions

View File

@ -54,18 +54,18 @@ public class ProcessData : IProcessData
fiBacklogMesaCollection = JsonSerializer.Deserialize<FIBacklogMesa[]>(json, new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
if (fiBacklogMesaCollection is null || !fiBacklogMesaCollection.Any())
throw new NullReferenceException();
foreach (FIBacklogMesa fIBacklogMesa in fiBacklogMesaCollection)
foreach (FIBacklogMesa fiBacklogMesa in fiBacklogMesaCollection)
{
if (string.IsNullOrEmpty(fIBacklogMesa.Req))
if (string.IsNullOrEmpty(fiBacklogMesa.Req))
continue;
if (string.IsNullOrEmpty(fIBacklogMesa.Submitted))
if (string.IsNullOrEmpty(fiBacklogMesa.Submitted))
continue;
if (string.IsNullOrEmpty(fIBacklogMesa.Requestor))
if (string.IsNullOrEmpty(fiBacklogMesa.Requestor))
continue;
key = $"{fIBacklogMesa.Req} - ";
key = $"{fiBacklogMesa.Req} - ";
if (results.ContainsKey(key))
continue;
results.Add(key, fIBacklogMesa);
results.Add(key, fiBacklogMesa);
}
return results;
}
@ -112,18 +112,139 @@ public class ProcessData : IProcessData
return results;
}
private static Value[] GetExtra(IReadOnlyList<Value> workItems, Dictionary<string, FIBacklogMesa> keyToFIBacklogMesa)
private static ReadOnlyCollection<ValueWithReq> GetValueWithReqCollection(IReadOnlyList<Value> workItems)
{
List<Value> results = new();
List<ValueWithReq> results = new();
string[] segments;
foreach (Value value in workItems)
{
if (!value.Fields.SystemTitle.Contains(" - "))
segments = value.Fields.SystemTitle.Split('-');
if (segments.Length < 2)
continue;
if (keyToFIBacklogMesa.Remove(value.Fields.SystemTitle))
if (!int.TryParse(segments[0], out int req) || req == 0)
continue;
results.Add(value);
results.Add(new(value, req));
}
return new(results);
}
private static ReadOnlyCollection<ValueWithReq> RemoveFrom(Dictionary<string, FIBacklogMesa> keyToFIBacklogMesa, ReadOnlyCollection<ValueWithReq> valueWithReqCollection)
{
List<ValueWithReq> results = new();
foreach (ValueWithReq valueWithReq in valueWithReqCollection)
{
if (keyToFIBacklogMesa.Remove($"{valueWithReq.Req} - "))
continue;
results.Add(valueWithReq);
}
return new(results);
}
private static void Update(WorkItemTrackingHttpClient workItemTrackingHttpClient, string sync, ValueWithReq valueWithReq)
{
JsonPatchDocument result = new();
AddPatch(result, "/fields/System.Tags", sync);
Task<WorkItem> workItem = workItemTrackingHttpClient.UpdateWorkItemAsync(result, valueWithReq.Value.Id);
workItem.Wait();
}
private static DateTime? GetCommitDate(FIBacklogMesa fiBacklogMesa)
{
DateTime? result;
if (!DateTime.TryParseExact(fiBacklogMesa.CommitDate.Split(' ').First(), "MM/dd/yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime dateTime) && dateTime != DateTime.MinValue)
result = null;
else
result = dateTime.AddHours(12).ToUniversalTime();
return result;
}
private static string? GetMappedState(FIBacklogMesa fiBacklogMesa) =>
fiBacklogMesa.Status == "CMP" ? "Closed" : fiBacklogMesa.Status == "UAT" ? "Resolved" : fiBacklogMesa.Status == "In process" ? "Active" : null;
private static void SetSyncTag(WorkItemTrackingHttpClient workItemTrackingHttpClient, ReadOnlyDictionary<string, string> requestorNameToUser, Dictionary<string, FIBacklogMesa> keyToFIBacklogMesa, ReadOnlyCollection<ValueWithReq> valueWithReqCollection)
{
string key;
bool isBugFix;
string? state;
List<string> tags;
TimeSpan timeSpan;
DateTime? dateTime;
List<string> compareTags;
const string sync = "Sync";
FIBacklogMesa? fiBacklogMesa;
foreach (ValueWithReq valueWithReq in valueWithReqCollection)
{
key = $"{valueWithReq.Req} - ";
compareTags = GetTags(valueWithReq.Value.Fields);
if (compareTags.Contains(sync))
continue;
if (!keyToFIBacklogMesa.TryGetValue(key, out fiBacklogMesa))
continue;
tags = GetTags(fiBacklogMesa);
isBugFix = fiBacklogMesa.Priority == "0 - BugFix";
_ = requestorNameToUser.TryGetValue(fiBacklogMesa.Requestor, out string? requestorUser);
if (!string.IsNullOrEmpty(requestorUser) && (valueWithReq.Value.Fields.SystemAssignedTo is null || !valueWithReq.Value.Fields.SystemAssignedTo.UniqueName.Equals(requestorUser, StringComparison.CurrentCultureIgnoreCase)))
{
Update(workItemTrackingHttpClient, sync, valueWithReq);
continue;
}
if (valueWithReq.Value.Fields.SystemTitle != $"{valueWithReq.Req} - {fiBacklogMesa.Subject}")
{
Update(workItemTrackingHttpClient, sync, valueWithReq);
continue;
}
foreach (string tag in tags)
{
if (compareTags.Contains(tag))
continue;
_ = tags.Remove(tag);
break;
}
if (tags.Count != compareTags.Count)
{
Update(workItemTrackingHttpClient, sync, valueWithReq);
continue;
}
if ((isBugFix && valueWithReq.Value.Fields.SystemWorkItemType != "Bug") || (!isBugFix && valueWithReq.Value.Fields.SystemWorkItemType == "Bug"))
{
Update(workItemTrackingHttpClient, sync, valueWithReq);
continue;
}
if (!isBugFix)
{
if (!int.TryParse(fiBacklogMesa.Priority.Substring(0, 1), out int priority))
{
Update(workItemTrackingHttpClient, sync, valueWithReq);
continue;
}
if (valueWithReq.Value.Fields.MicrosoftVSTSCommonPriority != priority)
{
Update(workItemTrackingHttpClient, sync, valueWithReq);
continue;
}
}
state = GetMappedState(fiBacklogMesa);
if (!string.IsNullOrEmpty(state) && valueWithReq.Value.Fields.SystemState != state)
{
Update(workItemTrackingHttpClient, sync, valueWithReq);
continue;
}
if (!isBugFix && int.TryParse(fiBacklogMesa.EstEffortDays, out int estEffortDays) && valueWithReq.Value.Fields.Effort != estEffortDays)
{
Update(workItemTrackingHttpClient, sync, valueWithReq);
continue;
}
dateTime = GetCommitDate(fiBacklogMesa);
if (dateTime is not null)
{
timeSpan = new(valueWithReq.Value.Fields.TargetDate.Ticks - dateTime.Value.Ticks);
if (timeSpan.Hours is > 32 or < -32)
{
Update(workItemTrackingHttpClient, sync, valueWithReq);
continue;
}
}
}
return results.ToArray();
}
private static string GetDescription(FIBacklogMesa fiBacklogMesa, DateTime dateTime) =>
@ -183,15 +304,15 @@ public class ProcessData : IProcessData
}
}
private static JsonPatchDocument GetUATDocument(string project, ReadOnlyDictionary<string, string> requestorNameToUser, DateTime dateTime, string key, FIBacklogMesa fiBacklogMesa)
private static JsonPatchDocument GetUATDocument(string project, ReadOnlyDictionary<string, string> requestorNameToUser, DateTime dateTime, FIBacklogMesa fiBacklogMesa)
{
JsonPatchDocument result = new();
AddPatch(result, "/fields/System.AreaPath", project);
string description = GetDescription(fiBacklogMesa, dateTime);
AddPatch(result, "/fields/System.IterationPath", project);
AddPatch(result, "/fields/System.Title", key);
AddPatch(result, "/fields/System.Title", $"{fiBacklogMesa.Req} - UAT");
AddPatch(result, "/fields/System.Description", description);
if (requestorNameToUser.TryGetValue(fiBacklogMesa.AssignedTo, out string? requestorUser))
if (requestorNameToUser.TryGetValue(fiBacklogMesa.Requestor, out string? requestorUser))
AddPatch(result, "/fields/System.AssignedTo", requestorUser);
return result;
}
@ -205,6 +326,9 @@ public class ProcessData : IProcessData
AddPatch(result, "/fields/System.AreaPath", project);
AddPatch(result, "/fields/System.IterationPath", project);
AddPatch(result, "/fields/System.Title", $"{fiBacklogMesa.Req} - {fiBacklogMesa.Subject}");
string? state = GetMappedState(fiBacklogMesa);
if (!string.IsNullOrEmpty(state))
AddPatch(result, "/fields/System.State", state);
if (!string.IsNullOrEmpty(fiBacklogMesa.Definition))
AddPatch(result, "/fields/System.Description", fiBacklogMesa.Definition);
if (assignedToNameToUser.TryGetValue(fiBacklogMesa.Requestor, out string? requestorUser))
@ -229,8 +353,8 @@ public class ProcessData : IProcessData
AddPatch(result, "/fields/System.AreaPath", project);
AddPatch(result, "/fields/System.IterationPath", project);
AddPatch(result, "/fields/System.Title", $"{fiBacklogMesa.Req} - Developer Task");
if (assignedToNameToUser.TryGetValue(fiBacklogMesa.SecondResource, out string? assignedToUser))
AddPatch(result, "/fields/System.AssignedTo", assignedToUser);
if (assignedToNameToUser.TryGetValue(fiBacklogMesa.SecondResource, out string? secondResourceUser))
AddPatch(result, "/fields/System.AssignedTo", secondResourceUser);
return result;
}
@ -243,6 +367,9 @@ public class ProcessData : IProcessData
AddPatch(result, "/fields/System.AreaPath", project);
AddPatch(result, "/fields/System.IterationPath", project);
AddPatch(result, "/fields/System.Title", $"{fiBacklogMesa.Req} - User Story");
string? state = GetMappedState(fiBacklogMesa);
if (!string.IsNullOrEmpty(state))
AddPatch(result, "/fields/System.State", state);
if (requestorNameToUser.TryGetValue(fiBacklogMesa.Requestor, out string? requestorUser))
AddPatch(result, "/fields/System.AssignedTo", requestorUser);
return result;
@ -271,6 +398,9 @@ public class ProcessData : IProcessData
JsonPatchDocument result = new();
if (userStoryWorkItemTask?.Result.Id is null)
throw new NotSupportedException();
string title = $"{fiBacklogMesa.Req} - {fiBacklogMesa.Subject}";
if (title.Length > 128)
title = title.Substring(0, 127);
AddPatch(result, "/relations/-", new WorkItemRelation() { Rel = "System.LinkTypes.Hierarchy-Forward", Url = userStoryWorkItemTask.Result.Url });
AddPatch(result, "/fields/System.AreaPath", project);
if (tags.Count > 0)
@ -281,38 +411,62 @@ public class ProcessData : IProcessData
AddPatch(result, "/fields/System.IterationPath", project);
if (!string.IsNullOrEmpty(fiBacklogMesa.Definition))
AddPatch(result, "/fields/System.Description", fiBacklogMesa.Definition);
string? state = GetMappedState(fiBacklogMesa);
if (!string.IsNullOrEmpty(state))
AddPatch(result, "/fields/System.State", state);
if (int.TryParse(fiBacklogMesa.Priority.Substring(0, 1), out int priority) && priority != 0)
AddPatch(result, "/fields/Microsoft.VSTS.Common.Priority", priority);
if (!string.IsNullOrEmpty(fiBacklogMesa.EstEffortDays) && int.TryParse(fiBacklogMesa.EstEffortDays, out int estEffortDays) && estEffortDays != 0)
AddPatch(result, "/fields/Microsoft.VSTS.Scheduling.Effort", estEffortDays);
if (!string.IsNullOrEmpty(fiBacklogMesa.CommitDate) && DateTime.TryParseExact(fiBacklogMesa.CommitDate.Split(' ').First(), "MM/dd/yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime commitDate) && commitDate != DateTime.MinValue)
AddPatch(result, "/fields/Microsoft.VSTS.Scheduling.TargetDate", commitDate.AddHours(12).ToUniversalTime());
DateTime? dateTime = GetCommitDate(fiBacklogMesa);
if (dateTime is not null)
AddPatch(result, "/fields/Microsoft.VSTS.Scheduling.TargetDate", dateTime);
if (!string.IsNullOrEmpty(fiBacklogMesa.Updates))
AddPatch(result, "/fields/System.History", fiBacklogMesa.Updates);
AddPatch(result, "/fields/System.Title", $"{fiBacklogMesa.Req} - {fiBacklogMesa.Subject}");
AddPatch(result, "/fields/System.Title", title);
if (requestorNameToUser.TryGetValue(fiBacklogMesa.Requestor, out string? requestorUser))
AddPatch(result, "/fields/System.AssignedTo", requestorUser);
// https://tfs.intra.infineon.com/tfs/ManufacturingIT/Mesa_FI/_apis/wit/workitemtypes/feature/fields?api-version=7.0
return result;
}
private static void DoWork(WorkItemTrackingHttpClient workItemTrackingHttpClient, string project, ReadOnlyDictionary<string, string> assignedToNameToUser, ReadOnlyDictionary<string, string> requestorNameToUser, string key, FIBacklogMesa fiBacklogMesa)
private static List<string> GetTags(FIBacklogMesa fiBacklogMesa)
{
DateTime dateTime;
List<string> tags = new();
JsonPatchDocument tagDocument;
Task<WorkItem>? secondResourceWorkItemTask = null;
bool isBugFix = fiBacklogMesa.Priority == "0 - BugFix";
if (!DateTime.TryParse(fiBacklogMesa.Submitted, out dateTime))
dateTime = DateTime.MinValue;
List<string> results = new();
foreach (string tag in fiBacklogMesa.SystemS.Split('/'))
{
if (string.IsNullOrEmpty(tag.Trim()))
continue;
tags.Add(tag.Trim());
results.Add(tag.Trim());
}
tags.Reverse();
JsonPatchDocument uatDocument = GetUATDocument(project, requestorNameToUser, dateTime, key, fiBacklogMesa);
return results;
}
private static List<string> GetTags(Fields fields)
{
List<string> results = new();
if (!string.IsNullOrEmpty(fields.SystemTags))
{
foreach (string tag in fields.SystemTags.Split(';'))
{
if (string.IsNullOrEmpty(tag.Trim()))
continue;
results.Add(tag.Trim());
}
}
return results;
}
private static void DoWork(WorkItemTrackingHttpClient workItemTrackingHttpClient, string project, ReadOnlyDictionary<string, string> assignedToNameToUser, ReadOnlyDictionary<string, string> requestorNameToUser, FIBacklogMesa fiBacklogMesa)
{
DateTime dateTime;
JsonPatchDocument tagDocument;
List<string> tags = GetTags(fiBacklogMesa);
Task<WorkItem>? secondResourceWorkItemTask = null;
bool isBugFix = fiBacklogMesa.Priority == "0 - BugFix";
if (!DateTime.TryParse(fiBacklogMesa.Submitted, out dateTime))
dateTime = DateTime.MinValue;
JsonPatchDocument uatDocument = GetUATDocument(project, requestorNameToUser, dateTime, fiBacklogMesa);
Task<WorkItem> uatWorkItemTask = workItemTrackingHttpClient.CreateWorkItemAsync(uatDocument, project, "Task");
uatWorkItemTask.Wait();
if (isBugFix)
@ -383,8 +537,10 @@ public class ProcessData : IProcessData
Dictionary<string, FIBacklogMesa> keyToFIBacklogMesa = GetFIBacklogMesaCollection(json);
Value[] workItems = string.IsNullOrEmpty(ids) ? Array.Empty<Value>() : GetWorkItems(httpClient, basePage, api, ids);
int count = keyToFIBacklogMesa.Count;
Value[] extra = GetExtra(workItems, keyToFIBacklogMesa);
if (count != extra.Length)
ReadOnlyCollection<ValueWithReq> valueWithReqCollection = GetValueWithReqCollection(workItems);
SetSyncTag(workItemTrackingHttpClient, requestorNameToUser, keyToFIBacklogMesa, valueWithReqCollection);
ReadOnlyCollection<ValueWithReq> extra = RemoveFrom(keyToFIBacklogMesa, valueWithReqCollection);
if (count != extra.Count)
{ }
if (count != keyToFIBacklogMesa.Count)
{ }
@ -395,7 +551,7 @@ public class ProcessData : IProcessData
break;
if (!fileRead.IsEAFHosted)
continue;
DoWork(workItemTrackingHttpClient, project, assignedToNameToUser, requestorNameToUser, keyValuePair.Key, keyValuePair.Value);
DoWork(workItemTrackingHttpClient, project, assignedToNameToUser, requestorNameToUser, keyValuePair.Value);
counter++;
}
}

View File

@ -23,7 +23,9 @@ public class Fields
DateTime microsoftVSTSCommonStateChangeDate,
int microsoftVSTSCommonPriority,
string systemDescription,
string systemTags
string systemTags,
float? effort,
DateTime targetDate
)
{
SystemAreaPath = systemAreaPath;
@ -43,6 +45,8 @@ public class Fields
MicrosoftVSTSCommonPriority = microsoftVSTSCommonPriority;
SystemDescription = systemDescription;
SystemTags = systemTags;
Effort = effort;
TargetDate = targetDate;
}
[JsonPropertyName("System.AreaPath")]
@ -95,4 +99,10 @@ public class Fields
[JsonPropertyName("System.Tags")]
public string SystemTags { get; } // { init; get; }
[JsonPropertyName("Microsoft.VSTS.Scheduling.Effort")]
public float? Effort { get; } // { init; get; }
[JsonPropertyName("Microsoft.VSTS.Scheduling.TargetDate")]
public DateTime TargetDate { get; } // { init; get; }
}

View File

@ -0,0 +1,19 @@
using System.Text.Json.Serialization;
namespace Adaptation.FileHandlers.json.WorkItems;
public class ValueWithReq
{
[JsonConstructor]
public ValueWithReq(
Value value,
int req
)
{
Value = value;
Req = req;
}
public Value Value { get; set; } // { init; get; }
public int Req { get; set; } // { init; get; }
}

View File

@ -122,6 +122,7 @@
<Compile Include="Adaptation\FileHandlers\json\WorkItems\SystemChangedBy.cs" />
<Compile Include="Adaptation\FileHandlers\json\WorkItems\SystemCreatedBy.cs" />
<Compile Include="Adaptation\FileHandlers\json\WorkItems\Value.cs" />
<Compile Include="Adaptation\FileHandlers\json\WorkItems\ValueWithReq.cs" />
<Compile Include="Adaptation\FileHandlers\MoveMatchingFiles\FileRead.cs" />
<Compile Include="Adaptation\FileHandlers\OpenInsightMetrologyViewerAttachments\FileRead.cs" />
<Compile Include="Adaptation\FileHandlers\OpenInsightMetrologyViewer\FileRead.cs" />