diff --git a/Adaptation/FileHandlers/ConvertExcelToJson/ProcessData.cs b/Adaptation/FileHandlers/ConvertExcelToJson/ProcessData.cs index 8c6f39a..7cc133b 100644 --- a/Adaptation/FileHandlers/ConvertExcelToJson/ProcessData.cs +++ b/Adaptation/FileHandlers/ConvertExcelToJson/ProcessData.cs @@ -98,12 +98,12 @@ public class ProcessData : IProcessData if (value.Contains("\"")) value = value.Replace("\"", "\\\""); if (value.Contains("\n")) - value = value.Replace("\n", "
"); + value = value.Replace("\n", "
"); name = table.Columns[j].ColumnName.ToString().Trim(); if (name.Contains("\"")) name = name.Replace("\"", "\\\""); if (name.Contains("\n")) - name = name.Replace("\n", "
"); + name = name.Replace("\n", "
"); _ = jsonString.Append('"').Append(name).Append("\":").Append('"').Append(value).Append('"'); if (j < table.Columns.Count - 1) _ = jsonString.Append(','); diff --git a/Adaptation/FileHandlers/json/FileRead.cs b/Adaptation/FileHandlers/json/FileRead.cs index a9137b8..b1e41ea 100644 --- a/Adaptation/FileHandlers/json/FileRead.cs +++ b/Adaptation/FileHandlers/json/FileRead.cs @@ -28,9 +28,12 @@ public class FileRead : Shared.FileRead, IFileRead private readonly string _Project; private readonly string _BasePage; private readonly HttpClient _HttpClient; + private string _LastDateForcedUpdatedBy; + private string _LastDateDeleteForcedUpdatedBy; + private readonly WorkItemTrackingHttpClient _WorkItemTrackingHttpClient; private readonly ReadOnlyDictionary _RequestorNameToUser; private readonly ReadOnlyDictionary _AssignedToNameToUser; - private readonly WorkItemTrackingHttpClient _WorkItemTrackingHttpClient; + private readonly ReadOnlyDictionary _AssignedToNameToEncodedPAT; public FileRead(ISMTP smtp, Dictionary fileParameter, string cellInstanceName, int? connectionCount, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList modelObjectParameters, string equipmentDictionaryName, Dictionary> dummyRuns, Dictionary> staticRuns, bool useCyclicalForDescription, bool isEAFHosted) : base(new Description(), false, smtp, fileParameter, cellInstanceName, connectionCount, cellInstanceConnectionName, fileConnectorConfiguration, equipmentTypeName, parameterizedModelObjectDefinitionType, modelObjectParameters, equipmentDictionaryName, dummyRuns, staticRuns, useCyclicalForDescription, isEAFHosted: connectionCount is null) @@ -45,8 +48,11 @@ public class FileRead : Shared.FileRead, IFileRead throw new Exception(cellInstanceConnectionName); if (!_IsDuplicator) throw new Exception(cellInstanceConnectionName); + _LastDateForcedUpdatedBy = string.Empty; + _LastDateDeleteForcedUpdatedBy = string.Empty; Dictionary requestorNameToUser = new(); Dictionary assignedToNameToUser = new(); + Dictionary assignedToNameToEncodedPAT = new(); string cellInstanceNamed = string.Concat("CellInstance.", cellInstanceName); MediaTypeWithQualityHeaderValue mediaTypeWithQualityHeaderValue = new("application/json"); _API = GetPropertyValue(cellInstanceConnectionName, modelObjectParameters, $"{cellInstanceNamed}.HttpClient.API"); @@ -63,6 +69,10 @@ public class FileRead : Shared.FileRead, IFileRead foreach (ModelObjectParameterDefinition modelObjectParameterDefinition in requestor) requestorNameToUser.Add(modelObjectParameterDefinition.Name.Split('.')[1], modelObjectParameterDefinition.Value); _RequestorNameToUser = new(requestorNameToUser); + ModelObjectParameterDefinition[] encodedPAT = GetProperties(cellInstanceConnectionName, modelObjectParameters, "Encoded.PAT."); + foreach (ModelObjectParameterDefinition modelObjectParameterDefinition in encodedPAT) + assignedToNameToEncodedPAT.Add(modelObjectParameterDefinition.Name.Split('.')[2], modelObjectParameterDefinition.Value); + _AssignedToNameToEncodedPAT = new(assignedToNameToEncodedPAT); byte[] bytes = Encoding.ASCII.GetBytes($":{pat}"); string base64 = Convert.ToBase64String(bytes); _HttpClient = new(new HttpClientHandler() { UseDefaultCredentials = true }) { BaseAddress = new(baseAddress) }; @@ -148,7 +158,28 @@ public class FileRead : Shared.FileRead, IFileRead results.Item4.Add(_Logistics.FileInfo); else { - IProcessData iProcessData = new ProcessData(this, _Logistics, results.Item4, _HttpClient, _BasePage, _API, _Query, _WorkItemTrackingHttpClient, _Project, _AssignedToNameToUser, _RequestorNameToUser, json); + string formattedDateTime = dateTime.ToString("yyyy-MM-dd"); + bool forceUpdatedBy = !_IsEAFHosted || (dateTime.DayOfWeek == DayOfWeek.Thursday && dateTime.Hour == 12 && _LastDateForcedUpdatedBy != formattedDateTime); + if (forceUpdatedBy) + _LastDateForcedUpdatedBy = formattedDateTime; + bool forceDeleteUpdatedBy = !_IsEAFHosted || (dateTime.DayOfWeek == DayOfWeek.Thursday && dateTime.Hour == 18 && _LastDateDeleteForcedUpdatedBy != formattedDateTime); + if (forceDeleteUpdatedBy) + _LastDateDeleteForcedUpdatedBy = formattedDateTime; + IProcessData iProcessData = new ProcessData(this, + _Logistics, + results.Item4, + _HttpClient, + _BasePage, + _API, + _Query, + _WorkItemTrackingHttpClient, + _Project, + _AssignedToNameToEncodedPAT, + _AssignedToNameToUser, + _RequestorNameToUser, + json, + forceUpdatedBy, + forceDeleteUpdatedBy); if (iProcessData is not ProcessData _) throw new Exception(string.Concat("A) No Data - ", dateTime.Ticks)); if (!iProcessData.Details.Any()) diff --git a/Adaptation/FileHandlers/json/ProcessData.cs b/Adaptation/FileHandlers/json/ProcessData.cs index 33ae566..31355cc 100644 --- a/Adaptation/FileHandlers/json/ProcessData.cs +++ b/Adaptation/FileHandlers/json/ProcessData.cs @@ -14,6 +14,7 @@ using System.Globalization; using System.IO; using System.Linq; using System.Net.Http; +using System.Net.Http.Headers; using System.Text; using System.Text.Json; using System.Threading.Tasks; @@ -27,11 +28,39 @@ public class ProcessData : IProcessData List Shared.Properties.IProcessData.Details => _Details; - public ProcessData(IFileRead fileRead, Logistics logistics, List fileInfoCollection, HttpClient httpClient, string basePage, string api, string query, WorkItemTrackingHttpClient workItemTrackingHttpClient, string project, ReadOnlyDictionary assignedToNameToUser, ReadOnlyDictionary requestorNameToUser, string json) + public ProcessData(IFileRead fileRead, + Logistics logistics, + List fileInfoCollection, + HttpClient httpClient, + string basePage, + string api, + string query, + WorkItemTrackingHttpClient workItemTrackingHttpClient, + string project, + ReadOnlyDictionary assignedToNameToEncodedPAT, + ReadOnlyDictionary assignedToNameToUser, + ReadOnlyDictionary requestorNameToUser, + string json, + bool forceUpdatedBy, + bool forceDeleteUpdatedBy) { fileInfoCollection.Clear(); _Details = new List(); - Parse(fileRead, logistics, fileInfoCollection, httpClient, basePage, api, query, workItemTrackingHttpClient, project, assignedToNameToUser, requestorNameToUser, json); + Parse(fileRead, + logistics, + fileInfoCollection, + httpClient, + basePage, + api, + query, + workItemTrackingHttpClient, + project, + assignedToNameToEncodedPAT, + assignedToNameToUser, + requestorNameToUser, + json, + forceUpdatedBy, + forceDeleteUpdatedBy); } string IProcessData.GetCurrentReactor(IFileRead fileRead, Logistics logistics, Dictionary reactors) @@ -92,7 +121,7 @@ public class ProcessData : IProcessData return result.ToString(); } - private static Value[] GetWorkItems(HttpClient httpClient, string basePage, string api, string ids) + private static Value[] GetWorkItems(IFileRead fileRead, HttpClient httpClient, string basePage, string api, string ids) { Value[]? results; Task httpResponseMessageTask = httpClient.GetAsync(string.Concat(basePage, api, $"/workitems?ids={ids}")); @@ -106,6 +135,8 @@ public class ProcessData : IProcessData JsonElement? jsonElement = JsonSerializer.Deserialize(streamTask.Result); if (jsonElement is null || jsonElement.Value.ValueKind != JsonValueKind.Object) throw new NullReferenceException(nameof(jsonElement)); + if (!fileRead.IsEAFHosted) + File.WriteAllText("../../example.json", jsonElement.Value.EnumerateObject().Last().Value.ToString()); results = JsonSerializer.Deserialize(jsonElement.Value.EnumerateObject().Last().Value); if (results is null || !results.Any()) throw new NullReferenceException(nameof(results)); @@ -158,12 +189,23 @@ public class ProcessData : IProcessData return result; } + private static int GetPriority(FIBacklogMesa fiBacklogMesa) + { + int result; + if (!int.TryParse(fiBacklogMesa.Priority.Substring(0, 1), out int priority) || priority == 0 || priority > 3) + result = 4; + else + result = priority; + 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 requestorNameToUser, Dictionary keyToFIBacklogMesa, ReadOnlyCollection valueWithReqCollection) { string key; + int priority; bool isBugFix; string? state; List tags; @@ -193,6 +235,11 @@ public class ProcessData : IProcessData Update(workItemTrackingHttpClient, sync, valueWithReq); continue; } + if (!string.IsNullOrEmpty(fiBacklogMesa.Definition) && valueWithReq.Value.Fields.SystemDescription != fiBacklogMesa.Definition.Replace("&", "&").Replace("\"", """)) + { + Update(workItemTrackingHttpClient, sync, valueWithReq); + continue; + } foreach (string tag in tags) { if (compareTags.Contains(tag)) @@ -212,11 +259,7 @@ public class ProcessData : IProcessData } if (!isBugFix) { - if (!int.TryParse(fiBacklogMesa.Priority.Substring(0, 1), out int priority)) - { - Update(workItemTrackingHttpClient, sync, valueWithReq); - continue; - } + priority = GetPriority(fiBacklogMesa); if (valueWithReq.Value.Fields.MicrosoftVSTSCommonPriority != priority) { Update(workItemTrackingHttpClient, sync, valueWithReq); @@ -247,12 +290,134 @@ public class ProcessData : IProcessData } } + private static ReadOnlyDictionary> GetForceUpdatedByCollection(ReadOnlyDictionary assignedToNameToEncodedPAT, ReadOnlyDictionary assignedToNameToUser, Dictionary keyToFIBacklogMesa, ReadOnlyCollection valueWithReqCollection) + { + Dictionary> results = new(); + string key; + List? reqCollection; + FIBacklogMesa? fiBacklogMesa; + foreach (ValueWithReq valueWithReq in valueWithReqCollection) + { + key = $"{valueWithReq.Req} - "; + if (!keyToFIBacklogMesa.TryGetValue(key, out fiBacklogMesa)) + continue; + if (string.IsNullOrEmpty(fiBacklogMesa.AssignedTo)) + continue; + if (!assignedToNameToUser.TryGetValue(fiBacklogMesa.AssignedTo, out string? assignedToUser)) + continue; + if (!valueWithReq.Value.Fields.SystemChangedBy.UniqueName.Equals(assignedToUser, StringComparison.CurrentCultureIgnoreCase)) + { + if (!assignedToNameToEncodedPAT.TryGetValue(fiBacklogMesa.AssignedTo, out string? assignedToEncodedPAT) || assignedToEncodedPAT.Length < 15) + continue; + if (!results.TryGetValue(assignedToEncodedPAT, out reqCollection)) + { + results.Add(assignedToEncodedPAT, new()); + if (!results.TryGetValue(assignedToEncodedPAT, out reqCollection)) + throw new NotSupportedException(); + } + reqCollection.Add(valueWithReq.Value.Id); + } + } + return new(results); + } + + private static ReadOnlyDictionary> GetForceUpdatedByCollectionDelete(string forceUpdatedByComment, ReadOnlyDictionary assignedToNameToEncodedPAT, ReadOnlyDictionary assignedToNameToUser, Dictionary keyToFIBacklogMesa, ReadOnlyCollection valueWithReqCollection) + { + Dictionary> results = new(); + string key; + List? reqCollection; + FIBacklogMesa? fiBacklogMesa; + foreach (ValueWithReq valueWithReq in valueWithReqCollection) + { + key = $"{valueWithReq.Req} - "; + if (!keyToFIBacklogMesa.TryGetValue(key, out fiBacklogMesa)) + continue; + if (string.IsNullOrEmpty(fiBacklogMesa.AssignedTo)) + continue; + if (!assignedToNameToUser.TryGetValue(fiBacklogMesa.AssignedTo, out string? assignedToUser)) + continue; + if (valueWithReq.Value.Fields.SystemHistory == forceUpdatedByComment) + { + if (!assignedToNameToEncodedPAT.TryGetValue(fiBacklogMesa.AssignedTo, out string? assignedToEncodedPAT) || assignedToEncodedPAT.Length < 15) + continue; + if (!results.TryGetValue(assignedToEncodedPAT, out reqCollection)) + { + results.Add(assignedToEncodedPAT, new()); + if (!results.TryGetValue(assignedToEncodedPAT, out reqCollection)) + throw new NotSupportedException(); + } + reqCollection.Add(new int[] { valueWithReq.Value.Id, valueWithReq.Value.CommentVersionRef.CommentId }); + } + } + return new(results); + } + + private static void Post(HttpClient httpClient, string basePage, string api, string query, HttpContent httpContent) + { + Task httpResponseMessageTask = httpClient.PostAsync(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(); + } + + private static void ForceUpdatedBy(HttpClient httpClient, string basePage, string project, string api, string forceUpdatedByComment, ReadOnlyDictionary> updateCollection) + { + string stringPayload; + HttpContent httpContent; + HttpClient keyHttpClient; + AuthenticationHeaderValue authenticationHeaderValue; + foreach (KeyValuePair> keyValuePair in updateCollection) + { + keyHttpClient = new() { BaseAddress = httpClient.BaseAddress }; + authenticationHeaderValue = keyHttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", keyValuePair.Key); + if (authenticationHeaderValue.Parameter != keyValuePair.Key) + throw new NotSupportedException(); + foreach (int id in keyValuePair.Value) + { + stringPayload = JsonSerializer.Serialize(new { text = forceUpdatedByComment }); + httpContent = new StringContent($"{stringPayload}", Encoding.UTF8, "application/json"); + Post(keyHttpClient, $"{basePage}/{project}", api, $"/workitems/{id}/comments?api-version=5.1-preview.3", httpContent); + } + } + } + + private static void Delete(HttpClient httpClient, string basePage, string api, string query) + { + Task httpResponseMessageTask = httpClient.DeleteAsync(string.Concat(basePage, api, query)); + httpResponseMessageTask.Wait(); + if (!httpResponseMessageTask.Result.IsSuccessStatusCode) + throw new Exception(httpResponseMessageTask.Result.StatusCode.ToString()); + Task stringTask = httpResponseMessageTask.Result.Content.ReadAsStringAsync(); + stringTask.Wait(); + } + + private static void ForceUpdatedByDelete(HttpClient httpClient, string basePage, string project, string api, ReadOnlyDictionary> deleteCollection) + { + HttpClient keyHttpClient; + AuthenticationHeaderValue authenticationHeaderValue; + foreach (KeyValuePair> keyValuePair in deleteCollection) + { + keyHttpClient = new() { BaseAddress = httpClient.BaseAddress }; + authenticationHeaderValue = keyHttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", keyValuePair.Key); + if (authenticationHeaderValue.Parameter != keyValuePair.Key) + throw new NotSupportedException(); + foreach (int[] idCollection in keyValuePair.Value) + { + if (idCollection.Length != 2) + throw new NotSupportedException(); + Delete(keyHttpClient, $"{basePage}/{project}", api, $"/workitems/{idCollection[0]}/comments/{idCollection[1]}?api-version=7.0-preview.3"); + } + } + } + private static string GetDescription(FIBacklogMesa fiBacklogMesa, DateTime dateTime) => $"Req:{fiBacklogMesa.Req}; Submitted:{(dateTime == DateTime.MinValue ? fiBacklogMesa.Submitted : dateTime.ToString("d-MMM-yy"))}; Requestor:{fiBacklogMesa.Requestor}; AssignedTo:{fiBacklogMesa.AssignedTo}; SecondResource:{fiBacklogMesa.SecondResource}; Systems:{fiBacklogMesa.SystemS}; "; private static void Update(HttpClient httpClient, string basePage, string api, string query, HttpContent httpContent) { -#if CORE +#if Windows Task httpResponseMessageTask = httpClient.PatchAsync(string.Concat(basePage, api, query), httpContent); httpResponseMessageTask.Wait(); if (!httpResponseMessageTask.Result.IsSuccessStatusCode) @@ -398,6 +563,7 @@ public class ProcessData : IProcessData JsonPatchDocument result = new(); if (userStoryWorkItemTask?.Result.Id is null) throw new NotSupportedException(); + int priority = GetPriority(fiBacklogMesa); string title = $"{fiBacklogMesa.Req} - {fiBacklogMesa.Subject}"; if (title.Length > 128) title = title.Substring(0, 127); @@ -409,13 +575,12 @@ public class ProcessData : IProcessData tags.RemoveAt(tags.Count - 1); } AddPatch(result, "/fields/System.IterationPath", project); + AddPatch(result, "/fields/Microsoft.VSTS.Common.Priority", priority); 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); DateTime? dateTime = GetCommitDate(fiBacklogMesa); @@ -518,7 +683,21 @@ public class ProcessData : IProcessData } } - private void Parse(IFileRead fileRead, Logistics logistics, List fileInfoCollection, HttpClient httpClient, string basePage, string api, string query, WorkItemTrackingHttpClient workItemTrackingHttpClient, string project, ReadOnlyDictionary assignedToNameToUser, ReadOnlyDictionary requestorNameToUser, string json) + private void Parse(IFileRead fileRead, + Logistics logistics, + List fileInfoCollection, + HttpClient httpClient, + string basePage, + string api, + string query, + WorkItemTrackingHttpClient workItemTrackingHttpClient, + string project, + ReadOnlyDictionary assignedToNameToEncodedPAT, + ReadOnlyDictionary assignedToNameToUser, + ReadOnlyDictionary requestorNameToUser, + string json, + bool forceUpdatedBy, + bool forceDeleteUpdatedBy) { if (fileRead is null) throw new NullReferenceException(); @@ -527,6 +706,7 @@ public class ProcessData : IProcessData if (fileInfoCollection is null) throw new NullReferenceException(); int counter = 0; + string forceUpdatedByComment = "Force updated by"; string? directory = Path.GetDirectoryName(fileRead.ReportFullPath) ?? throw new Exception(); string[] checkFiles = Directory.GetFiles(directory, "*.csv", SearchOption.TopDirectoryOnly); if (checkFiles.Any()) @@ -535,10 +715,19 @@ public class ProcessData : IProcessData { string ids = GetIds(httpClient, basePage, api, query); Dictionary keyToFIBacklogMesa = GetFIBacklogMesaCollection(json); - Value[] workItems = string.IsNullOrEmpty(ids) ? Array.Empty() : GetWorkItems(httpClient, basePage, api, ids); + Value[] workItems = string.IsNullOrEmpty(ids) ? Array.Empty() : GetWorkItems(fileRead, httpClient, basePage, api, ids); int count = keyToFIBacklogMesa.Count; ReadOnlyCollection valueWithReqCollection = GetValueWithReqCollection(workItems); SetSyncTag(workItemTrackingHttpClient, requestorNameToUser, keyToFIBacklogMesa, valueWithReqCollection); + ReadOnlyDictionary> updateCollection = GetForceUpdatedByCollection(assignedToNameToEncodedPAT, assignedToNameToUser, keyToFIBacklogMesa, valueWithReqCollection); + if (updateCollection.Count > 0 && forceUpdatedBy) + ForceUpdatedBy(httpClient, basePage, project, api, forceUpdatedByComment, updateCollection); + if (forceDeleteUpdatedBy) + { + ReadOnlyDictionary> deleteCollection = GetForceUpdatedByCollectionDelete(forceUpdatedByComment, assignedToNameToEncodedPAT, assignedToNameToUser, keyToFIBacklogMesa, valueWithReqCollection); + if (deleteCollection.Count > 0 && forceDeleteUpdatedBy) + ForceUpdatedByDelete(httpClient, basePage, project, api, deleteCollection); + } ReadOnlyCollection extra = RemoveFrom(keyToFIBacklogMesa, valueWithReqCollection); if (count != extra.Count) { } diff --git a/Adaptation/FileHandlers/json/WorkItems/CommentVersionRef.cs b/Adaptation/FileHandlers/json/WorkItems/CommentVersionRef.cs new file mode 100644 index 0000000..2cc4c8b --- /dev/null +++ b/Adaptation/FileHandlers/json/WorkItems/CommentVersionRef.cs @@ -0,0 +1,27 @@ +using System.Text.Json.Serialization; + +namespace Adaptation.FileHandlers.json.WorkItems; + +public class CommentVersionRef +{ + [JsonConstructor] + public CommentVersionRef( + int commentId, + int version, + string url + ) + { + CommentId = commentId; + Version = version; + URL = url; + } + + [JsonPropertyName("commentId")] + public int CommentId { get; } // { init; get; } + + [JsonPropertyName("version")] + public int Version { get; } // { init; get; } + + [JsonPropertyName("url")] + public string URL { get; } // { init; get; } +} \ No newline at end of file diff --git a/Adaptation/FileHandlers/json/WorkItems/Fields.cs b/Adaptation/FileHandlers/json/WorkItems/Fields.cs index 200c90b..ed1a03b 100644 --- a/Adaptation/FileHandlers/json/WorkItems/Fields.cs +++ b/Adaptation/FileHandlers/json/WorkItems/Fields.cs @@ -24,6 +24,7 @@ public class Fields int microsoftVSTSCommonPriority, string systemDescription, string systemTags, + string systemHistory, float? effort, DateTime targetDate ) @@ -45,6 +46,7 @@ public class Fields MicrosoftVSTSCommonPriority = microsoftVSTSCommonPriority; SystemDescription = systemDescription; SystemTags = systemTags; + SystemHistory = systemHistory; Effort = effort; TargetDate = targetDate; } @@ -100,6 +102,9 @@ public class Fields [JsonPropertyName("System.Tags")] public string SystemTags { get; } // { init; get; } + [JsonPropertyName("System.History")] + public string SystemHistory { get; } // { init; get; } + [JsonPropertyName("Microsoft.VSTS.Scheduling.Effort")] public float? Effort { get; } // { init; get; } diff --git a/Adaptation/FileHandlers/json/WorkItems/Value.cs b/Adaptation/FileHandlers/json/WorkItems/Value.cs index 5dbcf9d..adcfc06 100644 --- a/Adaptation/FileHandlers/json/WorkItems/Value.cs +++ b/Adaptation/FileHandlers/json/WorkItems/Value.cs @@ -9,12 +9,14 @@ public class Value int id, int rev, Fields fields, + CommentVersionRef commentVersionRef, string url ) { Id = id; Rev = rev; Fields = fields; + CommentVersionRef = commentVersionRef; Url = url; } @@ -27,6 +29,9 @@ public class Value [JsonPropertyName("fields")] public Fields Fields { get; } + [JsonPropertyName("commentVersionRef")] + public CommentVersionRef CommentVersionRef { get; } + [JsonPropertyName("url")] public string Url { get; } } \ No newline at end of file diff --git a/Adaptation/_Tests/Extract/Development/v2.52.0/MESAFIBACKLOG.cs b/Adaptation/_Tests/Extract/Development/v2.52.0/MESAFIBACKLOG.cs index f95f3f2..690cf64 100644 --- a/Adaptation/_Tests/Extract/Development/v2.52.0/MESAFIBACKLOG.cs +++ b/Adaptation/_Tests/Extract/Development/v2.52.0/MESAFIBACKLOG.cs @@ -91,4 +91,22 @@ public class MESAFIBACKLOG NonThrowTryCatch(); } + [Ignore] + [TestMethod] + public void Development__v2_52_0__MESAFIBACKLOG__json638323658386612550__Normal() + { + string check = "*.json"; + bool validatePDSF = false; + _MESAFIBACKLOG.Development__v2_52_0__MESAFIBACKLOG__json(); + MethodBase methodBase = new StackFrame().GetMethod(); + Assert.IsFalse(string.IsNullOrEmpty(_MESAFIBACKLOG.AdaptationTesting.TestContext.FullyQualifiedTestClassName)); + string[] variables = _MESAFIBACKLOG.AdaptationTesting.GetVariables(methodBase, check, validatePDSF); + IFileRead fileRead = _MESAFIBACKLOG.AdaptationTesting.Get(methodBase, sourceFileLocation: variables[2], sourceFileFilter: variables[3], useCyclicalForDescription: false); + Tuple> extractResult = fileRead.ReExtract(); + Assert.IsFalse(string.IsNullOrEmpty(extractResult?.Item1)); + Assert.IsNotNull(extractResult.Item3); + Assert.IsNotNull(extractResult.Item4); + NonThrowTryCatch(); + } + } \ No newline at end of file diff --git a/MESAFIBACKLOG.csproj b/MESAFIBACKLOG.csproj index dc0e13a..c002098 100644 --- a/MESAFIBACKLOG.csproj +++ b/MESAFIBACKLOG.csproj @@ -115,6 +115,7 @@ +