#if WorkItems using File_Folder_Helper.Day.Q32024.ConvertExcelToJson; using File_Folder_Helper.Day.Q32024.WorkItems; using File_Folder_Helper.Models; #endif using Microsoft.Extensions.Logging; #if WorkItems using Microsoft.TeamFoundation.WorkItemTracking.WebApi; using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models; using Microsoft.VisualStudio.Services.Common; using Microsoft.VisualStudio.Services.WebApi; using Microsoft.VisualStudio.Services.WebApi.Patch; using Microsoft.VisualStudio.Services.WebApi.Patch.Json; using System.Collections.ObjectModel; using System.Globalization; using System.Net.Http.Headers; using System.Text; using System.Text.Json; using System.Web; #endif namespace File_Folder_Helper.ADO2024.PI3; internal static partial class Helper20240809 { #if WorkItems private static void AddPatch(JsonPatchDocument document, string path, object value) => document.Add(new JsonPatchOperation { From = null, Operation = Operation.Add, Path = path, Value = value }); private static Dictionary GetFIBacklogMesaCollection(string json) { Dictionary results = []; string key; FIBacklogMesa[]? fiBacklogMesaCollection; fiBacklogMesaCollection = JsonSerializer.Deserialize(json, FIBacklogMesaCollectionSourceGenerationContext.Default.FIBacklogMesaArray); if (fiBacklogMesaCollection is null || fiBacklogMesaCollection.Length == 0) throw new NullReferenceException(); foreach (FIBacklogMesa fiBacklogMesa in fiBacklogMesaCollection) { if (string.IsNullOrEmpty(fiBacklogMesa.Req)) continue; if (string.IsNullOrEmpty(fiBacklogMesa.Submitted)) continue; if (string.IsNullOrEmpty(fiBacklogMesa.Requestor)) continue; key = $"{fiBacklogMesa.Req} - "; if (results.ContainsKey(key)) continue; results.Add(key, fiBacklogMesa); } return results; } private static string GetIds(HttpClient httpClient, string basePage, string api, string query) { StringBuilder result = new(); Task httpResponseMessageTask = httpClient.GetAsync(string.Concat(basePage, api, query)); httpResponseMessageTask.Wait(); if (!httpResponseMessageTask.Result.IsSuccessStatusCode) throw new Exception(httpResponseMessageTask.Result.StatusCode.ToString()); Task streamTask = httpResponseMessageTask.Result.Content.ReadAsStreamAsync(); streamTask.Wait(); if (!streamTask.Result.CanRead) throw new NullReferenceException(nameof(streamTask)); WIQL.Root? root = JsonSerializer.Deserialize(streamTask.Result, WIQL.WIQLRootSourceGenerationContext.Default.Root); streamTask.Result.Dispose(); if (root is null || root.WorkItems is null) throw new NullReferenceException(nameof(root)); foreach (WIQL.WorkItem workItem in root.WorkItems) _ = result.Append(workItem.Id).Append(','); if (result.Length > 0) _ = result.Remove(result.Length - 1, 1); return result.ToString(); } private static ReadOnlyCollection GetWorkItems(HttpClient httpClient, string basePage, string api, string sourceDirectory, string ids) { List results = []; int req; string json; string file; Value? value; string[] segments; JsonElement[] jsonElements; Task httpResponseMessageTask = httpClient.GetAsync(string.Concat(basePage, api, $"/workitems?ids={ids}")); httpResponseMessageTask.Wait(); if (!httpResponseMessageTask.Result.IsSuccessStatusCode) throw new Exception(httpResponseMessageTask.Result.StatusCode.ToString()); Task streamTask = httpResponseMessageTask.Result.Content.ReadAsStreamAsync(); streamTask.Wait(); if (!streamTask.Result.CanRead) throw new NullReferenceException(nameof(streamTask)); JsonElement? result = JsonSerializer.Deserialize(streamTask.Result); if (result is null || result.Value.ValueKind != JsonValueKind.Object) throw new NullReferenceException(nameof(result)); JsonProperty[] jsonProperties = result.Value.EnumerateObject().ToArray(); foreach (JsonProperty jsonProperty in jsonProperties) { if (jsonProperty.Value.ValueKind != JsonValueKind.Array) continue; jsonElements = jsonProperty.Value.EnumerateArray().ToArray(); foreach (JsonElement jsonElement in jsonElements) { json = jsonElement.GetRawText(); value = JsonSerializer.Deserialize(json, ValueSourceGenerationContext.Default.Value); if (value is null) continue; segments = value.Fields.SystemTitle.Split('-'); if (segments.Length < 2) continue; if (!int.TryParse(segments[0], out req) || req == 0) continue; file = Path.Combine(sourceDirectory, $"{req}-{value.Id}.json"); File.WriteAllText(file, json); results.Add(new(value, req, json)); } } return new(results); } private static ReadOnlyCollection RemoveFrom(Dictionary keyToFIBacklogMesa, ReadOnlyCollection valueWithReqCollection) { List results = []; foreach (ValueWithReq valueWithReq in valueWithReqCollection) { if (keyToFIBacklogMesa.Remove($"{valueWithReq.Req} - ")) continue; results.Add(valueWithReq); } return new(results); } private static ReadOnlyCollection GetComments(HttpClient httpClient, string basePage, string api, string sourceDirectory, int req, int id) { List results = []; string json; string file; Models.Comment? comment; JsonElement[] jsonElements; Task httpResponseMessageTask = httpClient.GetAsync(string.Concat(basePage, api, $"/workitems/{id}/comments?api-version=7.0-preview.3")); httpResponseMessageTask.Wait(); if (!httpResponseMessageTask.Result.IsSuccessStatusCode) throw new Exception(httpResponseMessageTask.Result.StatusCode.ToString()); Task streamTask = httpResponseMessageTask.Result.Content.ReadAsStreamAsync(); streamTask.Wait(); if (!streamTask.Result.CanRead) throw new NullReferenceException(nameof(streamTask)); JsonElement? result = JsonSerializer.Deserialize(streamTask.Result); if (result is null || result.Value.ValueKind != JsonValueKind.Object) throw new NullReferenceException(nameof(result)); JsonProperty[] jsonProperties = result.Value.EnumerateObject().ToArray(); foreach (JsonProperty jsonProperty in jsonProperties) { if (jsonProperty.Value.ValueKind != JsonValueKind.Array) continue; jsonElements = jsonProperty.Value.EnumerateArray().ToArray(); foreach (JsonElement jsonElement in jsonElements) { json = jsonElement.GetRawText(); comment = JsonSerializer.Deserialize(jsonElement, CommentSourceGenerationContext.Default.Comment); if (comment is null || comment.WorkItemId is null || comment.Id is null) continue; file = Path.Combine(sourceDirectory, $"{req}-{id}-{comment.Id}-comments.json"); File.WriteAllText(file, json); results.Add(comment); } } return new(results); } private static void UpdateComment(HttpClient httpClient, string basePage, string api, int id, FIBacklogMesa fiBacklogMesa, Models.Comment comment) { DateTime submittedDateTime; if (!DateTime.TryParse(fiBacklogMesa.Submitted, out submittedDateTime)) submittedDateTime = DateTime.MinValue; string updatesWithSubmitted = $"{fiBacklogMesa.Updates}
 
{submittedDateTime:MM/dd/yyyy} - Submitted by {fiBacklogMesa.Requestor}"; string json = JsonSerializer.Serialize(new { text = updatesWithSubmitted }); StringContent stringContent = new(json, Encoding.UTF8, "application/json"); string requestUri = string.Concat(basePage, api, $"/workitems/{id}/comments/{comment.Id}?api-version=7.0-preview.3"); Task httpResponseMessageTask = httpClient.PatchAsync(requestUri, stringContent); httpResponseMessageTask.Wait(); if (!httpResponseMessageTask.Result.IsSuccessStatusCode) throw new Exception(httpResponseMessageTask.Result.StatusCode.ToString()); Task streamTask = httpResponseMessageTask.Result.Content.ReadAsStreamAsync(); streamTask.Wait(); if (!streamTask.Result.CanRead) throw new NullReferenceException(nameof(streamTask)); JsonElement? result = JsonSerializer.Deserialize(streamTask.Result); if (result is null || result.Value.ValueKind != JsonValueKind.Object) throw new NullReferenceException(nameof(result)); } private static void UpdateAllWorkItemsPharesComment(HttpClient httpClient, string basePage, string api, string sourceDirectory, Dictionary keyToFIBacklogMesa, ReadOnlyCollection valueWithReqCollection) { string key; FIBacklogMesa? fIBacklogMesa; ReadOnlyCollection comments; foreach (ValueWithReq valueWithReq in valueWithReqCollection) { if (valueWithReq.Value.Fields.SystemCommentCount == 0) continue; key = $"{valueWithReq.Req} - "; if (!keyToFIBacklogMesa.TryGetValue(key, out fIBacklogMesa)) continue; comments = GetComments(httpClient, basePage, api, sourceDirectory, valueWithReq.Req, valueWithReq.Value.Id); foreach (Models.Comment comment in comments) { if (comment.CreatedBy?.UniqueName is null || !comment.CreatedBy.UniqueName.Contains("Phares", StringComparison.CurrentCultureIgnoreCase)) continue; UpdateComment(httpClient, basePage, api, valueWithReq.Value.Id, fIBacklogMesa, comment); } } } private static void UpdateIteration(HttpClient httpClient, string basePage, string api, int id, int rev) { string json = /*lang=json,strict*/ string.Concat("[ { \"op\": \"test\", \"path\": \"/rev\", \"value\": ", rev, " }, { \"op\": \"replace\", \"path\": \"/fields/System.IterationPath\", \"value\": \"ART SPS\" } ]"); StringContent stringContent = new(json, Encoding.UTF8, "application/json-patch+json"); string requestUri = string.Concat(basePage, api, $"/workitems/{id}?api-version=1.0"); Task httpResponseMessageTask = httpClient.PatchAsync(requestUri, stringContent); httpResponseMessageTask.Wait(); if (!httpResponseMessageTask.Result.IsSuccessStatusCode) throw new Exception(httpResponseMessageTask.Result.StatusCode.ToString()); Task streamTask = httpResponseMessageTask.Result.Content.ReadAsStreamAsync(); streamTask.Wait(); if (!streamTask.Result.CanRead) throw new NullReferenceException(nameof(streamTask)); JsonElement? result = JsonSerializer.Deserialize(streamTask.Result); if (result is null || result.Value.ValueKind != JsonValueKind.Object) throw new NullReferenceException(nameof(result)); } private static void UpdateAllFeaturesNotArtSPS(HttpClient httpClient, string basePage, string api, ReadOnlyCollection valueWithReqCollection) { foreach (ValueWithReq valueWithReq in valueWithReqCollection) { if (valueWithReq.Value.Fields.SystemIterationPath != "ART SPS\\2024") continue; UpdateIteration(httpClient, basePage, api, valueWithReq.Value.Id, valueWithReq.Value.Rev); } } private static DateTime? GetCommitDate(FIBacklogMesa fiBacklogMesa) { DateTime? result; DateTime dateTime; DateTime minDateTime = DateTime.MinValue.AddYears(10); string commitDate = fiBacklogMesa.CommitDate.Split(' ')[0]; if (string.IsNullOrEmpty(commitDate)) result = null; else { if (DateTime.TryParseExact(commitDate, "MM/dd/yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime) && dateTime >= minDateTime) result = dateTime.AddHours(12).ToUniversalTime(); else { if (DateTime.TryParseExact(commitDate, "dd-MMM-yy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime) && dateTime >= minDateTime) result = dateTime.AddHours(12).ToUniversalTime(); else { if (DateTime.TryParse(commitDate, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime) && dateTime >= minDateTime) result = dateTime.AddHours(12).ToUniversalTime(); else result = null; } } } return result; } private static int GetPriority(FIBacklogMesa fiBacklogMesa) { int result; if (string.IsNullOrEmpty(fiBacklogMesa.Priority) || !int.TryParse(fiBacklogMesa.Priority[..1], out int priority) || priority == 0 || priority > 3) result = 4; else result = priority; return result; } private static int? GetPrioritySubset(FIBacklogMesa fiBacklogMesa) { int? result; if (string.IsNullOrEmpty(fiBacklogMesa.PrioritySubset) || !int.TryParse(fiBacklogMesa.PrioritySubset[..1], out int prioritySubset) || prioritySubset == 0 || prioritySubset > 3) result = null; else result = prioritySubset; return result; } private static string GetIterationPath(string project, DateTime submittedDateTime) => submittedDateTime.Year != 2024 ? project : string.Concat(project, "\\", submittedDateTime.Year); private static string GetTitle(FIBacklogMesa fiBacklogMesa) { string result = $"{fiBacklogMesa.Req} - {fiBacklogMesa.Subject.Split(new string[] { Environment.NewLine }, StringSplitOptions.None)[0]}"; if (result.Length > 128) result = result[..127]; return result; } private static string GetTitle(FIBacklogMesa fiBacklogMesa, ValueWithReq valueWithReq) { string result = $"{valueWithReq.Req} - {fiBacklogMesa.Subject.Split(new string[] { Environment.NewLine }, StringSplitOptions.None)[0]}"; if (result.Length > 128) result = result[..127]; return result; } private static string? GetMappedState(FIBacklogMesa fiBacklogMesa) => fiBacklogMesa.Status == "CMP" ? "Closed" : fiBacklogMesa.Status == "UAT" ? "Resolved" : fiBacklogMesa.Status == "In process" ? "Active" : null; private static JsonPatchDocument GetBugDocument(string project, string site, ReadOnlyDictionary assignedToNameToUser, ReadOnlyDictionary requestorNameToUser, Task? uatWorkItemTask, FIBacklogMesa fiBacklogMesa, DateTime submittedDateTime) { JsonPatchDocument result = []; string title = GetTitle(fiBacklogMesa); string iterationPath = GetIterationPath(project, submittedDateTime); if (uatWorkItemTask?.Result.Id is not null) AddPatch(result, "/relations/-", new WorkItemRelation() { Rel = "System.LinkTypes.Hierarchy-Forward", Url = uatWorkItemTask.Result.Url }); AddPatch(result, "/fields/System.AreaPath", string.Concat(project, "\\", site)); AddPatch(result, "/fields/System.IterationPath", iterationPath); AddPatch(result, "/fields/System.Title", title); AddPatch(result, "/fields/System.CreatedDate", submittedDateTime.AddHours(12).ToUniversalTime()); 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.Subject}
 
{fiBacklogMesa.Definition}"); if (assignedToNameToUser.TryGetValue(fiBacklogMesa.AssignedTo, out string? assignedToUser)) AddPatch(result, "/fields/System.AssignedTo", assignedToUser); if (requestorNameToUser.TryGetValue(fiBacklogMesa.Requestor, out string? requestorUser)) AddPatch(result, "/fields/Custom.Requester", requestorUser); return result; } private static JsonPatchDocument GetFeatureDocument(string project, string site, ReadOnlyDictionary requestorNameToUser, ReadOnlyDictionary assignedToNameToUser, List tags, Task? userStoryWorkItemTask, FIBacklogMesa fiBacklogMesa, DateTime submittedDateTime) { JsonPatchDocument result = []; string title = GetTitle(fiBacklogMesa); int priority = GetPriority(fiBacklogMesa); string? state = GetMappedState(fiBacklogMesa); int? prioritySubset = GetPrioritySubset(fiBacklogMesa); if (prioritySubset is not null) AddPatch(result, "/fields/Microsoft.VSTS.Common.TimeCriticality", prioritySubset); string iterationPath = GetIterationPath(project, submittedDateTime); if (userStoryWorkItemTask?.Result.Id is not null) AddPatch(result, "/relations/-", new WorkItemRelation() { Rel = "System.LinkTypes.Hierarchy-Forward", Url = userStoryWorkItemTask.Result.Url }); AddPatch(result, "/fields/System.AreaPath", string.Concat(project, "\\", site)); if (tags.Count > 0) { AddPatch(result, "/fields/System.Tags", tags.Last()); tags.RemoveAt(tags.Count - 1); } AddPatch(result, "/fields/System.IterationPath", iterationPath); AddPatch(result, "/fields/Microsoft.VSTS.Common.Priority", priority); if (!string.IsNullOrEmpty(fiBacklogMesa.Definition)) AddPatch(result, "/fields/System.Description", $"{fiBacklogMesa.Subject}
 
{fiBacklogMesa.Definition}"); if (!string.IsNullOrEmpty(state)) AddPatch(result, "/fields/System.State", state); if (!string.IsNullOrEmpty(fiBacklogMesa.EstEffortDays) && int.TryParse(fiBacklogMesa.EstEffortDays, out int estEffortDays) && estEffortDays != 0) AddPatch(result, "/fields/Microsoft.VSTS.Scheduling.Effort", estEffortDays); 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", title); AddPatch(result, "/fields/System.CreatedDate", submittedDateTime.AddHours(12).ToUniversalTime()); if (assignedToNameToUser.TryGetValue(fiBacklogMesa.AssignedTo, out string? assignedToUser)) AddPatch(result, "/fields/System.AssignedTo", assignedToUser); if (requestorNameToUser.TryGetValue(fiBacklogMesa.Requestor, out string? requestorUser)) AddPatch(result, "/fields/Custom.Requester", requestorUser); // https://tfs.intra.infineon.com/tfs/ManufacturingIT/Mesa_FI/_apis/wit/workitemtypes/feature/fields?api-version=7.0 return result; } private static List GetTags(FIBacklogMesa fiBacklogMesa) { List results = []; foreach (string tag in fiBacklogMesa.SystemS.Split('/')) { if (string.IsNullOrEmpty(tag.Trim())) continue; results.Add(tag.Trim()); } return results; } private static List GetTags(Fields fields) { List results = []; 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 CreateWorkItem(WorkItemTrackingHttpClient workItemTrackingHttpClient, string project, string site, ReadOnlyDictionary assignedToNameToUser, ReadOnlyDictionary requestorNameToUser, FIBacklogMesa fiBacklogMesa) { DateTime submittedDateTime; JsonPatchDocument tagDocument; Task? workItem = null; List tags = GetTags(fiBacklogMesa); bool isBugFix = fiBacklogMesa.Priority == "0 - BugFix"; if (assignedToNameToUser.Count > requestorNameToUser.Count) throw new Exception(); if (!DateTime.TryParse(fiBacklogMesa.Submitted, out submittedDateTime)) submittedDateTime = DateTime.MinValue; if (isBugFix) { Task? uatWorkItemTask = null; JsonPatchDocument bugDocument = GetBugDocument(project, site, requestorNameToUser, assignedToNameToUser, uatWorkItemTask, fiBacklogMesa, submittedDateTime); workItem = workItemTrackingHttpClient.CreateWorkItemAsync(bugDocument, project, "Bug"); workItem.Wait(); } if (!isBugFix) { Task? userStoryWorkItemTask = null; JsonPatchDocument featureDocument = GetFeatureDocument(project, site, requestorNameToUser, assignedToNameToUser, tags, userStoryWorkItemTask, fiBacklogMesa, submittedDateTime); workItem = workItemTrackingHttpClient.CreateWorkItemAsync(featureDocument, project, "Feature"); workItem.Wait(); } for (int i = tags.Count - 1; i > -1; i--) { if (workItem is null) continue; if (workItem.Result.Id is null) throw new NotSupportedException(); tagDocument = []; AddPatch(tagDocument, "/fields/System.Tags", tags[i]); tags.RemoveAt(i); workItem = workItemTrackingHttpClient.UpdateWorkItemAsync(tagDocument, workItem.Result.Id.Value); workItem.Wait(); } } private static void KillTime(int loops) { for (int i = 1; i < loops; i++) Thread.Sleep(500); } private static void Update(HttpClient httpClient, string basePage, string api, string query, HttpContent httpContent) { #if Windows Task httpResponseMessageTask = httpClient.PatchAsync(string.Concat(basePage, api, query), httpContent); httpResponseMessageTask.Wait(); if (!httpResponseMessageTask.Result.IsSuccessStatusCode) throw new Exception(httpResponseMessageTask.Result.StatusCode.ToString()); Task stringTask = httpResponseMessageTask.Result.Content.ReadAsStringAsync(); stringTask.Wait(); #endif KillTime(30); } private static void Update(HttpClient httpClient, string basePage, string api, WorkItemTrackingHttpClient workItemTrackingHttpClient, string sync, ValueWithReq valueWithReq) { JsonPatchDocument result = []; AddPatch(result, "/fields/System.Tags", sync); Task workItem = workItemTrackingHttpClient.UpdateWorkItemAsync(result, valueWithReq.Value.Id); workItem.Wait(); if (result is null) { var payload = new { op = "replace", path = "/fields/System.IterationPath", value = "Mesa_FI" }; string stringPayload = JsonSerializer.Serialize(payload); HttpContent httpContent = new StringContent($"[{stringPayload}]", Encoding.UTF8, "application/json-patch+json"); Update(httpClient, basePage, api, $"/workitems/{valueWithReq.Value.Id}?api-version=1.0", httpContent); } } private static int SetSyncTag(HttpClient httpClient, string basePage, string api, WorkItemTrackingHttpClient workItemTrackingHttpClient, ReadOnlyDictionary assignedToNameToUser, ReadOnlyDictionary requestorNameToUser, Dictionary keyToFIBacklogMesa, ReadOnlyCollection valueWithReqCollection) { int result = 0; string key; string title; int priority; bool isBugFix; string? state; List tags; TimeSpan timeSpan; DateTime? dateTime; List compareTags; const string sync = "Sync"; FIBacklogMesa? fiBacklogMesa; foreach (ValueWithReq valueWithReq in valueWithReqCollection) { key = $"{valueWithReq.Req} - "; if (!string.IsNullOrEmpty(key)) // Forced to skip logic continue; compareTags = GetTags(valueWithReq.Value.Fields); if (compareTags.Contains(sync)) continue; if (!keyToFIBacklogMesa.TryGetValue(key, out fiBacklogMesa)) continue; tags = GetTags(fiBacklogMesa); title = GetTitle(fiBacklogMesa, valueWithReq); isBugFix = fiBacklogMesa.Priority == "0 - BugFix"; _ = requestorNameToUser.TryGetValue(fiBacklogMesa.Requestor, out string? requestorUser); if (!string.IsNullOrEmpty(requestorUser) && (valueWithReq.Value.Fields.CustomRequester is null || !valueWithReq.Value.Fields.CustomRequester.UniqueName.Equals(requestorUser, StringComparison.CurrentCultureIgnoreCase))) { result += 1; Update(httpClient, basePage, api, workItemTrackingHttpClient, sync, valueWithReq); continue; } _ = assignedToNameToUser.TryGetValue(fiBacklogMesa.Requestor, out string? assignedToUser); if (!string.IsNullOrEmpty(assignedToUser) && (valueWithReq.Value.Fields.SystemAssignedTo is null || !valueWithReq.Value.Fields.SystemAssignedTo.UniqueName.Equals(assignedToUser, StringComparison.CurrentCultureIgnoreCase))) { result += 1; Update(httpClient, basePage, api, workItemTrackingHttpClient, sync, valueWithReq); continue; } if (valueWithReq.Value.Fields.SystemTitle != title) { result += 1; Update(httpClient, basePage, api, workItemTrackingHttpClient, sync, valueWithReq); continue; } foreach (string tag in tags) { if (compareTags.Contains(tag)) continue; _ = tags.Remove(tag); break; } if (tags.Count != compareTags.Count) { result += 1; Update(httpClient, basePage, api, workItemTrackingHttpClient, sync, valueWithReq); continue; } if ((isBugFix && valueWithReq.Value.Fields.SystemWorkItemType != "Bug") || (!isBugFix && valueWithReq.Value.Fields.SystemWorkItemType == "Bug")) { result += 1; Update(httpClient, basePage, api, workItemTrackingHttpClient, sync, valueWithReq); continue; } if (!isBugFix) { priority = GetPriority(fiBacklogMesa); if (valueWithReq.Value.Fields.MicrosoftVSTSCommonPriority != priority) { result += 1; Update(httpClient, basePage, api, workItemTrackingHttpClient, sync, valueWithReq); continue; } } state = GetMappedState(fiBacklogMesa); if (!string.IsNullOrEmpty(state) && valueWithReq.Value.Fields.SystemState != state) { result += 1; Update(httpClient, basePage, api, workItemTrackingHttpClient, sync, valueWithReq); continue; } if (!isBugFix && int.TryParse(fiBacklogMesa.EstEffortDays, out int estEffortDays) && valueWithReq.Value.Fields.MicrosoftVSTSSchedulingEffort != estEffortDays) { result += 1; Update(httpClient, basePage, api, workItemTrackingHttpClient, sync, valueWithReq); continue; } dateTime = GetCommitDate(fiBacklogMesa); if (dateTime is not null) { timeSpan = new(valueWithReq.Value.Fields.MicrosoftVSTSSchedulingTargetDate.Ticks - dateTime.Value.Ticks); if (timeSpan.Hours is > 32 or < -32) { result += 1; Update(httpClient, basePage, api, workItemTrackingHttpClient, sync, valueWithReq); continue; } } } return result; } private static void CreateWorkItems(HttpClient httpClient, string sourceDirectory, string basePage, string api, string query, WorkItemTrackingHttpClient workItemTrackingHttpClient, string project, string site, ReadOnlyDictionary assignedToNameToUser, ReadOnlyDictionary requestorNameToUser, string json) { int counter = 0; string ids = GetIds(httpClient, basePage, api, query); Dictionary keyToFIBacklogMesa = GetFIBacklogMesaCollection(json); ReadOnlyCollection valueWithReqCollection = string.IsNullOrEmpty(ids) ? new([]) : GetWorkItems(httpClient, basePage, api, sourceDirectory, ids); int updated = SetSyncTag(httpClient, basePage, api, workItemTrackingHttpClient, assignedToNameToUser, requestorNameToUser, keyToFIBacklogMesa, valueWithReqCollection); if (updated == 0) { UpdateAllFeaturesNotArtSPS(httpClient, basePage, api, valueWithReqCollection); UpdateAllWorkItemsPharesComment(httpClient, basePage, api, sourceDirectory, keyToFIBacklogMesa, valueWithReqCollection); ReadOnlyCollection extra = RemoveFrom(keyToFIBacklogMesa, valueWithReqCollection); foreach (KeyValuePair keyValuePair in keyToFIBacklogMesa) { if (keyToFIBacklogMesa.Count == extra.Count) break; if (keyValuePair.Value.Status is "CMP" or "CNCL") continue; CreateWorkItem(workItemTrackingHttpClient, project, site, assignedToNameToUser, requestorNameToUser, keyValuePair.Value); counter++; } } } private static void CreateWorkItems(ILogger logger, string sourceDirectory, string api, string site, string query, string project, string basePage, string baseAddress, byte[] bytes, string[] assignedToNames, string[] requestorNames, string reportFullPath, MediaTypeWithQualityHeaderValue mediaTypeWithQualityHeaderValue, WorkItemTrackingHttpClient workItemTrackingHttpClient, HttpClient httpClient) { string base64 = Convert.ToBase64String(bytes); string json = File.ReadAllText(reportFullPath); httpClient.DefaultRequestHeaders.Authorization = new("Basic", base64); httpClient.DefaultRequestHeaders.Accept.Add(mediaTypeWithQualityHeaderValue); ReadOnlyDictionary requestorNameToUser = GetRequestorNameToUser(requestorNames); ReadOnlyDictionary assignedToNameToUser = GetAssignedToNameToUser(assignedToNames); logger.LogInformation("{baseAddress}{basePage}/{project}{api}{query}", baseAddress, basePage, HttpUtility.HtmlEncode(project), api, query); CreateWorkItems(httpClient, sourceDirectory, basePage, api, query, workItemTrackingHttpClient, project, site, new(assignedToNameToUser), new(requestorNameToUser), json); } private static ReadOnlyDictionary GetAssignedToNameToUser(string[] assignedToNames) { Dictionary results = []; string[] segments; foreach (string assignedToName in assignedToNames) { segments = assignedToName.Split('|'); if (segments.Length != 2) continue; results.Add(segments[0], segments[1]); } return new(results); } private static ReadOnlyDictionary GetRequestorNameToUser(string[] requestorNames) { Dictionary results = []; string[] segments; foreach (string requestorName in requestorNames) { segments = requestorName.Split('|'); if (segments.Length != 2) continue; results.Add(segments[0], segments[1]); } return new(results); } internal static void CreateWorkItems(ILogger logger, List args) { string api = args[6]; string pat = args[8]; string site = args[2]; string query = args[7]; string project = args[5]; string basePage = args[4]; string baseAddress = args[3]; string sourceDirectory = args[0]; VssBasicCredential credential = new("", pat); string[] requestorNames = args[11].Split(','); string[] assignedToNames = args[10].Split(','); byte[] bytes = Encoding.ASCII.GetBytes($":{pat}"); string reportFullPath = Path.GetFullPath(Path.Combine(sourceDirectory, args[9])); VssConnection connection = new(new(string.Concat(baseAddress, basePage)), credential); MediaTypeWithQualityHeaderValue mediaTypeWithQualityHeaderValue = new("application/json"); WorkItemTrackingHttpClient workItemTrackingHttpClient = connection.GetClient(); HttpClient httpClient = new(new HttpClientHandler() { UseDefaultCredentials = true }) { BaseAddress = new(baseAddress) }; CreateWorkItems(logger, sourceDirectory, api, site, query, project, basePage, baseAddress, bytes, assignedToNames, requestorNames, reportFullPath, mediaTypeWithQualityHeaderValue, workItemTrackingHttpClient, httpClient); } #else internal static void CreateWorkItems(ILogger logger, List args) { logger.LogError("CreateWorkItems is not available in WorkItems {args[0]}", args[0]); logger.LogError("CreateWorkItems is not available in WorkItems {args[1]}", args[1]); } #endif }