From f87c5a9aa64a3064706308f27961d26ebd10d74f Mon Sep 17 00:00:00 2001 From: Mike Phares Date: Wed, 21 Aug 2024 13:13:12 -0700 Subject: [PATCH] ADO Comment update --- .vscode/launch.json | 22 ++--- Day/Q32024/Helper-2024-08-09.cs | 147 +++++++++++++++++++++++++++----- Models/Comment.cs | 19 +++++ Models/CreatedBy.cs | 18 ++++ Models/ModifiedBy.cs | 18 ++++ 5 files changed, 192 insertions(+), 32 deletions(-) create mode 100644 Models/Comment.cs create mode 100644 Models/CreatedBy.cs create mode 100644 Models/ModifiedBy.cs diff --git a/.vscode/launch.json b/.vscode/launch.json index 1c003fc..cbdf429 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -13,16 +13,18 @@ "args": [ "s", "X", - "\\\\mesfs.infineon.com\\EC_SPC_Si\\PDSF\\MET08RESIHGCV\\Error", - "Day-Helper-2024-08-20", - "\\\\mesfs.infineon.com\\EC_SPC_Si\\PDSF\\MET08RESIHGCV\\Source", - "*.pdsf", - "5000", - "555", - "666", - "777", - "888", - "999" + "T:/MESAFIBACKLOG/06_SourceCode/MESAFIBACKLOG/Adaptation/.vscode/helper", + "Day-Helper-2024-08-09", + "MES", + "https://tfs.intra.infineon.com", + "/tfs/FactoryIntegration", + "ART SPS", + "/0d06e969-e1f5-4835-a359-620d557c7595/_apis/wit", + "/wiql/3373b300-8de3-4301-9795-e990c3b226f9", + "4n7d2jcql6bkq32f66tohddonfxajkypq66lm5y3zqemtlohawsa", + "FI Backlog Mesa - Request List.json", + "Chase|infineon\\TuckerC,Dakota(SRP)|infineon\\Mitchem,Daniel|infineon\\StieberD,Jonathan|infineon\\Ouellette,Mike|infineon\\Phares", + "Chad B|infineon\\cbecker1,Debra Q|infineon\\Quinones,Jeanne M|infineon\\jmcinty2,Jessica F|infineon\\jfuente1,Jonathon S|infineon\\jsperli1,Justin H|infineon\\jhollan2,Kelly C|infineon\\kclark1,Mark C|infineon\\mcouste1,Marti J|infineon\\mjarsey1,Nik C|infineon\\nclark1,Peyton M|infineon\\McChesne,Ron O|infineon\\HendersS,Susan H|infineon\\HendersS,Tiffany M|infineon\\tmunoz1,Todd C|infineon\\tcarrie1" ], "cwd": "${workspaceFolder}", "console": "integratedTerminal", diff --git a/Day/Q32024/Helper-2024-08-09.cs b/Day/Q32024/Helper-2024-08-09.cs index f530457..8ca69e6 100644 --- a/Day/Q32024/Helper-2024-08-09.cs +++ b/Day/Q32024/Helper-2024-08-09.cs @@ -1,5 +1,6 @@ using File_Folder_Helper.Day.Q32024.ConvertExcelToJson; using File_Folder_Helper.Day.Q32024.WorkItems; +using File_Folder_Helper.Models; using Microsoft.Extensions.Logging; using Microsoft.TeamFoundation.WorkItemTracking.WebApi; using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models; @@ -68,7 +69,7 @@ internal static partial class Helper20240809 return result.ToString(); } - private static ReadOnlyCollection GetWorkItems(HttpClient httpClient, string sourceDirectory, string basePage, string api, string ids) + private static ReadOnlyCollection GetWorkItems(HttpClient httpClient, string basePage, string api, string sourceDirectory, string ids) { List results = []; int req; @@ -76,6 +77,7 @@ internal static partial class Helper20240809 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) @@ -87,21 +89,27 @@ internal static partial class Helper20240809 JsonElement? result = JsonSerializer.Deserialize(streamTask.Result); if (result is null || result.Value.ValueKind != JsonValueKind.Object) throw new NullReferenceException(nameof(result)); - JsonElement[] jsonElements = result.Value.EnumerateObject().Last().Value.EnumerateArray().ToArray(); - foreach (JsonElement jsonElement in jsonElements) + JsonProperty[] jsonProperties = result.Value.EnumerateObject().ToArray(); + foreach (JsonProperty jsonProperty in jsonProperties) { - json = jsonElement.GetRawText(); - value = JsonSerializer.Deserialize(json, ValueSourceGenerationContext.Default.Value); - if (value is null) + if (jsonProperty.Value.ValueKind != JsonValueKind.Array) 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}.json"); - File.WriteAllText(file, json); - results.Add(new(value, req, json)); + 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); } @@ -118,6 +126,98 @@ internal static partial class Helper20240809 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 DateTime? GetCommitDate(FIBacklogMesa fiBacklogMesa) { DateTime? result; @@ -358,13 +458,13 @@ internal static partial class Helper20240809 } private static int SetSyncTag(HttpClient httpClient, - string basePage, - string api, - WorkItemTrackingHttpClient workItemTrackingHttpClient, - ReadOnlyDictionary assignedToNameToUser, - ReadOnlyDictionary requestorNameToUser, - Dictionary keyToFIBacklogMesa, - ReadOnlyCollection valueWithReqCollection) + string basePage, + string api, + WorkItemTrackingHttpClient workItemTrackingHttpClient, + ReadOnlyDictionary assignedToNameToUser, + ReadOnlyDictionary requestorNameToUser, + Dictionary keyToFIBacklogMesa, + ReadOnlyCollection valueWithReqCollection) { int result = 0; string key; @@ -381,6 +481,8 @@ internal static partial class Helper20240809 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; @@ -481,10 +583,11 @@ internal static partial class Helper20240809 int counter = 0; string ids = GetIds(httpClient, basePage, api, query); Dictionary keyToFIBacklogMesa = GetFIBacklogMesaCollection(json); - ReadOnlyCollection valueWithReqCollection = string.IsNullOrEmpty(ids) ? new([]) : GetWorkItems(httpClient, sourceDirectory, basePage, api, ids); + 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) { + UpdateAllWorkItemsPharesComment(httpClient, basePage, api, sourceDirectory, keyToFIBacklogMesa, valueWithReqCollection); ReadOnlyCollection extra = RemoveFrom(keyToFIBacklogMesa, valueWithReqCollection); foreach (KeyValuePair keyValuePair in keyToFIBacklogMesa) { diff --git a/Models/Comment.cs b/Models/Comment.cs new file mode 100644 index 0000000..2709685 --- /dev/null +++ b/Models/Comment.cs @@ -0,0 +1,19 @@ +using System.Text.Json.Serialization; + +namespace File_Folder_Helper.Models; + +public record Comment([property: JsonPropertyName("workItemId")] int? WorkItemId, + [property: JsonPropertyName("id")] int? Id, + [property: JsonPropertyName("version")] int? Version, + [property: JsonPropertyName("text")] string? Text, + [property: JsonPropertyName("createdBy")] CreatedBy CreatedBy, + [property: JsonPropertyName("createdDate")] DateTime CreatedDate, + [property: JsonPropertyName("modifiedBy")] ModifiedBy ModifiedBy, + [property: JsonPropertyName("modifiedDate")] DateTime ModifiedDate, + [property: JsonPropertyName("url")] string? Url); + +[JsonSourceGenerationOptions(WriteIndented = true)] +[JsonSerializable(typeof(Comment))] +internal partial class CommentSourceGenerationContext : JsonSerializerContext +{ +} \ No newline at end of file diff --git a/Models/CreatedBy.cs b/Models/CreatedBy.cs new file mode 100644 index 0000000..81408a8 --- /dev/null +++ b/Models/CreatedBy.cs @@ -0,0 +1,18 @@ +using File_Folder_Helper.Day.Q32024.WorkItems; +using System.Text.Json.Serialization; + +namespace File_Folder_Helper.Models; + +public record CreatedBy([property: JsonPropertyName("displayName")] string? DisplayName, + [property: JsonPropertyName("url")] string? Url, + [property: JsonPropertyName("_links")] Links Links, + [property: JsonPropertyName("id")] string? Id, + [property: JsonPropertyName("uniqueName")] string? UniqueName, + [property: JsonPropertyName("imageUrl")] string? ImageUrl, + [property: JsonPropertyName("descriptor")] string? Descriptor); + +[JsonSourceGenerationOptions(WriteIndented = true)] +[JsonSerializable(typeof(CreatedBy))] +internal partial class CreatedBySourceGenerationContext : JsonSerializerContext +{ +} \ No newline at end of file diff --git a/Models/ModifiedBy.cs b/Models/ModifiedBy.cs new file mode 100644 index 0000000..5a0967e --- /dev/null +++ b/Models/ModifiedBy.cs @@ -0,0 +1,18 @@ +using File_Folder_Helper.Day.Q32024.WorkItems; +using System.Text.Json.Serialization; + +namespace File_Folder_Helper.Models; + +public record ModifiedBy([property: JsonPropertyName("displayName")] string? DisplayName, + [property: JsonPropertyName("url")] string? Url, + [property: JsonPropertyName("_links")] Links Links, + [property: JsonPropertyName("id")] string? Id, + [property: JsonPropertyName("uniqueName")] string? UniqueName, + [property: JsonPropertyName("imageUrl")] string? ImageUrl, + [property: JsonPropertyName("descriptor")] string? Descriptor); + +[JsonSourceGenerationOptions(WriteIndented = true)] +[JsonSerializable(typeof(ModifiedBy))] +internal partial class ModifiedBySourceGenerationContext : JsonSerializerContext +{ +} \ No newline at end of file