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 }); fiBacklogMesaCollection = JsonSerializer.Deserialize<FIBacklogMesa[]>(json, new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
if (fiBacklogMesaCollection is null || !fiBacklogMesaCollection.Any()) if (fiBacklogMesaCollection is null || !fiBacklogMesaCollection.Any())
throw new NullReferenceException(); throw new NullReferenceException();
foreach (FIBacklogMesa fIBacklogMesa in fiBacklogMesaCollection) foreach (FIBacklogMesa fiBacklogMesa in fiBacklogMesaCollection)
{ {
if (string.IsNullOrEmpty(fIBacklogMesa.Req)) if (string.IsNullOrEmpty(fiBacklogMesa.Req))
continue; continue;
if (string.IsNullOrEmpty(fIBacklogMesa.Submitted)) if (string.IsNullOrEmpty(fiBacklogMesa.Submitted))
continue; continue;
if (string.IsNullOrEmpty(fIBacklogMesa.Requestor)) if (string.IsNullOrEmpty(fiBacklogMesa.Requestor))
continue; continue;
key = $"{fIBacklogMesa.Req} - "; key = $"{fiBacklogMesa.Req} - ";
if (results.ContainsKey(key)) if (results.ContainsKey(key))
continue; continue;
results.Add(key, fIBacklogMesa); results.Add(key, fiBacklogMesa);
} }
return results; return results;
} }
@ -112,18 +112,139 @@ public class ProcessData : IProcessData
return results; 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) foreach (Value value in workItems)
{ {
if (!value.Fields.SystemTitle.Contains(" - ")) segments = value.Fields.SystemTitle.Split('-');
if (segments.Length < 2)
continue; continue;
if (keyToFIBacklogMesa.Remove(value.Fields.SystemTitle)) if (!int.TryParse(segments[0], out int req) || req == 0)
continue; 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) => 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(); JsonPatchDocument result = new();
AddPatch(result, "/fields/System.AreaPath", project); AddPatch(result, "/fields/System.AreaPath", project);
string description = GetDescription(fiBacklogMesa, dateTime); string description = GetDescription(fiBacklogMesa, dateTime);
AddPatch(result, "/fields/System.IterationPath", project); 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); 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); AddPatch(result, "/fields/System.AssignedTo", requestorUser);
return result; return result;
} }
@ -205,6 +326,9 @@ public class ProcessData : IProcessData
AddPatch(result, "/fields/System.AreaPath", project); AddPatch(result, "/fields/System.AreaPath", project);
AddPatch(result, "/fields/System.IterationPath", project); AddPatch(result, "/fields/System.IterationPath", project);
AddPatch(result, "/fields/System.Title", $"{fiBacklogMesa.Req} - {fiBacklogMesa.Subject}"); 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)) if (!string.IsNullOrEmpty(fiBacklogMesa.Definition))
AddPatch(result, "/fields/System.Description", fiBacklogMesa.Definition); AddPatch(result, "/fields/System.Description", fiBacklogMesa.Definition);
if (assignedToNameToUser.TryGetValue(fiBacklogMesa.Requestor, out string? requestorUser)) 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.AreaPath", project);
AddPatch(result, "/fields/System.IterationPath", project); AddPatch(result, "/fields/System.IterationPath", project);
AddPatch(result, "/fields/System.Title", $"{fiBacklogMesa.Req} - Developer Task"); AddPatch(result, "/fields/System.Title", $"{fiBacklogMesa.Req} - Developer Task");
if (assignedToNameToUser.TryGetValue(fiBacklogMesa.SecondResource, out string? assignedToUser)) if (assignedToNameToUser.TryGetValue(fiBacklogMesa.SecondResource, out string? secondResourceUser))
AddPatch(result, "/fields/System.AssignedTo", assignedToUser); AddPatch(result, "/fields/System.AssignedTo", secondResourceUser);
return result; return result;
} }
@ -243,6 +367,9 @@ public class ProcessData : IProcessData
AddPatch(result, "/fields/System.AreaPath", project); AddPatch(result, "/fields/System.AreaPath", project);
AddPatch(result, "/fields/System.IterationPath", project); AddPatch(result, "/fields/System.IterationPath", project);
AddPatch(result, "/fields/System.Title", $"{fiBacklogMesa.Req} - User Story"); 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)) if (requestorNameToUser.TryGetValue(fiBacklogMesa.Requestor, out string? requestorUser))
AddPatch(result, "/fields/System.AssignedTo", requestorUser); AddPatch(result, "/fields/System.AssignedTo", requestorUser);
return result; return result;
@ -271,6 +398,9 @@ public class ProcessData : IProcessData
JsonPatchDocument result = new(); JsonPatchDocument result = new();
if (userStoryWorkItemTask?.Result.Id is null) if (userStoryWorkItemTask?.Result.Id is null)
throw new NotSupportedException(); 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, "/relations/-", new WorkItemRelation() { Rel = "System.LinkTypes.Hierarchy-Forward", Url = userStoryWorkItemTask.Result.Url });
AddPatch(result, "/fields/System.AreaPath", project); AddPatch(result, "/fields/System.AreaPath", project);
if (tags.Count > 0) if (tags.Count > 0)
@ -281,38 +411,62 @@ public class ProcessData : IProcessData
AddPatch(result, "/fields/System.IterationPath", project); AddPatch(result, "/fields/System.IterationPath", project);
if (!string.IsNullOrEmpty(fiBacklogMesa.Definition)) if (!string.IsNullOrEmpty(fiBacklogMesa.Definition))
AddPatch(result, "/fields/System.Description", 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) if (int.TryParse(fiBacklogMesa.Priority.Substring(0, 1), out int priority) && priority != 0)
AddPatch(result, "/fields/Microsoft.VSTS.Common.Priority", priority); AddPatch(result, "/fields/Microsoft.VSTS.Common.Priority", priority);
if (!string.IsNullOrEmpty(fiBacklogMesa.EstEffortDays) && int.TryParse(fiBacklogMesa.EstEffortDays, out int estEffortDays) && estEffortDays != 0) if (!string.IsNullOrEmpty(fiBacklogMesa.EstEffortDays) && int.TryParse(fiBacklogMesa.EstEffortDays, out int estEffortDays) && estEffortDays != 0)
AddPatch(result, "/fields/Microsoft.VSTS.Scheduling.Effort", estEffortDays); 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) DateTime? dateTime = GetCommitDate(fiBacklogMesa);
AddPatch(result, "/fields/Microsoft.VSTS.Scheduling.TargetDate", commitDate.AddHours(12).ToUniversalTime()); if (dateTime is not null)
AddPatch(result, "/fields/Microsoft.VSTS.Scheduling.TargetDate", dateTime);
if (!string.IsNullOrEmpty(fiBacklogMesa.Updates)) if (!string.IsNullOrEmpty(fiBacklogMesa.Updates))
AddPatch(result, "/fields/System.History", 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)) if (requestorNameToUser.TryGetValue(fiBacklogMesa.Requestor, out string? requestorUser))
AddPatch(result, "/fields/System.AssignedTo", 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 // https://tfs.intra.infineon.com/tfs/ManufacturingIT/Mesa_FI/_apis/wit/workitemtypes/feature/fields?api-version=7.0
return result; 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> results = new();
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;
foreach (string tag in fiBacklogMesa.SystemS.Split('/')) foreach (string tag in fiBacklogMesa.SystemS.Split('/'))
{ {
if (string.IsNullOrEmpty(tag.Trim())) if (string.IsNullOrEmpty(tag.Trim()))
continue; continue;
tags.Add(tag.Trim()); results.Add(tag.Trim());
} }
tags.Reverse(); return results;
JsonPatchDocument uatDocument = GetUATDocument(project, requestorNameToUser, dateTime, key, fiBacklogMesa); }
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"); Task<WorkItem> uatWorkItemTask = workItemTrackingHttpClient.CreateWorkItemAsync(uatDocument, project, "Task");
uatWorkItemTask.Wait(); uatWorkItemTask.Wait();
if (isBugFix) if (isBugFix)
@ -383,8 +537,10 @@ public class ProcessData : IProcessData
Dictionary<string, FIBacklogMesa> keyToFIBacklogMesa = GetFIBacklogMesaCollection(json); Dictionary<string, FIBacklogMesa> keyToFIBacklogMesa = GetFIBacklogMesaCollection(json);
Value[] workItems = string.IsNullOrEmpty(ids) ? Array.Empty<Value>() : GetWorkItems(httpClient, basePage, api, ids); Value[] workItems = string.IsNullOrEmpty(ids) ? Array.Empty<Value>() : GetWorkItems(httpClient, basePage, api, ids);
int count = keyToFIBacklogMesa.Count; int count = keyToFIBacklogMesa.Count;
Value[] extra = GetExtra(workItems, keyToFIBacklogMesa); ReadOnlyCollection<ValueWithReq> valueWithReqCollection = GetValueWithReqCollection(workItems);
if (count != extra.Length) SetSyncTag(workItemTrackingHttpClient, requestorNameToUser, keyToFIBacklogMesa, valueWithReqCollection);
ReadOnlyCollection<ValueWithReq> extra = RemoveFrom(keyToFIBacklogMesa, valueWithReqCollection);
if (count != extra.Count)
{ } { }
if (count != keyToFIBacklogMesa.Count) if (count != keyToFIBacklogMesa.Count)
{ } { }
@ -395,7 +551,7 @@ public class ProcessData : IProcessData
break; break;
if (!fileRead.IsEAFHosted) if (!fileRead.IsEAFHosted)
continue; continue;
DoWork(workItemTrackingHttpClient, project, assignedToNameToUser, requestorNameToUser, keyValuePair.Key, keyValuePair.Value); DoWork(workItemTrackingHttpClient, project, assignedToNameToUser, requestorNameToUser, keyValuePair.Value);
counter++; counter++;
} }
} }

View File

@ -23,7 +23,9 @@ public class Fields
DateTime microsoftVSTSCommonStateChangeDate, DateTime microsoftVSTSCommonStateChangeDate,
int microsoftVSTSCommonPriority, int microsoftVSTSCommonPriority,
string systemDescription, string systemDescription,
string systemTags string systemTags,
float? effort,
DateTime targetDate
) )
{ {
SystemAreaPath = systemAreaPath; SystemAreaPath = systemAreaPath;
@ -43,6 +45,8 @@ public class Fields
MicrosoftVSTSCommonPriority = microsoftVSTSCommonPriority; MicrosoftVSTSCommonPriority = microsoftVSTSCommonPriority;
SystemDescription = systemDescription; SystemDescription = systemDescription;
SystemTags = systemTags; SystemTags = systemTags;
Effort = effort;
TargetDate = targetDate;
} }
[JsonPropertyName("System.AreaPath")] [JsonPropertyName("System.AreaPath")]
@ -95,4 +99,10 @@ public class Fields
[JsonPropertyName("System.Tags")] [JsonPropertyName("System.Tags")]
public string SystemTags { get; } // { init; get; } 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\SystemChangedBy.cs" />
<Compile Include="Adaptation\FileHandlers\json\WorkItems\SystemCreatedBy.cs" /> <Compile Include="Adaptation\FileHandlers\json\WorkItems\SystemCreatedBy.cs" />
<Compile Include="Adaptation\FileHandlers\json\WorkItems\Value.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\MoveMatchingFiles\FileRead.cs" />
<Compile Include="Adaptation\FileHandlers\OpenInsightMetrologyViewerAttachments\FileRead.cs" /> <Compile Include="Adaptation\FileHandlers\OpenInsightMetrologyViewerAttachments\FileRead.cs" />
<Compile Include="Adaptation\FileHandlers\OpenInsightMetrologyViewer\FileRead.cs" /> <Compile Include="Adaptation\FileHandlers\OpenInsightMetrologyViewer\FileRead.cs" />