Moved to ADO2024 PI#
Ran SortCodeMethods
This commit is contained in:
parent
3d114918e4
commit
b6d8d4c52f
12
.vscode/launch.json
vendored
12
.vscode/launch.json
vendored
@ -13,13 +13,13 @@
|
||||
"args": [
|
||||
"s",
|
||||
"X",
|
||||
"D:/5-Other-Small/Kanban-messa010ec/Kanban/Work-Items",
|
||||
"Day-Helper-2024-09-11",
|
||||
"*.json",
|
||||
".kanbn",
|
||||
"Epic|Feature|User Story",
|
||||
"L:/DevOps/Mesa_FI/File-Folder-Helper/.vscode/helper/tfs",
|
||||
"https://tfs.intra.infineon.com/tfs/FactoryIntegration/ART%20SPS/_workitems/edit/"
|
||||
"Day-Helper-2024-09-11",
|
||||
"https://eaf-dev.mes.infineon.com/json/work-items.json?v=2024-10-04-08-34&_=1728333679350",
|
||||
"https://oi-metrology-viewer-prod.mes.infineon.com/json/work-items.json?v=2024-10-07-10-09&_=1728336047608",
|
||||
"Epic|Feature|User Story",
|
||||
"https://tfs.intra.infineon.com/tfs/FactoryIntegration/ART%20SPS/_workitems/edit/",
|
||||
"L:/DevOps/Mesa_FI/File-Folder-Helper/.vscode/helper/tfs"
|
||||
],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"console": "integratedTerminal",
|
||||
|
@ -6,7 +6,7 @@ using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q12024;
|
||||
namespace File_Folder_Helper.ADO2024.PI1;
|
||||
|
||||
#pragma warning disable IDE1006, CS8618
|
||||
|
@ -5,19 +5,13 @@ using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q12024;
|
||||
namespace File_Folder_Helper.ADO2024.PI1;
|
||||
|
||||
internal static partial class Helper20240106
|
||||
{
|
||||
|
||||
private record Record(string Key, Dictionary<string, string> KeyValuePairs);
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Dictionary<string, Dictionary<string, string>>))]
|
||||
private partial class DictionaryDictionarySourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
private static Dictionary<string, Dictionary<string, string>> GetKeyValuePairs(List<Record> collection, bool replaceFound)
|
||||
{
|
||||
Dictionary<string, Dictionary<string, string>> results = [];
|
||||
@ -34,6 +28,27 @@ internal static partial class Helper20240106
|
||||
return results;
|
||||
}
|
||||
|
||||
private static Dictionary<int, Host> GetHosts(string jsonl)
|
||||
{
|
||||
Dictionary<int, Host> results = [];
|
||||
int id;
|
||||
string json = $"[{File.ReadAllText(jsonl).Replace("\r\n", ",")}]";
|
||||
Host[] hosts = JsonSerializer.Deserialize(json, HostSourceGenerationContext.Default.HostArray) ?? throw new NullReferenceException(nameof(json));
|
||||
foreach (Host host in hosts)
|
||||
{
|
||||
if (host.Id is null)
|
||||
continue;
|
||||
if (host.Hyphen is not null and nameof(host.Hyphen))
|
||||
continue;
|
||||
if (!int.TryParse(host.Id, out id))
|
||||
throw new NotSupportedException($"{host.Id} is not a number");
|
||||
if (results.ContainsKey(id))
|
||||
throw new NotSupportedException($"Id {id} is not unique!");
|
||||
results.Add(id, host);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static int? GetHeaderLine(string[] lines)
|
||||
{
|
||||
int? headerLine = null;
|
||||
@ -97,27 +112,6 @@ internal static partial class Helper20240106
|
||||
return results;
|
||||
}
|
||||
|
||||
private static Dictionary<int, Host> GetHosts(string jsonl)
|
||||
{
|
||||
Dictionary<int, Host> results = [];
|
||||
int id;
|
||||
string json = $"[{File.ReadAllText(jsonl).Replace("\r\n", ",")}]";
|
||||
Host[] hosts = JsonSerializer.Deserialize(json, HostSourceGenerationContext.Default.HostArray) ?? throw new NullReferenceException(nameof(json));
|
||||
foreach (Host host in hosts)
|
||||
{
|
||||
if (host.Id is null)
|
||||
continue;
|
||||
if (host.Hyphen is not null and nameof(host.Hyphen))
|
||||
continue;
|
||||
if (!int.TryParse(host.Id, out id))
|
||||
throw new NotSupportedException($"{host.Id} is not a number");
|
||||
if (results.ContainsKey(id))
|
||||
throw new NotSupportedException($"Id {id} is not unique!");
|
||||
results.Add(id, host);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<string> GetIpAddressAndVerify(ILogger<Worker> logger, string key, Dictionary<string, Dictionary<string, string>> keyValuePairs, Dictionary<int, Host> hosts, string filter)
|
||||
{
|
||||
List<string> results = [];
|
||||
@ -188,6 +182,12 @@ internal static partial class Helper20240106
|
||||
File.AppendAllLines(hostConfFile, lines);
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Dictionary<string, Dictionary<string, string>>))]
|
||||
private partial class DictionaryDictionarySourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
internal static void TextToJson(ILogger<Worker> logger, List<string> args)
|
||||
{
|
||||
string json;
|
@ -1,7 +1,7 @@
|
||||
using DiscUtils.Iso9660;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q12024;
|
||||
namespace File_Folder_Helper.ADO2024.PI1;
|
||||
|
||||
internal static partial class Helper20240107
|
||||
{
|
@ -2,7 +2,7 @@ using Microsoft.Extensions.Logging;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q12024;
|
||||
namespace File_Folder_Helper.ADO2024.PI1;
|
||||
|
||||
internal static partial class Helper20240108
|
||||
{
|
@ -2,7 +2,7 @@ using Microsoft.Extensions.Logging;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q12024;
|
||||
namespace File_Folder_Helper.ADO2024.PI1;
|
||||
|
||||
internal static partial class Helper20240129
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Globalization;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q12024;
|
||||
namespace File_Folder_Helper.ADO2024.PI1;
|
||||
|
||||
internal static partial class Helper20240305
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q22024;
|
||||
namespace File_Folder_Helper.ADO2024.PI1;
|
||||
|
||||
internal static partial class Helper20240403
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q22024;
|
||||
namespace File_Folder_Helper.ADO2024.PI1;
|
||||
|
||||
internal static partial class Helper20240404
|
||||
{
|
@ -2,7 +2,7 @@ using Microsoft.Extensions.Logging;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q22024;
|
||||
namespace File_Folder_Helper.ADO2024.PI1;
|
||||
|
||||
internal static partial class Helper20240409
|
||||
{
|
@ -2,7 +2,7 @@ using File_Folder_Helper.Helpers;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q22024;
|
||||
namespace File_Folder_Helper.ADO2024.PI1;
|
||||
|
||||
internal static partial class Helper20240417
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Text;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q22024;
|
||||
namespace File_Folder_Helper.ADO2024.PI1;
|
||||
|
||||
internal static partial class Helper20240426
|
||||
{
|
@ -4,7 +4,7 @@ using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q22024;
|
||||
namespace File_Folder_Helper.ADO2024.PI1;
|
||||
|
||||
internal static partial class Helper20240427
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q22024;
|
||||
namespace File_Folder_Helper.ADO2024.PI2;
|
||||
|
||||
internal static partial class Helper20240429
|
||||
{
|
@ -1,6 +1,6 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q22024;
|
||||
namespace File_Folder_Helper.ADO2024.PI2;
|
||||
|
||||
internal static partial class Helper20240510
|
||||
{
|
@ -2,7 +2,7 @@ using File_Folder_Helper.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q22024;
|
||||
namespace File_Folder_Helper.ADO2024.PI2;
|
||||
|
||||
internal static partial class Helper20240513
|
||||
{
|
@ -3,7 +3,7 @@ using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q22024;
|
||||
namespace File_Folder_Helper.ADO2024.PI2;
|
||||
|
||||
internal static partial class Helper20240517
|
||||
{
|
@ -2,7 +2,7 @@ using File_Folder_Helper.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q22024;
|
||||
namespace File_Folder_Helper.ADO2024.PI2;
|
||||
|
||||
internal static partial class Helper20240518
|
||||
{
|
@ -2,7 +2,7 @@ using File_Folder_Helper.Helpers;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q22024;
|
||||
namespace File_Folder_Helper.ADO2024.PI2;
|
||||
|
||||
internal static partial class Helper20240519
|
||||
{
|
@ -4,7 +4,7 @@ using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q22024;
|
||||
namespace File_Folder_Helper.ADO2024.PI2;
|
||||
|
||||
internal static partial class Helper20240520
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q22024;
|
||||
namespace File_Folder_Helper.ADO2024.PI2;
|
||||
|
||||
internal static partial class Helper20240623
|
||||
{
|
@ -1,6 +1,6 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q22024;
|
||||
namespace File_Folder_Helper.ADO2024.PI2;
|
||||
|
||||
internal static partial class Helper20240624
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q32024;
|
||||
namespace File_Folder_Helper.ADO2024.PI2;
|
||||
|
||||
internal static partial class Helper20240711
|
||||
{
|
@ -3,7 +3,7 @@ using Microsoft.Extensions.Logging;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q32024;
|
||||
namespace File_Folder_Helper.ADO2024.PI2;
|
||||
|
||||
internal static partial class Helper20240718
|
||||
{
|
@ -5,7 +5,7 @@ using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q32024;
|
||||
namespace File_Folder_Helper.ADO2024.PI2;
|
||||
|
||||
internal static partial class Helper20240724
|
||||
{
|
||||
@ -25,22 +25,10 @@ internal static partial class Helper20240724
|
||||
[".txt"],
|
||||
"D:/Tmp/Phares/TargetFileLocation");
|
||||
|
||||
private static DateTime GetFileAgeThresholdDateTime(string fileAgeThreshold)
|
||||
private static string[] GetValidDays(DateTime fileAgeThresholdDateTime)
|
||||
{
|
||||
DateTime result = DateTime.Now;
|
||||
string[] segments = fileAgeThreshold.Split(':');
|
||||
for (int i = 0; i < segments.Length; i++)
|
||||
{
|
||||
result = i switch
|
||||
{
|
||||
0 => result.AddDays(double.Parse(segments[i]) * -1),
|
||||
1 => result.AddHours(double.Parse(segments[i]) * -1),
|
||||
2 => result.AddMinutes(double.Parse(segments[i]) * -1),
|
||||
3 => result.AddSeconds(double.Parse(segments[i]) * -1),
|
||||
_ => throw new Exception(),
|
||||
};
|
||||
}
|
||||
return result;
|
||||
DateTime dateTime = DateTime.Now;
|
||||
return new string[] { dateTime.ToString("yyyy-MM-dd"), fileAgeThresholdDateTime.ToString("yyyy-MM-dd") }.Distinct().ToArray();
|
||||
}
|
||||
|
||||
private static string[] GetValidWeeks(DateTime fileAgeThresholdDateTime)
|
||||
@ -52,12 +40,6 @@ internal static partial class Helper20240724
|
||||
return new string[] { weekOfYear, lastWeekOfYear }.Distinct().ToArray();
|
||||
}
|
||||
|
||||
private static string[] GetValidDays(DateTime fileAgeThresholdDateTime)
|
||||
{
|
||||
DateTime dateTime = DateTime.Now;
|
||||
return new string[] { dateTime.ToString("yyyy-MM-dd"), fileAgeThresholdDateTime.ToString("yyyy-MM-dd") }.Distinct().ToArray();
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<NginxFileSystem> GetDayNginxFileSystemCollection(DateTime fileAgeThresholdDateTime, string week, string day, string dayUrl, NginxFileSystem[] dayNginxFileSystemCollection)
|
||||
{
|
||||
List<NginxFileSystem> results = new();
|
||||
@ -78,6 +60,24 @@ internal static partial class Helper20240724
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
private static DateTime GetFileAgeThresholdDateTime(string fileAgeThreshold)
|
||||
{
|
||||
DateTime result = DateTime.Now;
|
||||
string[] segments = fileAgeThreshold.Split(':');
|
||||
for (int i = 0; i < segments.Length; i++)
|
||||
{
|
||||
result = i switch
|
||||
{
|
||||
0 => result.AddDays(double.Parse(segments[i]) * -1),
|
||||
1 => result.AddHours(double.Parse(segments[i]) * -1),
|
||||
2 => result.AddMinutes(double.Parse(segments[i]) * -1),
|
||||
3 => result.AddSeconds(double.Parse(segments[i]) * -1),
|
||||
_ => throw new Exception(),
|
||||
};
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<NginxFileSystem> GetDayNginxFileSystemCollection(DateTime fileAgeThresholdDateTime)
|
||||
{
|
||||
#nullable enable
|
@ -1,7 +1,7 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q32024;
|
||||
namespace File_Folder_Helper.ADO2024.PI2;
|
||||
|
||||
internal static partial class Helper20240728
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q32024.ConvertExcelToJson;
|
||||
namespace File_Folder_Helper.ADO2024.PI3.ConvertExcelToJson;
|
||||
|
||||
public class FIBacklogMesa
|
||||
{
|
@ -1,10 +1,24 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q32024;
|
||||
namespace File_Folder_Helper.ADO2024.PI3;
|
||||
|
||||
internal static partial class Helper20240805
|
||||
{
|
||||
|
||||
private static void RenameFiles(string find, string replace, string[] ignoreFileNames, string[] confFiles)
|
||||
{
|
||||
string checkFile;
|
||||
foreach (string confFile in confFiles)
|
||||
{
|
||||
if (ignoreFileNames.Contains(confFile))
|
||||
continue;
|
||||
checkFile = confFile.Replace(find, replace);
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
File.Move(confFile, checkFile);
|
||||
}
|
||||
}
|
||||
|
||||
private static void RenameFiles(ILogger<Worker> logger, string sourceDirectory, string[] files, string[] lines, string globalSettingsFile)
|
||||
{
|
||||
string to;
|
||||
@ -53,20 +67,6 @@ internal static partial class Helper20240805
|
||||
File.WriteAllText(globalSettingsFile, globalSettingsLines);
|
||||
}
|
||||
|
||||
private static void RenameFiles(string find, string replace, string[] ignoreFileNames, string[] confFiles)
|
||||
{
|
||||
string checkFile;
|
||||
foreach (string confFile in confFiles)
|
||||
{
|
||||
if (ignoreFileNames.Contains(confFile))
|
||||
continue;
|
||||
checkFile = confFile.Replace(find, replace);
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
File.Move(confFile, checkFile);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void RenameFiles(ILogger<Worker> logger, List<string> args)
|
||||
{
|
||||
string find = args[6];
|
@ -1,7 +1,7 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Globalization;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q32024;
|
||||
namespace File_Folder_Helper.ADO2024.PI3;
|
||||
|
||||
internal static partial class Helper20240806
|
||||
{
|
24075
ADO2024/PI3/Helper-2024-08-09.cs
Normal file
24075
ADO2024/PI3/Helper-2024-08-09.cs
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
namespace File_Folder_Helper.Day.Q32024;
|
||||
namespace File_Folder_Helper.ADO2024.PI3;
|
||||
|
||||
internal static partial class Helper20240820
|
||||
{
|
@ -3,7 +3,7 @@ using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q32024;
|
||||
namespace File_Folder_Helper.ADO2024.PI3;
|
||||
|
||||
internal static partial class Helper20240822
|
||||
{
|
@ -5,7 +5,7 @@ using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q32024;
|
||||
namespace File_Folder_Helper.ADO2024.PI3;
|
||||
|
||||
internal static partial class Helper20240828
|
||||
{
|
||||
@ -68,33 +68,6 @@ internal static partial class Helper20240828
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Record GetRecord(string[] lines, int i)
|
||||
{
|
||||
Record result;
|
||||
int ii = i;
|
||||
string line;
|
||||
string[] segments;
|
||||
string? lastDate = null;
|
||||
List<ReadOnlyCollection<string>> matches = [];
|
||||
for (int j = i; j >= 0; j--)
|
||||
{
|
||||
ii = j;
|
||||
line = lines[j];
|
||||
segments = line.Split(',');
|
||||
if (segments.Length < 2)
|
||||
continue;
|
||||
lastDate ??= segments[0];
|
||||
if (segments[0] != lastDate)
|
||||
{
|
||||
lastDate = segments[0];
|
||||
break;
|
||||
}
|
||||
matches.Add(new(segments));
|
||||
}
|
||||
result = GetRecord(ii + 1, lastDate, new(matches));
|
||||
return result;
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<Record> GetRecords(string logDirectory, string logSearchPattern)
|
||||
{
|
||||
List<Record> results = [];
|
||||
@ -130,6 +103,33 @@ internal static partial class Helper20240828
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static Record GetRecord(string[] lines, int i)
|
||||
{
|
||||
Record result;
|
||||
int ii = i;
|
||||
string line;
|
||||
string[] segments;
|
||||
string? lastDate = null;
|
||||
List<ReadOnlyCollection<string>> matches = [];
|
||||
for (int j = i; j >= 0; j--)
|
||||
{
|
||||
ii = j;
|
||||
line = lines[j];
|
||||
segments = line.Split(',');
|
||||
if (segments.Length < 2)
|
||||
continue;
|
||||
lastDate ??= segments[0];
|
||||
if (segments[0] != lastDate)
|
||||
{
|
||||
lastDate = segments[0];
|
||||
break;
|
||||
}
|
||||
matches.Add(new(segments));
|
||||
}
|
||||
result = GetRecord(ii + 1, lastDate, new(matches));
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Dictionary<int, ReadOnlyCollection<Record>> GetKeyValuePairs(string logSearchPattern, string logDirectory)
|
||||
{
|
||||
Dictionary<int, ReadOnlyCollection<Record>> results;
|
@ -1,5 +1,5 @@
|
||||
#if WorkItems
|
||||
using File_Folder_Helper.Day.Q32024.WorkItems;
|
||||
using File_Folder_Helper.ADO2024.PI3.WorkItems;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.TeamFoundation.WorkItemTracking.WebApi;
|
||||
using Microsoft.VisualStudio.Services.Common;
|
||||
@ -10,7 +10,7 @@ using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Web;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q32024;
|
||||
namespace File_Folder_Helper.ADO2024.PI3;
|
||||
|
||||
internal static partial class Helper20240830
|
||||
{
|
||||
@ -42,6 +42,88 @@ internal static partial class Helper20240830
|
||||
string WorkItemType,
|
||||
float? WeightedShortestJobFirst);
|
||||
|
||||
private static void CompareWorkItems(ILogger<Worker> logger, string sourceDirectory, string api, string site, string query, string project, string basePage, string baseAddress, byte[] bytes, MediaTypeWithQualityHeaderValue mediaTypeWithQualityHeaderValue, WorkItemTrackingHttpClient workItemTrackingHttpClient, HttpClient httpClient)
|
||||
{
|
||||
string base64 = Convert.ToBase64String(bytes);
|
||||
httpClient.DefaultRequestHeaders.Authorization = new("Basic", base64);
|
||||
httpClient.DefaultRequestHeaders.Accept.Add(mediaTypeWithQualityHeaderValue);
|
||||
logger.LogInformation("{baseAddress}{basePage}/{project}{api}{query}", baseAddress, basePage, HttpUtility.HtmlEncode(project), api, query);
|
||||
CompareWorkItems(httpClient, sourceDirectory, basePage, api, query, workItemTrackingHttpClient, project, site);
|
||||
}
|
||||
|
||||
private static void GetSingle(HttpClient httpClient, string basePage, string api, string targetFileLocation, int id)
|
||||
{
|
||||
Task<HttpResponseMessage> httpResponseMessageTask = httpClient.GetAsync(string.Concat(basePage, api, $"/workitems/{id}?%24expand=1"));
|
||||
httpResponseMessageTask.Wait();
|
||||
if (!httpResponseMessageTask.Result.IsSuccessStatusCode)
|
||||
throw new Exception(httpResponseMessageTask.Result.StatusCode.ToString());
|
||||
Task<Stream> streamTask = httpResponseMessageTask.Result.Content.ReadAsStreamAsync();
|
||||
streamTask.Wait();
|
||||
if (!streamTask.Result.CanRead)
|
||||
throw new NullReferenceException(nameof(streamTask));
|
||||
JsonElement? result = JsonSerializer.Deserialize<JsonElement>(streamTask.Result);
|
||||
string file = Path.Combine(targetFileLocation, $"{-9}-{id}.json");
|
||||
File.WriteAllText(file, result.ToString());
|
||||
}
|
||||
|
||||
internal static void CompareWorkItems(ILogger<Worker> logger, List<string> 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);
|
||||
byte[] bytes = Encoding.ASCII.GetBytes($":{pat}");
|
||||
VssConnection connection = new(new(string.Concat(baseAddress, basePage)), credential);
|
||||
MediaTypeWithQualityHeaderValue mediaTypeWithQualityHeaderValue = new("application/json");
|
||||
WorkItemTrackingHttpClient workItemTrackingHttpClient = connection.GetClient<WorkItemTrackingHttpClient>();
|
||||
HttpClient httpClient = new(new HttpClientHandler() { UseDefaultCredentials = true }) { BaseAddress = new(baseAddress) };
|
||||
CompareWorkItems(logger, sourceDirectory, api, site, query, project, basePage, baseAddress, bytes, mediaTypeWithQualityHeaderValue, workItemTrackingHttpClient, httpClient);
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<WorkItem> GetWorkItems(ReadOnlyCollection<ValueWithReq> valueWithReqCollection)
|
||||
{
|
||||
List<WorkItem> results = [];
|
||||
Fields fields;
|
||||
WorkItem workItem;
|
||||
foreach (ValueWithReq valueWithReq in valueWithReqCollection)
|
||||
{
|
||||
fields = valueWithReq.Value.Fields;
|
||||
workItem = new(fields.SystemAreaPath,
|
||||
fields.SystemAssignedTo?.DisplayName,
|
||||
fields.MicrosoftVSTSCommonBusinessValue == 0 ? null : fields.MicrosoftVSTSCommonBusinessValue,
|
||||
fields.SystemChangedDate,
|
||||
fields.MicrosoftVSTSCommonClosedDate == DateTime.MinValue ? null : fields.MicrosoftVSTSCommonClosedDate,
|
||||
fields.SystemCommentCount,
|
||||
fields.SystemCreatedDate,
|
||||
fields.SystemDescription,
|
||||
fields.MicrosoftVSTSSchedulingEffort == 0 ? null : fields.MicrosoftVSTSSchedulingEffort,
|
||||
valueWithReq.Value.Id,
|
||||
fields.SystemIterationPath,
|
||||
fields.SystemParent == 0 ? null : fields.SystemParent,
|
||||
fields.MicrosoftVSTSCommonPriority == 0 ? null : fields.MicrosoftVSTSCommonPriority,
|
||||
valueWithReq.Value.Relations,
|
||||
fields.CustomRequester?.DisplayName,
|
||||
fields.MicrosoftVSTSCommonResolvedDate == DateTime.MinValue ? null : fields.MicrosoftVSTSCommonResolvedDate,
|
||||
valueWithReq.Value.Rev,
|
||||
fields.CustomRRminusOE == 0 ? null : fields.CustomRRminusOE,
|
||||
fields.MicrosoftVSTSSchedulingStartDate == DateTime.MinValue ? null : fields.MicrosoftVSTSSchedulingStartDate,
|
||||
fields.SystemState,
|
||||
fields.SystemTags,
|
||||
fields.MicrosoftVSTSSchedulingTargetDate == DateTime.MinValue ? null : fields.MicrosoftVSTSSchedulingTargetDate,
|
||||
fields.MicrosoftVSTSCommonTimeCriticality == 0 ? null : fields.MicrosoftVSTSCommonTimeCriticality,
|
||||
fields.SystemTitle,
|
||||
fields.SystemWorkItemType,
|
||||
fields.CustomWSJF == 0 ? null : fields.CustomWSJF);
|
||||
results.Add(workItem);
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static string GetIds(HttpClient httpClient, string basePage, string api, string query)
|
||||
{
|
||||
List<int> results = [];
|
||||
@ -71,21 +153,6 @@ internal static partial class Helper20240830
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
private static void GetSingle(HttpClient httpClient, string basePage, string api, string targetFileLocation, int id)
|
||||
{
|
||||
Task<HttpResponseMessage> httpResponseMessageTask = httpClient.GetAsync(string.Concat(basePage, api, $"/workitems/{id}?%24expand=1"));
|
||||
httpResponseMessageTask.Wait();
|
||||
if (!httpResponseMessageTask.Result.IsSuccessStatusCode)
|
||||
throw new Exception(httpResponseMessageTask.Result.StatusCode.ToString());
|
||||
Task<Stream> streamTask = httpResponseMessageTask.Result.Content.ReadAsStreamAsync();
|
||||
streamTask.Wait();
|
||||
if (!streamTask.Result.CanRead)
|
||||
throw new NullReferenceException(nameof(streamTask));
|
||||
JsonElement? result = JsonSerializer.Deserialize<JsonElement>(streamTask.Result);
|
||||
string file = Path.Combine(targetFileLocation, $"{-9}-{id}.json");
|
||||
File.WriteAllText(file, result.ToString());
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<ValueWithReq> GetWorkItems(HttpClient httpClient, string basePage, string api, string targetFileLocation, string ids)
|
||||
{
|
||||
List<ValueWithReq> results = [];
|
||||
@ -126,45 +193,6 @@ internal static partial class Helper20240830
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<WorkItem> GetWorkItems(ReadOnlyCollection<ValueWithReq> valueWithReqCollection)
|
||||
{
|
||||
List<WorkItem> results = [];
|
||||
Fields fields;
|
||||
WorkItem workItem;
|
||||
foreach (ValueWithReq valueWithReq in valueWithReqCollection)
|
||||
{
|
||||
fields = valueWithReq.Value.Fields;
|
||||
workItem = new(fields.SystemAreaPath,
|
||||
fields.SystemAssignedTo?.DisplayName,
|
||||
fields.MicrosoftVSTSCommonBusinessValue == 0 ? null : fields.MicrosoftVSTSCommonBusinessValue,
|
||||
fields.SystemChangedDate,
|
||||
fields.MicrosoftVSTSCommonClosedDate == DateTime.MinValue ? null : fields.MicrosoftVSTSCommonClosedDate,
|
||||
fields.SystemCommentCount,
|
||||
fields.SystemCreatedDate,
|
||||
fields.SystemDescription,
|
||||
fields.MicrosoftVSTSSchedulingEffort == 0 ? null : fields.MicrosoftVSTSSchedulingEffort,
|
||||
valueWithReq.Value.Id,
|
||||
fields.SystemIterationPath,
|
||||
fields.SystemParent == 0 ? null : fields.SystemParent,
|
||||
fields.MicrosoftVSTSCommonPriority == 0 ? null : fields.MicrosoftVSTSCommonPriority,
|
||||
valueWithReq.Value.Relations,
|
||||
fields.CustomRequester?.DisplayName,
|
||||
fields.MicrosoftVSTSCommonResolvedDate == DateTime.MinValue ? null : fields.MicrosoftVSTSCommonResolvedDate,
|
||||
valueWithReq.Value.Rev,
|
||||
fields.CustomRRminusOE == 0 ? null : fields.CustomRRminusOE,
|
||||
fields.MicrosoftVSTSSchedulingStartDate == DateTime.MinValue ? null : fields.MicrosoftVSTSSchedulingStartDate,
|
||||
fields.SystemState,
|
||||
fields.SystemTags,
|
||||
fields.MicrosoftVSTSSchedulingTargetDate == DateTime.MinValue ? null : fields.MicrosoftVSTSSchedulingTargetDate,
|
||||
fields.MicrosoftVSTSCommonTimeCriticality == 0 ? null : fields.MicrosoftVSTSCommonTimeCriticality,
|
||||
fields.SystemTitle,
|
||||
fields.SystemWorkItemType,
|
||||
fields.CustomWSJF == 0 ? null : fields.CustomWSJF);
|
||||
results.Add(workItem);
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static void CompareWorkItems(WorkItemTrackingHttpClient workItemTrackingHttpClient,
|
||||
string sourceDirectory,
|
||||
string project,
|
||||
@ -204,33 +232,5 @@ internal static partial class Helper20240830
|
||||
CompareWorkItems(workItemTrackingHttpClient, targetFileLocation, project, site, valueWithReqCollection);
|
||||
}
|
||||
|
||||
private static void CompareWorkItems(ILogger<Worker> logger, string sourceDirectory, string api, string site, string query, string project, string basePage, string baseAddress, byte[] bytes, MediaTypeWithQualityHeaderValue mediaTypeWithQualityHeaderValue, WorkItemTrackingHttpClient workItemTrackingHttpClient, HttpClient httpClient)
|
||||
{
|
||||
string base64 = Convert.ToBase64String(bytes);
|
||||
httpClient.DefaultRequestHeaders.Authorization = new("Basic", base64);
|
||||
httpClient.DefaultRequestHeaders.Accept.Add(mediaTypeWithQualityHeaderValue);
|
||||
logger.LogInformation("{baseAddress}{basePage}/{project}{api}{query}", baseAddress, basePage, HttpUtility.HtmlEncode(project), api, query);
|
||||
CompareWorkItems(httpClient, sourceDirectory, basePage, api, query, workItemTrackingHttpClient, project, site);
|
||||
}
|
||||
|
||||
internal static void CompareWorkItems(ILogger<Worker> logger, List<string> 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);
|
||||
byte[] bytes = Encoding.ASCII.GetBytes($":{pat}");
|
||||
VssConnection connection = new(new(string.Concat(baseAddress, basePage)), credential);
|
||||
MediaTypeWithQualityHeaderValue mediaTypeWithQualityHeaderValue = new("application/json");
|
||||
WorkItemTrackingHttpClient workItemTrackingHttpClient = connection.GetClient<WorkItemTrackingHttpClient>();
|
||||
HttpClient httpClient = new(new HttpClientHandler() { UseDefaultCredentials = true }) { BaseAddress = new(baseAddress) };
|
||||
CompareWorkItems(logger, sourceDirectory, api, site, query, project, basePage, baseAddress, bytes, mediaTypeWithQualityHeaderValue, workItemTrackingHttpClient, httpClient);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
@ -1,7 +1,7 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Globalization;
|
||||
namespace File_Folder_Helper.Day.Q32024;
|
||||
namespace File_Folder_Helper.ADO2024.PI3;
|
||||
|
||||
internal static partial class Helper20240910
|
||||
{
|
698
ADO2024/PI3/Helper-2024-09-11.cs
Normal file
698
ADO2024/PI3/Helper-2024-09-11.cs
Normal file
@ -0,0 +1,698 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
namespace File_Folder_Helper.ADO2024.PI3;
|
||||
|
||||
internal static partial class Helper20240911
|
||||
{
|
||||
|
||||
public record Attribute([property: JsonPropertyName("isLocked")] bool IsLocked,
|
||||
[property: JsonPropertyName("name")] string Name);
|
||||
|
||||
public record Relation([property: JsonPropertyName("rel")] string Type,
|
||||
[property: JsonPropertyName("url")] string URL,
|
||||
[property: JsonPropertyName("attributes")] Attribute Attributes);
|
||||
|
||||
public record Record(WorkItem WorkItem, WorkItem? Parent, ReadOnlyCollection<Record> Children);
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Record[]))]
|
||||
internal partial class RecordCollectionCommonSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
public record WorkItem(string AreaPath,
|
||||
string? AssignedTo,
|
||||
int? BusinessValue,
|
||||
DateTime ChangedDate,
|
||||
DateTime? ClosedDate,
|
||||
int CommentCount,
|
||||
DateTime CreatedDate,
|
||||
string Description,
|
||||
float? Effort,
|
||||
int Id,
|
||||
string IterationPath,
|
||||
int? Parent,
|
||||
int? Priority,
|
||||
Relation[] Relations,
|
||||
string? Requester,
|
||||
DateTime? ResolvedDate,
|
||||
int Revision,
|
||||
int? RiskReductionMinusOpportunityEnablement,
|
||||
DateTime? StartDate,
|
||||
string State,
|
||||
string Tags,
|
||||
DateTime? TargetDate,
|
||||
float? TimeCriticality,
|
||||
string Title,
|
||||
string? Violation,
|
||||
float? WeightedShortestJobFirst,
|
||||
string WorkItemType)
|
||||
{
|
||||
|
||||
public override string ToString() => $"{Id} - {WorkItemType} - {Title}";
|
||||
|
||||
public static WorkItem Get(WorkItem workItem, string? violation) =>
|
||||
new(workItem.AreaPath,
|
||||
workItem.AssignedTo,
|
||||
workItem.BusinessValue,
|
||||
workItem.ChangedDate,
|
||||
workItem.ClosedDate,
|
||||
workItem.CommentCount,
|
||||
workItem.CreatedDate,
|
||||
workItem.Description,
|
||||
workItem.Effort,
|
||||
workItem.Id,
|
||||
workItem.IterationPath,
|
||||
workItem.Parent,
|
||||
workItem.Priority,
|
||||
workItem.Relations,
|
||||
workItem.Requester,
|
||||
workItem.ResolvedDate,
|
||||
workItem.Revision,
|
||||
workItem.RiskReductionMinusOpportunityEnablement,
|
||||
workItem.StartDate,
|
||||
workItem.State,
|
||||
workItem.Tags,
|
||||
workItem.TargetDate,
|
||||
workItem.TimeCriticality,
|
||||
workItem.Title,
|
||||
workItem.Violation is null ? violation : workItem.Violation,
|
||||
workItem.WeightedShortestJobFirst,
|
||||
workItem.WorkItemType);
|
||||
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(WorkItem[]))]
|
||||
internal partial class WorkItemSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
private static int? GetIdFromUrlIfChild(Relation relation)
|
||||
{
|
||||
int? result;
|
||||
string[] segments = relation?.Attributes is null || relation.Attributes.Name != "Child" ? [] : relation.URL.Split('/');
|
||||
if (segments.Length < 2)
|
||||
result = null;
|
||||
else
|
||||
{
|
||||
if (!int.TryParse(segments[^1], out int id))
|
||||
result = null;
|
||||
else
|
||||
result = id;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<Record> GetKeyValuePairs(ReadOnlyDictionary<int, WorkItem> keyValuePairs, WorkItem workItem, List<bool> nests)
|
||||
{
|
||||
List<Record> results = [];
|
||||
int? childId;
|
||||
nests.Add(true);
|
||||
WorkItem? childWorkItem;
|
||||
WorkItem? parentWorkItem;
|
||||
List<WorkItem> collection = [];
|
||||
ReadOnlyCollection<Record> records;
|
||||
if (workItem.Relations is not null && workItem.Relations.Length > 0)
|
||||
{
|
||||
collection.Clear();
|
||||
foreach (Relation relation in workItem.Relations)
|
||||
{
|
||||
childId = GetIdFromUrlIfChild(relation);
|
||||
if (childId is not null && workItem.Parent is not null && relation?.URL is not null && relation.URL.Contains(workItem.Parent.Value.ToString()))
|
||||
continue;
|
||||
if (childId is null || !keyValuePairs.TryGetValue(childId.Value, out childWorkItem))
|
||||
continue;
|
||||
collection.Add(childWorkItem);
|
||||
}
|
||||
collection = (from l in collection orderby l.State != "Closed", l.Id select l).ToList();
|
||||
foreach (WorkItem item in collection)
|
||||
{
|
||||
if (nests.Count > 99)
|
||||
break;
|
||||
if (item.Parent is null)
|
||||
parentWorkItem = null;
|
||||
else
|
||||
_ = keyValuePairs.TryGetValue(item.Parent.Value, out parentWorkItem);
|
||||
records = GetKeyValuePairs(keyValuePairs, item, nests);
|
||||
results.Add(new(item, parentWorkItem, records));
|
||||
}
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static void AppendLines(List<char> spaces, List<string> lines, Record record, bool condensed, bool sprintOnly)
|
||||
{
|
||||
string line;
|
||||
spaces.Add('\t');
|
||||
WorkItem workItem;
|
||||
foreach (Record child in record.Children)
|
||||
{
|
||||
workItem = child.WorkItem;
|
||||
line = GetLine(spaces, workItem, child, condensed, sprintOnly).TrimEnd();
|
||||
lines.Add(line);
|
||||
AppendLines(spaces, lines, child, condensed, sprintOnly);
|
||||
}
|
||||
spaces.RemoveAt(0);
|
||||
}
|
||||
|
||||
private static void AppendLines(string url, List<char> spaces, List<string> lines, ReadOnlyCollection<Record> records, string workItemType)
|
||||
{
|
||||
List<string> results = [];
|
||||
string? maxIterationPath;
|
||||
List<string> distinct = [];
|
||||
foreach (Record record in records)
|
||||
{
|
||||
// if (record.WorkItem.Id != 109724)
|
||||
// continue;
|
||||
if (record.WorkItem.WorkItemType != workItemType)
|
||||
continue;
|
||||
results.Add($"## {record.WorkItem.AssignedTo} - {record.WorkItem.Id} - {record.WorkItem.Title}");
|
||||
results.Add(string.Empty);
|
||||
results.Add($"- [{record.WorkItem.Id}]({url}{record.WorkItem.Id})");
|
||||
if (record.Children.Count == 0)
|
||||
results.Add(string.Empty);
|
||||
else
|
||||
{
|
||||
AppendLines(spaces, results, record, condensed: true, sprintOnly: false);
|
||||
results.Add(string.Empty);
|
||||
distinct.Clear();
|
||||
AppendLines(spaces, distinct, record, condensed: false, sprintOnly: true);
|
||||
if (distinct.Count > 1)
|
||||
{
|
||||
results.Add($"## Distinct Iteration Path(s) - {record.WorkItem.WorkItemType} - {record.WorkItem.AssignedTo} - {record.WorkItem.Id} - {record.WorkItem.Title} - {record.WorkItem.IterationPath}");
|
||||
results.Add(string.Empty);
|
||||
results.Add($"- [{record.WorkItem.Id}]({url}{record.WorkItem.Id})");
|
||||
distinct.Sort();
|
||||
distinct = (from l in distinct select l.Trim()).Distinct().ToList();
|
||||
results.AddRange(distinct);
|
||||
results.Add(string.Empty);
|
||||
maxIterationPath = distinct.Max();
|
||||
if (!string.IsNullOrEmpty(maxIterationPath) && maxIterationPath.Contains("] ") && maxIterationPath.Split(']')[1].Trim() != record.WorkItem.IterationPath)
|
||||
{
|
||||
results.Add($"### Sync to Distinct Max Iteration Path => {maxIterationPath} - {record.WorkItem.Id} - {record.WorkItem.Title}");
|
||||
results.Add(string.Empty);
|
||||
}
|
||||
}
|
||||
results.Add($"## Extended - {record.WorkItem.Id} - {record.WorkItem.Title}");
|
||||
results.Add(string.Empty);
|
||||
AppendLines(spaces, results, record, condensed: false, sprintOnly: false);
|
||||
results.Add(string.Empty);
|
||||
}
|
||||
lines.AddRange(results);
|
||||
results.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetClosed(WorkItem workItem) =>
|
||||
workItem.State != "Closed" ? "[ ]" : "[x]";
|
||||
|
||||
private static string GetLine(List<char> spaces, WorkItem workItem, Record record, bool condensed, bool sprintOnly)
|
||||
{
|
||||
string result;
|
||||
string closed = GetClosed(workItem);
|
||||
result = sprintOnly ? $"\t- [ ] {workItem.IterationPath}" :
|
||||
condensed ? $"{new string(spaces.Skip(1).ToArray())}- {closed} {record.WorkItem.Id} - {workItem.Title}" :
|
||||
$"{new string(spaces.Skip(1).ToArray())}- {closed} {record.WorkItem.Id} - {workItem.Title} ~~~ {workItem.AssignedTo} - {workItem.IterationPath.Replace('\\', '-')} - {workItem.CreatedDate} --- {workItem.ClosedDate}";
|
||||
return result;
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<WorkItem> GetWorkItemsNotMatching(string tags, ReadOnlyCollection<WorkItem> workItems)
|
||||
{
|
||||
List<WorkItem> results = [];
|
||||
string[] segments;
|
||||
string[] parentTags = tags.Split(';');
|
||||
foreach (WorkItem workItem in workItems)
|
||||
{
|
||||
segments = tags.Split(';');
|
||||
if (segments.Length > 0 && parentTags.Any(l => segments.Contains(l)))
|
||||
continue;
|
||||
results.Add(workItem);
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<WorkItem> GetWorkItemsNotMatching(int? priority, ReadOnlyCollection<WorkItem> workItems)
|
||||
{
|
||||
List<WorkItem> results = [];
|
||||
foreach (WorkItem workItem in workItems)
|
||||
{
|
||||
if (workItem.Priority == priority)
|
||||
continue;
|
||||
results.Add(workItem);
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static int GetState(WorkItem workItem) =>
|
||||
workItem.State switch
|
||||
{
|
||||
"New" => 1,
|
||||
"Active" => 2,
|
||||
"Resolved" => 3,
|
||||
"Closed" => 4,
|
||||
"Removed" => 5,
|
||||
_ => 8
|
||||
};
|
||||
|
||||
private static ReadOnlyCollection<WorkItem> GetWorkItemsNotMatching(Record record, ReadOnlyCollection<WorkItem> workItems)
|
||||
{
|
||||
List<WorkItem> results = [];
|
||||
int check;
|
||||
int state = GetState(record.WorkItem);
|
||||
List<KeyValuePair<int, WorkItem>> collection = [];
|
||||
foreach (WorkItem workItem in workItems)
|
||||
{
|
||||
check = GetState(workItem);
|
||||
if (check == state)
|
||||
continue;
|
||||
collection.Add(new(check, workItem));
|
||||
}
|
||||
foreach (KeyValuePair<int, WorkItem> keyValuePair in collection.OrderByDescending(l => l.Key))
|
||||
results.Add(keyValuePair.Value);
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<string> GetChildrenDirectories(ReadOnlyDictionary<int, Record> keyValuePairs, List<bool> nests, string parentDirectory, ReadOnlyCollection<Record> children)
|
||||
{
|
||||
List<string> results = [];
|
||||
nests.Add(true);
|
||||
string directory;
|
||||
Record? childRecord;
|
||||
ReadOnlyCollection<string> childrenDirectories;
|
||||
foreach (Record record in children)
|
||||
{
|
||||
// if (record.WorkItem.Id == 110730)
|
||||
// continue;
|
||||
// if (record.WorkItem.Id == 110732)
|
||||
// continue;
|
||||
directory = Path.Combine(parentDirectory, $"{record.WorkItem.WorkItemType[..1]}-{record.WorkItem.Id}-{record.WorkItem.Title.Trim()[..1]}");
|
||||
results.Add(directory);
|
||||
if (!keyValuePairs.TryGetValue(record.WorkItem.Id, out childRecord))
|
||||
continue;
|
||||
if (nests.Count > 99)
|
||||
break;
|
||||
childrenDirectories = GetChildrenDirectories(keyValuePairs, nests, directory, childRecord.Children);
|
||||
results.AddRange(childrenDirectories);
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static ReadOnlyDictionary<int, Record> GetKeyValuePairs(ReadOnlyDictionary<int, WorkItem> keyValuePairs)
|
||||
{
|
||||
Dictionary<int, Record> results = [];
|
||||
List<bool> nests = [];
|
||||
WorkItem? parentWorkItem;
|
||||
ReadOnlyCollection<Record> records;
|
||||
foreach (KeyValuePair<int, WorkItem> keyValuePair in keyValuePairs)
|
||||
{
|
||||
nests.Clear();
|
||||
if (keyValuePair.Value.Parent is null)
|
||||
parentWorkItem = null;
|
||||
else
|
||||
_ = keyValuePairs.TryGetValue(keyValuePair.Value.Parent.Value, out parentWorkItem);
|
||||
try
|
||||
{
|
||||
records = GetKeyValuePairs(keyValuePairs, keyValuePair.Value, nests);
|
||||
results.Add(keyValuePair.Key, new(keyValuePair.Value, parentWorkItem, records));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
results.Add(keyValuePair.Key, new(keyValuePair.Value, parentWorkItem, new([])));
|
||||
}
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<string> GetDirectories(string destinationDirectory, ReadOnlyDictionary<int, Record> keyValuePairs)
|
||||
{
|
||||
List<string> results = [];
|
||||
Record record;
|
||||
string directory;
|
||||
List<bool> nests = [];
|
||||
ReadOnlyCollection<string> childrenDirectories;
|
||||
string ticksDirectory = Path.Combine(destinationDirectory, "_", DateTime.Now.Ticks.ToString());
|
||||
foreach (KeyValuePair<int, Record> keyValuePair in keyValuePairs)
|
||||
{
|
||||
record = keyValuePair.Value;
|
||||
if (record.Parent is not null && (record.WorkItem.Parent is null || record.Parent.Id != record.WorkItem.Parent.Value))
|
||||
continue;
|
||||
if (record.Parent is not null)
|
||||
continue;
|
||||
// if (record.WorkItem.Id == 110730)
|
||||
// continue;
|
||||
// if (record.WorkItem.Id == 110732)
|
||||
// continue;
|
||||
nests.Clear();
|
||||
directory = Path.Combine(ticksDirectory, $"{record.WorkItem.WorkItemType[..1]}-{record.WorkItem.Id}-{record.WorkItem.Title.Trim()[..1]}");
|
||||
childrenDirectories = GetChildrenDirectories(keyValuePairs, nests, directory, record.Children);
|
||||
results.AddRange(childrenDirectories);
|
||||
}
|
||||
return new(results.Distinct().ToArray());
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<WorkItem> FilterChildren(Record record, ReadOnlyCollection<string> workItemTypes)
|
||||
{
|
||||
List<WorkItem> results = [];
|
||||
WorkItem workItem;
|
||||
foreach (Record child in record.Children)
|
||||
{
|
||||
workItem = child.WorkItem;
|
||||
if (!workItemTypes.Contains(workItem.WorkItemType))
|
||||
continue;
|
||||
results.Add(workItem);
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static string? GetMaxIterationPath(ReadOnlyCollection<WorkItem> workItems)
|
||||
{
|
||||
string? result;
|
||||
List<string> results = [];
|
||||
foreach (WorkItem workItem in workItems)
|
||||
{
|
||||
if (results.Contains(workItem.IterationPath))
|
||||
continue;
|
||||
results.Add(workItem.IterationPath);
|
||||
}
|
||||
result = results.Count == 0 ? null : results.Max();
|
||||
return result;
|
||||
}
|
||||
|
||||
private static ReadOnlyDictionary<int, Record> GetWorkItems(ILogger<Worker> logger, string developmentURL, string productionURL)
|
||||
{
|
||||
ReadOnlyDictionary<int, Record> results;
|
||||
Dictionary<int, WorkItem> keyValuePairs = [];
|
||||
Task<HttpResponseMessage> httpResponseMessage;
|
||||
HttpClient httpClient = new(new HttpClientHandler { UseCookies = false });
|
||||
httpResponseMessage = httpClient.GetAsync(developmentURL);
|
||||
httpResponseMessage.Wait();
|
||||
if (!httpResponseMessage.Result.IsSuccessStatusCode)
|
||||
logger.LogWarning("{StatusCode} for {url}", httpResponseMessage.Result.StatusCode, developmentURL);
|
||||
Task<string> developmentJSON = httpResponseMessage.Result.Content.ReadAsStringAsync();
|
||||
developmentJSON.Wait();
|
||||
httpResponseMessage = httpClient.GetAsync(productionURL);
|
||||
httpResponseMessage.Wait();
|
||||
if (!httpResponseMessage.Result.IsSuccessStatusCode)
|
||||
logger.LogWarning("{StatusCode} for {url}", httpResponseMessage.Result.StatusCode, productionURL);
|
||||
Task<string> productionJSON = httpResponseMessage.Result.Content.ReadAsStringAsync();
|
||||
productionJSON.Wait();
|
||||
if (developmentJSON.Result != developmentJSON.Result)
|
||||
logger.LogWarning("developmentJSON doesn't match developmentJSON");
|
||||
WorkItem[]? workItems = JsonSerializer.Deserialize(productionJSON.Result, WorkItemSourceGenerationContext.Default.WorkItemArray);
|
||||
if (workItems is null)
|
||||
logger.LogWarning("workItems is null");
|
||||
else
|
||||
{
|
||||
foreach (WorkItem workItem in workItems)
|
||||
keyValuePairs.Add(workItem.Id, workItem);
|
||||
}
|
||||
results = GetKeyValuePairs(new(keyValuePairs));
|
||||
return results;
|
||||
}
|
||||
|
||||
private static void WriteFileStructure(string destinationDirectory, ReadOnlyDictionary<int, Record> keyValuePairs)
|
||||
{
|
||||
ReadOnlyCollection<string> collection = GetDirectories(destinationDirectory, keyValuePairs);
|
||||
foreach (string directory in collection)
|
||||
{
|
||||
if (directory.Length > 222)
|
||||
continue;
|
||||
if (!Directory.Exists(directory))
|
||||
_ = Directory.CreateDirectory(directory);
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteFiles(string destinationDirectory, ReadOnlyCollection<Record> records, string fileName)
|
||||
{
|
||||
string json = JsonSerializer.Serialize(records.ToArray(), RecordCollectionCommonSourceGenerationContext.Default.RecordArray);
|
||||
string jsonFile = Path.Combine(destinationDirectory, $"{fileName}.json");
|
||||
string jsonOld = !File.Exists(jsonFile) ? string.Empty : File.ReadAllText(jsonFile);
|
||||
if (json != jsonOld)
|
||||
File.WriteAllText(jsonFile, json);
|
||||
}
|
||||
|
||||
private static void WriteFiles(string destinationDirectory, ReadOnlyCollection<string> lines, ReadOnlyCollection<WorkItem> workItems, string fileName)
|
||||
{
|
||||
string text = string.Join(Environment.NewLine, lines);
|
||||
string markdownFile = Path.Combine(destinationDirectory, $"{fileName}.md");
|
||||
string textOld = !File.Exists(markdownFile) ? string.Empty : File.ReadAllText(markdownFile);
|
||||
if (text != textOld)
|
||||
File.WriteAllText(markdownFile, text);
|
||||
string html = CommonMark.CommonMarkConverter.Convert(text).Replace("<a href", "<a target='_blank' href");
|
||||
string htmlFile = Path.Combine(destinationDirectory, $"{fileName}.html");
|
||||
string htmlOld = !File.Exists(htmlFile) ? string.Empty : File.ReadAllText(htmlFile);
|
||||
if (html != htmlOld)
|
||||
File.WriteAllText(htmlFile, html);
|
||||
string json = JsonSerializer.Serialize(workItems.ToArray(), WorkItemSourceGenerationContext.Default.WorkItemArray);
|
||||
string jsonFile = Path.Combine(destinationDirectory, $"{fileName}.json");
|
||||
string jsonOld = !File.Exists(jsonFile) ? string.Empty : File.ReadAllText(jsonFile);
|
||||
if (json != jsonOld)
|
||||
File.WriteAllText(jsonFile, json);
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<WorkItem> FeatureCheckIterationPath122508(string url, List<string> lines, ReadOnlyCollection<string> workItemTypes, ReadOnlyCollection<Record> records, string workItemType)
|
||||
{
|
||||
List<WorkItem> results = [];
|
||||
string? maxIterationPath;
|
||||
List<string> collection = [];
|
||||
List<string> violations = [];
|
||||
ReadOnlyCollection<WorkItem> childrenWorkItems;
|
||||
foreach (Record record in records)
|
||||
{
|
||||
if (record.WorkItem.WorkItemType != workItemType)
|
||||
continue;
|
||||
collection.Clear();
|
||||
violations.Clear();
|
||||
if (record.Children.Count == 0)
|
||||
continue;
|
||||
childrenWorkItems = FilterChildren(record, workItemTypes);
|
||||
maxIterationPath = GetMaxIterationPath(childrenWorkItems);
|
||||
if (string.IsNullOrEmpty(maxIterationPath) || record.WorkItem.IterationPath == maxIterationPath)
|
||||
continue;
|
||||
collection.Add($"## {record.WorkItem.AssignedTo} - {record.WorkItem.Id} - {record.WorkItem.Title}");
|
||||
collection.Add(string.Empty);
|
||||
collection.Add($"- [{record.WorkItem.Id}]({url}{record.WorkItem.Id})");
|
||||
collection.Add($"- [ ] {record.WorkItem.Id} => {record.WorkItem.IterationPath} != {maxIterationPath}");
|
||||
collection.Add(string.Empty);
|
||||
lines.AddRange(collection);
|
||||
results.Add(WorkItem.Get(record.WorkItem, $"IterationPath:<a target='_blank' href='{url}{record.WorkItem.Id}'>{record.WorkItem.Id}</a>;{record.WorkItem.IterationPath} != {maxIterationPath}"));
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<WorkItem> FeatureCheckTag122514(string url, List<string> lines, ReadOnlyCollection<string> workItemTypes, ReadOnlyCollection<Record> records, string workItemType)
|
||||
{
|
||||
List<WorkItem> results = [];
|
||||
List<string> collection = [];
|
||||
List<string> violations = [];
|
||||
ReadOnlyCollection<WorkItem> childrenWorkItems;
|
||||
ReadOnlyCollection<WorkItem> workItemsNotMatching;
|
||||
foreach (Record record in records)
|
||||
{
|
||||
if (record.WorkItem.WorkItemType != workItemType)
|
||||
continue;
|
||||
collection.Clear();
|
||||
violations.Clear();
|
||||
if (record.Children.Count == 0)
|
||||
continue;
|
||||
if (string.IsNullOrEmpty(record.WorkItem.Tags))
|
||||
workItemsNotMatching = new([record.WorkItem]);
|
||||
else
|
||||
{
|
||||
childrenWorkItems = FilterChildren(record, workItemTypes);
|
||||
workItemsNotMatching = GetWorkItemsNotMatching(record.WorkItem.Tags, childrenWorkItems);
|
||||
if (!string.IsNullOrEmpty(record.WorkItem.Tags) && workItemsNotMatching.Count == 0)
|
||||
continue;
|
||||
}
|
||||
collection.Add($"## {record.WorkItem.AssignedTo} - {record.WorkItem.Id} - {record.WorkItem.Title}");
|
||||
collection.Add(string.Empty);
|
||||
collection.Add($"- [{record.WorkItem.Id}]({url}{record.WorkItem.Id})");
|
||||
foreach (WorkItem workItem in workItemsNotMatching)
|
||||
collection.Add($"- [ ] {workItem} {nameof(record.WorkItem.Tags)} != {record.WorkItem.Tags}");
|
||||
collection.Add(string.Empty);
|
||||
lines.AddRange(collection);
|
||||
violations.Add($"Tag:{record.WorkItem.Tags};");
|
||||
foreach (WorkItem workItem in workItemsNotMatching)
|
||||
violations.Add($"<a target='_blank' href='{url}{workItem.Id}'>{workItem.Id}</a>:{workItem.Tags};");
|
||||
results.Add(WorkItem.Get(record.WorkItem, string.Join(' ', violations)));
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<WorkItem> FeatureCheckPriority126169(string url, List<string> lines, ReadOnlyCollection<string> workItemTypes, ReadOnlyCollection<Record> records, string workItemType)
|
||||
{
|
||||
List<WorkItem> results = [];
|
||||
List<string> collection = [];
|
||||
List<string> violations = [];
|
||||
ReadOnlyCollection<WorkItem> childrenWorkItems;
|
||||
ReadOnlyCollection<WorkItem> workItemsNotMatching;
|
||||
foreach (Record record in records)
|
||||
{
|
||||
if (record.WorkItem.WorkItemType != workItemType)
|
||||
continue;
|
||||
collection.Clear();
|
||||
violations.Clear();
|
||||
if (record.Children.Count == 0)
|
||||
continue;
|
||||
childrenWorkItems = FilterChildren(record, workItemTypes);
|
||||
workItemsNotMatching = GetWorkItemsNotMatching(record.WorkItem.Priority, childrenWorkItems);
|
||||
if (workItemsNotMatching.Count == 0)
|
||||
continue;
|
||||
collection.Add($"## {record.WorkItem.AssignedTo} - {record.WorkItem.Id} - {record.WorkItem.Title}");
|
||||
collection.Add(string.Empty);
|
||||
collection.Add($"- [{record.WorkItem.Id}]({url}{record.WorkItem.Id})");
|
||||
foreach (WorkItem workItem in workItemsNotMatching)
|
||||
collection.Add($"- [ ] [{workItem.Id}]({url}{workItem.Id}) {nameof(record.WorkItem.Priority)} != {record.WorkItem.Priority}");
|
||||
collection.Add(string.Empty);
|
||||
lines.AddRange(collection);
|
||||
violations.Add($"Priority:{record.WorkItem.Priority};");
|
||||
foreach (WorkItem workItem in workItemsNotMatching)
|
||||
violations.Add($"<a target='_blank' href='{url}{workItem.Id}'>{workItem.Id}</a>:{workItem.Priority};");
|
||||
results.Add(WorkItem.Get(record.WorkItem, string.Join(' ', violations)));
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<WorkItem> FeatureCheckState123066(string url, List<string> lines, ReadOnlyCollection<string> workItemTypes, ReadOnlyCollection<Record> records, string workItemType)
|
||||
{
|
||||
List<WorkItem> results = [];
|
||||
List<string> collection = [];
|
||||
List<string> violations = [];
|
||||
ReadOnlyCollection<WorkItem> childrenWorkItems;
|
||||
ReadOnlyCollection<WorkItem> workItemsNotMatching;
|
||||
foreach (Record record in records)
|
||||
{
|
||||
if (record.WorkItem.WorkItemType != workItemType)
|
||||
continue;
|
||||
collection.Clear();
|
||||
violations.Clear();
|
||||
if (record.WorkItem.State == "New")
|
||||
continue;
|
||||
if (record.Children.Count == 0)
|
||||
continue;
|
||||
childrenWorkItems = FilterChildren(record, workItemTypes);
|
||||
workItemsNotMatching = GetWorkItemsNotMatching(record, childrenWorkItems);
|
||||
if (workItemsNotMatching.Count == 0)
|
||||
continue;
|
||||
collection.Add($"## {record.WorkItem.AssignedTo} - {record.WorkItem.Id} - {record.WorkItem.Title}");
|
||||
collection.Add(string.Empty);
|
||||
collection.Add($"- [{record.WorkItem.Id}]({url}{record.WorkItem.Id})");
|
||||
foreach (WorkItem workItem in workItemsNotMatching)
|
||||
collection.Add($"- [ ] [{workItem.Id}]({url}{workItem.Id}) {nameof(record.WorkItem.State)} != {record.WorkItem.State}");
|
||||
collection.Add(string.Empty);
|
||||
lines.AddRange(collection);
|
||||
violations.Add($"State:{record.WorkItem.State};");
|
||||
foreach (WorkItem workItem in workItemsNotMatching)
|
||||
violations.Add($"<a target='_blank' href='{url}{workItem.Id}'>{workItem.Id}</a>:{workItem.State};");
|
||||
results.Add(WorkItem.Get(record.WorkItem, string.Join(' ', violations)));
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<WorkItem> FeatureCheckState123067(string url, List<string> lines, ReadOnlyCollection<string> workItemTypes, ReadOnlyCollection<Record> records, string workItemType)
|
||||
{
|
||||
List<WorkItem> results = [];
|
||||
List<string> collection = [];
|
||||
List<string> violations = [];
|
||||
ReadOnlyCollection<WorkItem> childrenWorkItems;
|
||||
ReadOnlyCollection<WorkItem> workItemsNotMatching;
|
||||
foreach (Record record in records)
|
||||
{
|
||||
if (record.WorkItem.WorkItemType != workItemType)
|
||||
continue;
|
||||
collection.Clear();
|
||||
violations.Clear();
|
||||
if (record.Children.Count == 0)
|
||||
continue;
|
||||
childrenWorkItems = FilterChildren(record, workItemTypes);
|
||||
workItemsNotMatching = GetWorkItemsNotMatching(record, childrenWorkItems);
|
||||
if (workItemsNotMatching.Count == 0)
|
||||
continue;
|
||||
collection.Add($"## {record.WorkItem.AssignedTo} - {record.WorkItem.Id} - {record.WorkItem.Title}");
|
||||
collection.Add(string.Empty);
|
||||
collection.Add($"- [{record.WorkItem.Id}]({url}{record.WorkItem.Id})");
|
||||
foreach (WorkItem workItem in workItemsNotMatching)
|
||||
collection.Add($"- [ ] [{workItem.Id}]({url}{workItem.Id}) {nameof(record.WorkItem.State)} != {record.WorkItem.State}");
|
||||
collection.Add(string.Empty);
|
||||
lines.AddRange(collection);
|
||||
violations.Add($"State:{record.WorkItem.State};");
|
||||
foreach (WorkItem workItem in workItemsNotMatching)
|
||||
violations.Add($"<a target='_blank' href='{url}{workItem.Id}'>{workItem.Id}</a>:{workItem.State};");
|
||||
results.Add(WorkItem.Get(record.WorkItem, string.Join(' ', violations)));
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
internal static void WriteMarkdown(ILogger<Worker> logger, List<string> args)
|
||||
{
|
||||
string url = args[5];
|
||||
List<char> spaces = [];
|
||||
List<string> lines = [];
|
||||
ReadOnlyCollection<WorkItem> results;
|
||||
string[] workItemTypes = args[4].Split('|');
|
||||
string sourceDirectory = Path.GetFullPath(args[0]);
|
||||
string destinationDirectory = Path.GetFullPath(args[6]);
|
||||
if (!Directory.Exists(destinationDirectory))
|
||||
_ = Directory.CreateDirectory(destinationDirectory);
|
||||
ReadOnlyDictionary<int, Record> keyValuePairs = GetWorkItems(logger, args[2], args[3]);
|
||||
WriteFileStructure(destinationDirectory, keyValuePairs);
|
||||
ReadOnlyCollection<Record> records = new(keyValuePairs.Values.ToArray());
|
||||
logger.LogInformation("Found {workItems} workItemAndChildren", records.Count);
|
||||
ReadOnlyCollection<string> bugUserStoryWorkItemTypes = new(new string[] { "Bug", "User Story" });
|
||||
ReadOnlyCollection<string> bugUserStoryTaskWorkItemTypes = new(new string[] { "Bug", "User Story", "Task" });
|
||||
WriteFiles(destinationDirectory, records, "with-parents");
|
||||
foreach (string workItemType in workItemTypes)
|
||||
{
|
||||
lines.Clear();
|
||||
lines.Add($"# {workItemType}");
|
||||
lines.Add(string.Empty);
|
||||
AppendLines(url, spaces, lines, records, workItemType);
|
||||
results = new([]);
|
||||
WriteFiles(destinationDirectory, new(lines), results, workItemType);
|
||||
}
|
||||
{
|
||||
lines.Clear();
|
||||
string workItemType = "Feature";
|
||||
lines.Add($"# {nameof(FeatureCheckIterationPath122508)}");
|
||||
lines.Add(string.Empty);
|
||||
results = FeatureCheckIterationPath122508(url, lines, bugUserStoryTaskWorkItemTypes, records, workItemType);
|
||||
WriteFiles(destinationDirectory, new(lines), results, "check-122508");
|
||||
}
|
||||
{
|
||||
lines.Clear();
|
||||
string workItemType = "Feature";
|
||||
lines.Add($"# {nameof(FeatureCheckTag122514)}");
|
||||
lines.Add(string.Empty);
|
||||
results = FeatureCheckTag122514(url, lines, bugUserStoryWorkItemTypes, records, workItemType);
|
||||
WriteFiles(destinationDirectory, new(lines), results, "check-122514");
|
||||
}
|
||||
{
|
||||
lines.Clear();
|
||||
string workItemType = "Feature";
|
||||
lines.Add($"# {nameof(FeatureCheckPriority126169)}");
|
||||
lines.Add(string.Empty);
|
||||
results = FeatureCheckPriority126169(url, lines, bugUserStoryWorkItemTypes, records, workItemType);
|
||||
WriteFiles(destinationDirectory, new(lines), results, "check-126169");
|
||||
}
|
||||
{
|
||||
lines.Clear();
|
||||
string workItemType = "Feature";
|
||||
lines.Add($"# {nameof(FeatureCheckState123066)}");
|
||||
lines.Add(string.Empty);
|
||||
results = FeatureCheckState123066(url, lines, bugUserStoryTaskWorkItemTypes, records, workItemType);
|
||||
WriteFiles(destinationDirectory, new(lines), results, "check-123066");
|
||||
}
|
||||
{
|
||||
lines.Clear();
|
||||
string workItemType = "Feature";
|
||||
lines.Add($"# {nameof(FeatureCheckState123067)}");
|
||||
lines.Add(string.Empty);
|
||||
results = FeatureCheckState123067(url, lines, bugUserStoryTaskWorkItemTypes, records, workItemType);
|
||||
WriteFiles(destinationDirectory, new(lines), results, "check-123067");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Collections.ObjectModel;
|
||||
namespace File_Folder_Helper.Day.Q32024;
|
||||
namespace File_Folder_Helper.ADO2024.PI3;
|
||||
|
||||
internal static partial class Helper20240916
|
||||
{
|
@ -2,7 +2,7 @@ using Microsoft.Extensions.Logging;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
namespace File_Folder_Helper.Day.Q32024;
|
||||
namespace File_Folder_Helper.ADO2024.PI3;
|
||||
|
||||
internal static partial class Helper20240925
|
||||
{
|
@ -2,7 +2,7 @@ using Microsoft.Extensions.Logging;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
namespace File_Folder_Helper.Day.Q42024;
|
||||
namespace File_Folder_Helper.ADO2024.PI3;
|
||||
|
||||
internal static partial class Helper20241002
|
||||
{
|
||||
@ -68,6 +68,30 @@ internal static partial class Helper20241002
|
||||
return result;
|
||||
}
|
||||
|
||||
private static ReadOnlyDictionary<string, Record> GetKeyValuePairs(ReadOnlyDictionary<string, Record> keyValuePairs)
|
||||
{
|
||||
Dictionary<string, Record> results = [];
|
||||
Record result;
|
||||
Record record;
|
||||
string? calculation;
|
||||
foreach (KeyValuePair<string, Record> keyValuePair in keyValuePairs)
|
||||
{
|
||||
record = keyValuePair.Value;
|
||||
calculation = record.RawCalculation;
|
||||
if (calculation is not null)
|
||||
{
|
||||
foreach (KeyValuePair<string, Record> kVP in keyValuePairs)
|
||||
calculation = calculation.Replace(kVP.Key, $"%DCS(Value, {kVP.Value.Test})");
|
||||
}
|
||||
result = Record.Get(record, calculation);
|
||||
results.Add(keyValuePair.Key, result);
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static string GetKey(Record record) =>
|
||||
$"ch({record.Id + 1})";
|
||||
|
||||
private static ReadOnlyCollection<Record> GetRecords(string sourceDirectory, string searchPattern, string searchPatternB, string searchPatternC)
|
||||
{
|
||||
List<Record> results = [];
|
||||
@ -112,9 +136,6 @@ internal static partial class Helper20241002
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static string GetKey(Record record) =>
|
||||
$"ch({record.Id + 1})";
|
||||
|
||||
private static ReadOnlyDictionary<string, Record> GetKeyValuePairs(ReadOnlyCollection<Record> records)
|
||||
{
|
||||
Dictionary<string, Record> results = [];
|
||||
@ -133,27 +154,6 @@ internal static partial class Helper20241002
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static ReadOnlyDictionary<string, Record> GetKeyValuePairs(ReadOnlyDictionary<string, Record> keyValuePairs)
|
||||
{
|
||||
Dictionary<string, Record> results = [];
|
||||
Record result;
|
||||
Record record;
|
||||
string? calculation;
|
||||
foreach (KeyValuePair<string, Record> keyValuePair in keyValuePairs)
|
||||
{
|
||||
record = keyValuePair.Value;
|
||||
calculation = record.RawCalculation;
|
||||
if (calculation is not null)
|
||||
{
|
||||
foreach (KeyValuePair<string, Record> kVP in keyValuePairs)
|
||||
calculation = calculation.Replace(kVP.Key, $"%DCS(Value, {kVP.Value.Test})");
|
||||
}
|
||||
result = Record.Get(record, calculation);
|
||||
results.Add(keyValuePair.Key, result);
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
internal static void ConvertInfinityQSProjectFiles(ILogger<Worker> logger, List<string> args)
|
||||
{
|
||||
string searchPattern = args[2];
|
@ -1,7 +1,7 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q32024.WIQL;
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WIQL;
|
||||
|
||||
public class Column
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q32024.WIQL;
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WIQL;
|
||||
|
||||
public class Field
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q32024.WIQL;
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WIQL;
|
||||
|
||||
public class Root
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q32024.WIQL;
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WIQL;
|
||||
|
||||
public class SortColumn
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q32024.WIQL;
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WIQL;
|
||||
|
||||
public class WorkItem
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q32024.WorkItems;
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WorkItems;
|
||||
|
||||
public class Avatar
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q32024.WorkItems;
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WorkItems;
|
||||
|
||||
public class CommentVersionRef
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q32024.WorkItems;
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WorkItems;
|
||||
|
||||
public class CustomRequester
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q32024.WorkItems;
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WorkItems;
|
||||
|
||||
public class Fields
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q32024.WorkItems;
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WorkItems;
|
||||
|
||||
public class Html
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q32024.WorkItems;
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WorkItems;
|
||||
|
||||
public class Links
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q32024.WorkItems;
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WorkItems;
|
||||
|
||||
public class SystemAssignedTo
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q32024.WorkItems;
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WorkItems;
|
||||
|
||||
public class SystemChangedBy
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q32024.WorkItems;
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WorkItems;
|
||||
|
||||
public class SystemCreatedBy
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q32024.WorkItems;
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WorkItems;
|
||||
|
||||
public class Value
|
||||
{
|
@ -1,5 +1,5 @@
|
||||
#if WorkItems
|
||||
namespace File_Folder_Helper.Day.Q32024.WorkItems;
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WorkItems;
|
||||
|
||||
public class ValueWithReq
|
||||
{
|
@ -34,85 +34,85 @@ internal static class HelperDay
|
||||
else if (args[1] == "Day-Helper-2023-12-22")
|
||||
Day.Q42023.Helper20231222.ConvertId(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-01-05")
|
||||
Day.Q12024.Helper20240105.ConvertKeePassExport(logger, args);
|
||||
ADO2024.PI1.Helper20240105.ConvertKeePassExport(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-01-06")
|
||||
Day.Q12024.Helper20240106.TextToJson(logger, args);
|
||||
ADO2024.PI1.Helper20240106.TextToJson(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-01-07")
|
||||
Day.Q12024.Helper20240107.DirectoryToISO(logger, args);
|
||||
ADO2024.PI1.Helper20240107.DirectoryToISO(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-01-08")
|
||||
Day.Q12024.Helper20240108.SortCodeMethods(logger, args, cancellationToken);
|
||||
ADO2024.PI1.Helper20240108.SortCodeMethods(logger, args, cancellationToken);
|
||||
else if (args[1] == "Day-Helper-2024-01-27")
|
||||
logger.LogError("{arg} - has been migrated to Clipboard_Send_Keys", args[1]);
|
||||
else if (args[1] == "Day-Helper-2024-01-29")
|
||||
Day.Q12024.Helper20240129.JsonToTsv(logger, args);
|
||||
ADO2024.PI1.Helper20240129.JsonToTsv(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-03-05")
|
||||
Day.Q12024.Helper20240305.ArchiveFiles(logger, args);
|
||||
ADO2024.PI1.Helper20240305.ArchiveFiles(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-04-03")
|
||||
Day.Q22024.Helper20240403.AlertIfNewDeviceIsConnected(logger, args);
|
||||
ADO2024.PI1.Helper20240403.AlertIfNewDeviceIsConnected(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-04-04")
|
||||
Day.Q22024.Helper20240404.ParseCSV(logger, args);
|
||||
ADO2024.PI1.Helper20240404.ParseCSV(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-04-09")
|
||||
Day.Q22024.Helper20240409.MonA(logger, args);
|
||||
ADO2024.PI1.Helper20240409.MonA(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-04-17")
|
||||
Day.Q22024.Helper20240417.FilteredRunCommand(logger, args, cancellationToken);
|
||||
ADO2024.PI1.Helper20240417.FilteredRunCommand(logger, args, cancellationToken);
|
||||
else if (args[1] == "Day-Helper-2024-04-26")
|
||||
Day.Q22024.Helper20240426.UpdateTests(logger, args);
|
||||
ADO2024.PI1.Helper20240426.UpdateTests(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-04-27")
|
||||
Day.Q22024.Helper20240427.Immich(appSettings, logger, args);
|
||||
ADO2024.PI1.Helper20240427.Immich(appSettings, logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-04-29")
|
||||
Day.Q22024.Helper20240429.GitConfigCleanUp(logger, args);
|
||||
ADO2024.PI2.Helper20240429.GitConfigCleanUp(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-05-10")
|
||||
Day.Q22024.Helper20240510.PullIconsForBLM(logger, args);
|
||||
ADO2024.PI2.Helper20240510.PullIconsForBLM(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-05-13")
|
||||
Day.Q22024.Helper20240513.PersonKeyToName(logger, args);
|
||||
ADO2024.PI2.Helper20240513.PersonKeyToName(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-05-17")
|
||||
Day.Q22024.Helper20240517.SaveAmazon(logger, args);
|
||||
ADO2024.PI2.Helper20240517.SaveAmazon(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-05-18")
|
||||
Day.Q22024.Helper20240518.PersonKeyToImmichImport(logger, args);
|
||||
ADO2024.PI2.Helper20240518.PersonKeyToImmichImport(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-05-19")
|
||||
Day.Q22024.Helper20240519.FindReplaceDirectoryName(logger, args);
|
||||
ADO2024.PI2.Helper20240519.FindReplaceDirectoryName(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-05-20")
|
||||
Day.Q22024.Helper20240520.IdentifierRename(logger, args);
|
||||
ADO2024.PI2.Helper20240520.IdentifierRename(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-06-23")
|
||||
Day.Q22024.Helper20240623.UpdateSubTasksInMarkdownFiles(logger, args);
|
||||
ADO2024.PI2.Helper20240623.UpdateSubTasksInMarkdownFiles(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-06-24")
|
||||
Day.Q22024.Helper20240624.MoveUpOneDirectory(logger, args);
|
||||
ADO2024.PI2.Helper20240624.MoveUpOneDirectory(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-07-11")
|
||||
Day.Q32024.Helper20240711.GitRemoteRemove(logger, args);
|
||||
ADO2024.PI2.Helper20240711.GitRemoteRemove(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-07-18")
|
||||
Day.Q32024.Helper20240718.JsonToMarkdown(logger, args);
|
||||
ADO2024.PI2.Helper20240718.JsonToMarkdown(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-07-24")
|
||||
Day.Q32024.Helper20240724.CopyDirectories(logger, args);
|
||||
ADO2024.PI2.Helper20240724.CopyDirectories(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-07-28")
|
||||
Day.Q32024.Helper20240728.DownloadSslCertificates(logger, args);
|
||||
ADO2024.PI2.Helper20240728.DownloadSslCertificates(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-08-05")
|
||||
Day.Q32024.Helper20240805.RenameFiles(logger, args);
|
||||
ADO2024.PI3.Helper20240805.RenameFiles(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-08-06")
|
||||
Day.Q32024.Helper20240806.ArchiveFiles(logger, args);
|
||||
ADO2024.PI3.Helper20240806.ArchiveFiles(logger, args);
|
||||
#if WorkItems
|
||||
else if (args[1] == "Day-Helper-2024-08-09")
|
||||
Day.Q32024.Helper20240809.CreateWorkItems(logger, args);
|
||||
ADO2024.PI3.Helper20240809.CreateWorkItems(logger, args);
|
||||
#endif
|
||||
else if (args[1] == "Day-Helper-2024-08-20")
|
||||
Day.Q32024.Helper20240820.MoveFilesWithSleep(logger, args);
|
||||
ADO2024.PI3.Helper20240820.MoveFilesWithSleep(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-08-22")
|
||||
Day.Q32024.Helper20240822.ParseKanbn(logger, args);
|
||||
ADO2024.PI3.Helper20240822.ParseKanbn(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-08-28")
|
||||
Day.Q32024.Helper20240828.MoveWaferCounterToArchive(logger, args);
|
||||
ADO2024.PI3.Helper20240828.MoveWaferCounterToArchive(logger, args);
|
||||
#if WorkItems
|
||||
else if (args[1] == "Day-Helper-2024-08-30")
|
||||
Day.Q32024.Helper20240830.CompareWorkItems(logger, args);
|
||||
ADO2024.PI3.Helper20240830.CompareWorkItems(logger, args);
|
||||
#endif
|
||||
else if (args[1] == "Day-Helper-2024-09-10")
|
||||
Day.Q32024.Helper20240910.MoveFilesToWeekOfYear(logger, args);
|
||||
ADO2024.PI3.Helper20240910.MoveFilesToWeekOfYear(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-09-11")
|
||||
Day.Q32024.Helper20240911.WriteMarkdown(logger, args);
|
||||
ADO2024.PI3.Helper20240911.WriteMarkdown(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-09-16")
|
||||
Day.Q32024.Helper20240916.DebugProxyPass(logger, args);
|
||||
ADO2024.PI3.Helper20240916.DebugProxyPass(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-09-25")
|
||||
Day.Q32024.Helper20240925.DistinctTests(logger, args);
|
||||
ADO2024.PI3.Helper20240925.DistinctTests(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-10-02")
|
||||
Day.Q42024.Helper20241002.ConvertInfinityQSProjectFiles(logger, args);
|
||||
ADO2024.PI3.Helper20241002.ConvertInfinityQSProjectFiles(logger, args);
|
||||
else
|
||||
throw new Exception(appSettings.Company);
|
||||
}
|
||||
|
@ -1,705 +0,0 @@
|
||||
#if WorkItems
|
||||
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;
|
||||
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;
|
||||
|
||||
namespace File_Folder_Helper.Day.Q32024;
|
||||
|
||||
internal static partial class Helper20240809
|
||||
{
|
||||
|
||||
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<string, FIBacklogMesa> GetFIBacklogMesaCollection(string json)
|
||||
{
|
||||
Dictionary<string, FIBacklogMesa> 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<HttpResponseMessage> httpResponseMessageTask = httpClient.GetAsync(string.Concat(basePage, api, query));
|
||||
httpResponseMessageTask.Wait();
|
||||
if (!httpResponseMessageTask.Result.IsSuccessStatusCode)
|
||||
throw new Exception(httpResponseMessageTask.Result.StatusCode.ToString());
|
||||
Task<Stream> 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<ValueWithReq> GetWorkItems(HttpClient httpClient, string basePage, string api, string sourceDirectory, string ids)
|
||||
{
|
||||
List<ValueWithReq> results = [];
|
||||
int req;
|
||||
string json;
|
||||
string file;
|
||||
Value? value;
|
||||
string[] segments;
|
||||
JsonElement[] jsonElements;
|
||||
Task<HttpResponseMessage> httpResponseMessageTask = httpClient.GetAsync(string.Concat(basePage, api, $"/workitems?ids={ids}"));
|
||||
httpResponseMessageTask.Wait();
|
||||
if (!httpResponseMessageTask.Result.IsSuccessStatusCode)
|
||||
throw new Exception(httpResponseMessageTask.Result.StatusCode.ToString());
|
||||
Task<Stream> streamTask = httpResponseMessageTask.Result.Content.ReadAsStreamAsync();
|
||||
streamTask.Wait();
|
||||
if (!streamTask.Result.CanRead)
|
||||
throw new NullReferenceException(nameof(streamTask));
|
||||
JsonElement? result = JsonSerializer.Deserialize<JsonElement>(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<ValueWithReq> RemoveFrom(Dictionary<string, FIBacklogMesa> keyToFIBacklogMesa, ReadOnlyCollection<ValueWithReq> valueWithReqCollection)
|
||||
{
|
||||
List<ValueWithReq> results = [];
|
||||
foreach (ValueWithReq valueWithReq in valueWithReqCollection)
|
||||
{
|
||||
if (keyToFIBacklogMesa.Remove($"{valueWithReq.Req} - "))
|
||||
continue;
|
||||
results.Add(valueWithReq);
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<Models.Comment> GetComments(HttpClient httpClient, string basePage, string api, string sourceDirectory, int req, int id)
|
||||
{
|
||||
List<Models.Comment> results = [];
|
||||
string json;
|
||||
string file;
|
||||
Models.Comment? comment;
|
||||
JsonElement[] jsonElements;
|
||||
Task<HttpResponseMessage> 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<Stream> streamTask = httpResponseMessageTask.Result.Content.ReadAsStreamAsync();
|
||||
streamTask.Wait();
|
||||
if (!streamTask.Result.CanRead)
|
||||
throw new NullReferenceException(nameof(streamTask));
|
||||
JsonElement? result = JsonSerializer.Deserialize<JsonElement>(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}<br> <br>{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<HttpResponseMessage> httpResponseMessageTask = httpClient.PatchAsync(requestUri, stringContent);
|
||||
httpResponseMessageTask.Wait();
|
||||
if (!httpResponseMessageTask.Result.IsSuccessStatusCode)
|
||||
throw new Exception(httpResponseMessageTask.Result.StatusCode.ToString());
|
||||
Task<Stream> streamTask = httpResponseMessageTask.Result.Content.ReadAsStreamAsync();
|
||||
streamTask.Wait();
|
||||
if (!streamTask.Result.CanRead)
|
||||
throw new NullReferenceException(nameof(streamTask));
|
||||
JsonElement? result = JsonSerializer.Deserialize<JsonElement>(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<string, FIBacklogMesa> keyToFIBacklogMesa,
|
||||
ReadOnlyCollection<ValueWithReq> valueWithReqCollection)
|
||||
{
|
||||
string key;
|
||||
FIBacklogMesa? fIBacklogMesa;
|
||||
ReadOnlyCollection<Models.Comment> 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<HttpResponseMessage> httpResponseMessageTask = httpClient.PatchAsync(requestUri, stringContent);
|
||||
httpResponseMessageTask.Wait();
|
||||
if (!httpResponseMessageTask.Result.IsSuccessStatusCode)
|
||||
throw new Exception(httpResponseMessageTask.Result.StatusCode.ToString());
|
||||
Task<Stream> streamTask = httpResponseMessageTask.Result.Content.ReadAsStreamAsync();
|
||||
streamTask.Wait();
|
||||
if (!streamTask.Result.CanRead)
|
||||
throw new NullReferenceException(nameof(streamTask));
|
||||
JsonElement? result = JsonSerializer.Deserialize<JsonElement>(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<ValueWithReq> 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<string, string> assignedToNameToUser, ReadOnlyDictionary<string, string> requestorNameToUser, Task<WorkItem>? 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}<br> <br>{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<string, string> requestorNameToUser, ReadOnlyDictionary<string, string> assignedToNameToUser, List<string> tags, Task<WorkItem>? 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}<br> <br>{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<string> GetTags(FIBacklogMesa fiBacklogMesa)
|
||||
{
|
||||
List<string> results = [];
|
||||
foreach (string tag in fiBacklogMesa.SystemS.Split('/'))
|
||||
{
|
||||
if (string.IsNullOrEmpty(tag.Trim()))
|
||||
continue;
|
||||
results.Add(tag.Trim());
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static List<string> GetTags(Fields fields)
|
||||
{
|
||||
List<string> 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<string, string> assignedToNameToUser, ReadOnlyDictionary<string, string> requestorNameToUser, FIBacklogMesa fiBacklogMesa)
|
||||
{
|
||||
DateTime submittedDateTime;
|
||||
JsonPatchDocument tagDocument;
|
||||
Task<WorkItem>? workItem = null;
|
||||
List<string> 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<WorkItem>? uatWorkItemTask = null;
|
||||
JsonPatchDocument bugDocument = GetBugDocument(project, site, requestorNameToUser, assignedToNameToUser, uatWorkItemTask, fiBacklogMesa, submittedDateTime);
|
||||
workItem = workItemTrackingHttpClient.CreateWorkItemAsync(bugDocument, project, "Bug");
|
||||
workItem.Wait();
|
||||
}
|
||||
if (!isBugFix)
|
||||
{
|
||||
Task<WorkItem>? 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<HttpResponseMessage> httpResponseMessageTask = httpClient.PatchAsync(string.Concat(basePage, api, query), httpContent);
|
||||
httpResponseMessageTask.Wait();
|
||||
if (!httpResponseMessageTask.Result.IsSuccessStatusCode)
|
||||
throw new Exception(httpResponseMessageTask.Result.StatusCode.ToString());
|
||||
Task<string> 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> 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<string, string> assignedToNameToUser,
|
||||
ReadOnlyDictionary<string, string> requestorNameToUser,
|
||||
Dictionary<string, FIBacklogMesa> keyToFIBacklogMesa,
|
||||
ReadOnlyCollection<ValueWithReq> valueWithReqCollection)
|
||||
{
|
||||
int result = 0;
|
||||
string key;
|
||||
string title;
|
||||
int priority;
|
||||
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} - ";
|
||||
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<string, string> assignedToNameToUser,
|
||||
ReadOnlyDictionary<string, string> requestorNameToUser,
|
||||
string json)
|
||||
{
|
||||
int counter = 0;
|
||||
string ids = GetIds(httpClient, basePage, api, query);
|
||||
Dictionary<string, FIBacklogMesa> keyToFIBacklogMesa = GetFIBacklogMesaCollection(json);
|
||||
ReadOnlyCollection<ValueWithReq> 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<ValueWithReq> extra = RemoveFrom(keyToFIBacklogMesa, valueWithReqCollection);
|
||||
foreach (KeyValuePair<string, FIBacklogMesa> 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<Worker> 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<string, string> requestorNameToUser = GetRequestorNameToUser(requestorNames);
|
||||
ReadOnlyDictionary<string, string> 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<string, string> GetAssignedToNameToUser(string[] assignedToNames)
|
||||
{
|
||||
Dictionary<string, string> 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<string, string> GetRequestorNameToUser(string[] requestorNames)
|
||||
{
|
||||
Dictionary<string, string> 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<Worker> logger, List<string> 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<WorkItemTrackingHttpClient>();
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
@ -1,427 +0,0 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
namespace File_Folder_Helper.Day.Q32024;
|
||||
|
||||
internal static partial class Helper20240911
|
||||
{
|
||||
|
||||
public record Attribute([property: JsonPropertyName("isLocked")] bool IsLocked,
|
||||
[property: JsonPropertyName("name")] string Name);
|
||||
|
||||
public record Relation([property: JsonPropertyName("rel")] string Type,
|
||||
[property: JsonPropertyName("url")] string URL,
|
||||
[property: JsonPropertyName("attributes")] Attribute Attributes);
|
||||
|
||||
public record Record(WorkItem WorkItem, ReadOnlyDictionary<int, Record> Children);
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Record))]
|
||||
internal partial class RecordCommonSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
public record WorkItem(string AreaPath,
|
||||
string? AssignedTo,
|
||||
int? BusinessValue,
|
||||
DateTime ChangedDate,
|
||||
DateTime? ClosedDate,
|
||||
int CommentCount,
|
||||
DateTime CreatedDate,
|
||||
string Description,
|
||||
float? Effort,
|
||||
int Id,
|
||||
string IterationPath,
|
||||
int? Parent,
|
||||
int? Priority,
|
||||
Relation[] Relations,
|
||||
string? Requester,
|
||||
DateTime? ResolvedDate,
|
||||
int Revision,
|
||||
int? RiskReductionMinusOpportunityEnablement,
|
||||
DateTime? StartDate,
|
||||
string State,
|
||||
string Tags,
|
||||
DateTime? TargetDate,
|
||||
float? TimeCriticality,
|
||||
string Title,
|
||||
string WorkItemType,
|
||||
float? WeightedShortestJobFirst);
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(WorkItem))]
|
||||
internal partial class WorkItemSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
private static ReadOnlyDictionary<int, WorkItem> GetWorkItems(string filterDirectory, string[] files)
|
||||
{
|
||||
Dictionary<int, WorkItem> results = [];
|
||||
string json;
|
||||
WorkItem? workItem;
|
||||
string? directoryName;
|
||||
foreach (string file in files)
|
||||
{
|
||||
directoryName = Path.GetDirectoryName(file);
|
||||
if (string.IsNullOrEmpty(directoryName))
|
||||
continue;
|
||||
if (!directoryName.EndsWith(filterDirectory))
|
||||
continue;
|
||||
json = File.ReadAllText(file);
|
||||
workItem = JsonSerializer.Deserialize(json, WorkItemSourceGenerationContext.Default.WorkItem);
|
||||
if (workItem is null)
|
||||
continue;
|
||||
results.Add(workItem.Id, workItem);
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static int? GetIdFromUrlIfChild(Relation relation)
|
||||
{
|
||||
int? result;
|
||||
string[] segments = relation?.Attributes is null || relation.Attributes.Name != "Child" ? [] : relation.URL.Split('/');
|
||||
if (segments.Length < 2)
|
||||
result = null;
|
||||
else
|
||||
{
|
||||
if (!int.TryParse(segments[^1], out int id))
|
||||
result = null;
|
||||
else
|
||||
result = id;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Dictionary<int, Record> GetKeyValuePairs(ReadOnlyDictionary<int, WorkItem> workItems, WorkItem workItem)
|
||||
{
|
||||
Dictionary<int, Record> results = [];
|
||||
int? childId;
|
||||
WorkItem? childWorkItem;
|
||||
List<WorkItem> collection = [];
|
||||
Dictionary<int, Record> keyValuePairs;
|
||||
if (workItem.Relations is not null && workItem.Relations.Length > 0)
|
||||
{
|
||||
collection.Clear();
|
||||
foreach (Relation relation in workItem.Relations)
|
||||
{
|
||||
childId = GetIdFromUrlIfChild(relation);
|
||||
if (childId is null || !workItems.TryGetValue(childId.Value, out childWorkItem))
|
||||
continue;
|
||||
collection.Add(childWorkItem);
|
||||
}
|
||||
collection = (from l in collection orderby l.State != "Closed", l.Id select l).ToList();
|
||||
foreach (WorkItem item in collection)
|
||||
{
|
||||
keyValuePairs = GetKeyValuePairs(workItems, item);
|
||||
results.Add(item.Id, new(item, new(keyValuePairs)));
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static ReadOnlyDictionary<int, Record> GetWorkItemAndChildren(ReadOnlyDictionary<int, WorkItem> workItems)
|
||||
{
|
||||
Dictionary<int, Record> results = [];
|
||||
Dictionary<int, Record> keyValuePairs;
|
||||
foreach (KeyValuePair<int, WorkItem> keyValuePair in workItems)
|
||||
{
|
||||
keyValuePairs = GetKeyValuePairs(workItems, keyValuePair.Value);
|
||||
results.Add(keyValuePair.Key, new(keyValuePair.Value, new(keyValuePairs)));
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static string GetClosed(WorkItem workItem)
|
||||
{
|
||||
string result = workItem.State != "Closed" ? "[ ]" : "[x]";
|
||||
return result;
|
||||
}
|
||||
|
||||
private static string GetLine(List<char> spaces, WorkItem workItem, KeyValuePair<int, Record> keyValuePair, bool condensed, bool sprintOnly) =>
|
||||
sprintOnly ? $"\t- [ ] {workItem.IterationPath}" :
|
||||
condensed ? $"{new string(spaces.Skip(1).ToArray())}- {GetClosed(workItem)} {keyValuePair.Key} - {workItem.Title}" :
|
||||
$"{new string(spaces.Skip(1).ToArray())}- {GetClosed(workItem)} {keyValuePair.Key} - {workItem.Title} ~~~ {workItem.AssignedTo} - {workItem.IterationPath.Replace('\\', '-')} - {workItem.CreatedDate} --- {workItem.ClosedDate}";
|
||||
|
||||
private static void AppendLines(List<char> spaces, List<string> lines, Record record, bool condensed, bool sprintOnly)
|
||||
{
|
||||
string line;
|
||||
spaces.Add('\t');
|
||||
WorkItem workItem;
|
||||
foreach (KeyValuePair<int, Record> keyValuePair in record.Children)
|
||||
{
|
||||
workItem = keyValuePair.Value.WorkItem;
|
||||
line = GetLine(spaces, workItem, keyValuePair, condensed, sprintOnly).TrimEnd();
|
||||
lines.Add(line);
|
||||
AppendLines(spaces, lines, keyValuePair.Value, condensed, sprintOnly);
|
||||
}
|
||||
spaces.RemoveAt(0);
|
||||
}
|
||||
|
||||
private static void AppendLines(string url, List<char> spaces, List<string> lines, ReadOnlyDictionary<int, Record> workItemAndChildren, string workItemType)
|
||||
{
|
||||
List<string> results = [];
|
||||
WorkItem workItem;
|
||||
string? maxIterationPath;
|
||||
List<string> distinct = [];
|
||||
foreach (KeyValuePair<int, Record> keyValuePair in workItemAndChildren)
|
||||
{
|
||||
workItem = keyValuePair.Value.WorkItem;
|
||||
// if (keyValuePair.Key != 109724)
|
||||
// continue;
|
||||
if (workItem.WorkItemType != workItemType)
|
||||
continue;
|
||||
results.Add($"## {workItem.AssignedTo} - {workItem.Id} - {workItem.Title}");
|
||||
results.Add(string.Empty);
|
||||
results.Add($"- [{workItem.Id}]({url}{workItem.Id})");
|
||||
if (keyValuePair.Value.Children.Count == 0)
|
||||
results.Add(string.Empty);
|
||||
else
|
||||
{
|
||||
AppendLines(spaces, results, keyValuePair.Value, condensed: true, sprintOnly: false);
|
||||
results.Add(string.Empty);
|
||||
distinct.Clear();
|
||||
AppendLines(spaces, distinct, keyValuePair.Value, condensed: false, sprintOnly: true);
|
||||
if (distinct.Count > 1)
|
||||
{
|
||||
results.Add($"## Distinct Iteration Path(s) - {workItem.WorkItemType} - {workItem.AssignedTo} - {workItem.Id} - {workItem.Title} - {workItem.IterationPath}");
|
||||
results.Add(string.Empty);
|
||||
results.Add($"- [{workItem.Id}]({url}{workItem.Id})");
|
||||
distinct.Sort();
|
||||
distinct = (from l in distinct select l.Trim()).Distinct().ToList();
|
||||
results.AddRange(distinct);
|
||||
results.Add(string.Empty);
|
||||
maxIterationPath = distinct.Max();
|
||||
if (!string.IsNullOrEmpty(maxIterationPath) && maxIterationPath.Contains("] ") && maxIterationPath.Split(']')[1].Trim() != workItem.IterationPath)
|
||||
{
|
||||
results.Add($"### Sync to Distinct Max Iteration Path => {maxIterationPath} - {workItem.Id} - {workItem.Title}");
|
||||
results.Add(string.Empty);
|
||||
}
|
||||
}
|
||||
results.Add($"## Extended - {workItem.Id} - {workItem.Title}");
|
||||
results.Add(string.Empty);
|
||||
AppendLines(spaces, results, keyValuePair.Value, condensed: false, sprintOnly: false);
|
||||
results.Add(string.Empty);
|
||||
}
|
||||
lines.AddRange(results);
|
||||
results.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteFiles(string destinationDirectory, string fileName, ReadOnlyCollection<string> lines)
|
||||
{
|
||||
string text = string.Join(Environment.NewLine, lines);
|
||||
string markdownFile = Path.Combine(destinationDirectory, $"{fileName}.md");
|
||||
string textOld = !File.Exists(markdownFile) ? string.Empty : File.ReadAllText(markdownFile);
|
||||
if (text != textOld)
|
||||
File.WriteAllText(markdownFile, text);
|
||||
string html = CommonMark.CommonMarkConverter.Convert(text);
|
||||
string htmlFile = Path.Combine(destinationDirectory, $"{fileName}.html");
|
||||
string htmlOld = !File.Exists(htmlFile) ? string.Empty : File.ReadAllText(htmlFile);
|
||||
if (html != htmlOld)
|
||||
File.WriteAllText(htmlFile, html);
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<WorkItem> FilterChildren(Record record, ReadOnlyCollection<string> workItemTypes)
|
||||
{
|
||||
List<WorkItem> results = [];
|
||||
WorkItem workItem;
|
||||
foreach (KeyValuePair<int, Record> keyValuePair in record.Children)
|
||||
{
|
||||
workItem = keyValuePair.Value.WorkItem;
|
||||
if (!workItemTypes.Contains(workItem.WorkItemType))
|
||||
continue;
|
||||
results.Add(workItem);
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static string? GetMaxIterationPath(ReadOnlyCollection<WorkItem> workItems)
|
||||
{
|
||||
string? result;
|
||||
List<string> results = [];
|
||||
foreach (WorkItem workItem in workItems)
|
||||
{
|
||||
if (results.Contains(workItem.IterationPath))
|
||||
continue;
|
||||
results.Add(workItem.IterationPath);
|
||||
}
|
||||
result = results.Count == 0 ? null : results.Max();
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void FeatureCheckIterationPath(string url, List<string> lines, ReadOnlyCollection<string> workItemTypes, ReadOnlyDictionary<int, Record> workItemAndChildren, string workItemType)
|
||||
{
|
||||
WorkItem workItem;
|
||||
string? maxIterationPath;
|
||||
List<string> results = [];
|
||||
ReadOnlyCollection<WorkItem> workItems;
|
||||
foreach (KeyValuePair<int, Record> keyValuePair in workItemAndChildren)
|
||||
{
|
||||
workItem = keyValuePair.Value.WorkItem;
|
||||
if (workItem.WorkItemType != workItemType)
|
||||
continue;
|
||||
results.Clear();
|
||||
if (keyValuePair.Value.Children.Count == 0)
|
||||
continue;
|
||||
workItems = FilterChildren(keyValuePair.Value, workItemTypes);
|
||||
maxIterationPath = GetMaxIterationPath(workItems);
|
||||
if (string.IsNullOrEmpty(maxIterationPath) || workItem.IterationPath == maxIterationPath)
|
||||
continue;
|
||||
results.Add($"## {workItem.AssignedTo} - {workItem.Id} - {workItem.Title}");
|
||||
results.Add(string.Empty);
|
||||
results.Add($"- [{workItem.Id}]({url}{workItem.Id})");
|
||||
results.Add($"- [ ] {workItem.Id} => {workItem.IterationPath} != {maxIterationPath}");
|
||||
results.Add(string.Empty);
|
||||
lines.AddRange(results);
|
||||
}
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<int> GetIdsNotMatching(string tags, ReadOnlyCollection<WorkItem> workItems)
|
||||
{
|
||||
List<int> results = [];
|
||||
string[] segments;
|
||||
string[] parentTags = tags.Split(';');
|
||||
foreach (WorkItem workItem in workItems)
|
||||
{
|
||||
segments = tags.Split(';');
|
||||
if (segments.Length > 0 && parentTags.Any(l => segments.Contains(l)))
|
||||
continue;
|
||||
results.Add(workItem.Id);
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static void FeatureCheckTag(string url, List<string> lines, ReadOnlyCollection<string> workItemTypes, ReadOnlyDictionary<int, Record> workItemAndChildren, string workItemType)
|
||||
{
|
||||
WorkItem workItem;
|
||||
List<string> results = [];
|
||||
ReadOnlyCollection<int> idsNotMatching;
|
||||
ReadOnlyCollection<WorkItem> workItems;
|
||||
foreach (KeyValuePair<int, Record> keyValuePair in workItemAndChildren)
|
||||
{
|
||||
workItem = keyValuePair.Value.WorkItem;
|
||||
if (workItem.WorkItemType != workItemType)
|
||||
continue;
|
||||
results.Clear();
|
||||
if (keyValuePair.Value.Children.Count == 0)
|
||||
continue;
|
||||
if (string.IsNullOrEmpty(workItem.Tags))
|
||||
idsNotMatching = new([workItem.Id]);
|
||||
else
|
||||
{
|
||||
workItems = FilterChildren(keyValuePair.Value, workItemTypes);
|
||||
idsNotMatching = GetIdsNotMatching(workItem.Tags, workItems);
|
||||
if (!string.IsNullOrEmpty(workItem.Tags) && idsNotMatching.Count == 0)
|
||||
continue;
|
||||
}
|
||||
results.Add($"## {workItem.AssignedTo} - {workItem.Id} - {workItem.Title}");
|
||||
results.Add(string.Empty);
|
||||
results.Add($"- [{workItem.Id}]({url}{workItem.Id})");
|
||||
foreach (int id in idsNotMatching)
|
||||
results.Add($"- [ ] {id} {nameof(workItem.Tags)} != {workItem.Tags}");
|
||||
results.Add(string.Empty);
|
||||
lines.AddRange(results);
|
||||
}
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<int> GetIdsNotMatching(int? priority, ReadOnlyCollection<WorkItem> workItems)
|
||||
{
|
||||
List<int> results = [];
|
||||
foreach (WorkItem workItem in workItems)
|
||||
{
|
||||
if (workItem.Priority == priority)
|
||||
continue;
|
||||
results.Add(workItem.Id);
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static void FeatureCheckPriority(string url, List<string> lines, ReadOnlyCollection<string> workItemTypes, ReadOnlyDictionary<int, Record> workItemAndChildren, string workItemType)
|
||||
{
|
||||
WorkItem workItem;
|
||||
List<string> results = [];
|
||||
ReadOnlyCollection<int> idsNotMatching;
|
||||
ReadOnlyCollection<WorkItem> workItems;
|
||||
foreach (KeyValuePair<int, Record> keyValuePair in workItemAndChildren)
|
||||
{
|
||||
workItem = keyValuePair.Value.WorkItem;
|
||||
if (workItem.WorkItemType != workItemType)
|
||||
continue;
|
||||
results.Clear();
|
||||
if (keyValuePair.Value.Children.Count == 0)
|
||||
continue;
|
||||
workItems = FilterChildren(keyValuePair.Value, workItemTypes);
|
||||
idsNotMatching = GetIdsNotMatching(workItem.Priority, workItems);
|
||||
if (idsNotMatching.Count == 0)
|
||||
continue;
|
||||
results.Add($"## {workItem.AssignedTo} - {workItem.Id} - {workItem.Title}");
|
||||
results.Add(string.Empty);
|
||||
results.Add($"- [{workItem.Id}]({url}{workItem.Id})");
|
||||
foreach (int id in idsNotMatching)
|
||||
results.Add($"- [ ] {id} {nameof(workItem.Priority)} != {workItem.Priority}");
|
||||
results.Add(string.Empty);
|
||||
lines.AddRange(results);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void WriteMarkdown(ILogger<Worker> logger, List<string> args)
|
||||
{
|
||||
string url = args[6];
|
||||
List<char> spaces = [];
|
||||
List<string> lines = [];
|
||||
string searchPattern = args[2];
|
||||
string filterDirectory = args[3];
|
||||
string[] workItemTypes = args[4].Split('|');
|
||||
string sourceDirectory = Path.GetFullPath(args[0]);
|
||||
string destinationDirectory = Path.GetFullPath(args[5]);
|
||||
if (!Directory.Exists(destinationDirectory))
|
||||
_ = Directory.CreateDirectory(destinationDirectory);
|
||||
ReadOnlyCollection<string> userStoryWorkItemTypes = new(["User Story"]);
|
||||
ReadOnlyCollection<string> userStoryTaskWorkItemTypes = new(["User Story", "Task"]);
|
||||
string[] files = Directory.GetFiles(sourceDirectory, searchPattern, SearchOption.AllDirectories);
|
||||
logger.LogInformation("With search pattern '{SearchPattern}' found {files} file(s)", searchPattern, files.Length);
|
||||
ReadOnlyDictionary<int, WorkItem> workItems = GetWorkItems(filterDirectory, files);
|
||||
logger.LogInformation("With search pattern '{SearchPattern}' found {files} workItem(s)", searchPattern, workItems.Count);
|
||||
ReadOnlyDictionary<int, Record> workItemAndChildren = GetWorkItemAndChildren(workItems);
|
||||
logger.LogInformation("With search pattern '{SearchPattern}' found {files} workItemAndChildren", searchPattern, workItemAndChildren.Count);
|
||||
if (workItemAndChildren.Count == -1)
|
||||
{
|
||||
string json = JsonSerializer.Serialize(workItemAndChildren, RecordCommonSourceGenerationContext.Default.ReadOnlyDictionaryInt32Record);
|
||||
File.WriteAllText(".json", json);
|
||||
}
|
||||
foreach (string workItemType in workItemTypes)
|
||||
{
|
||||
lines.Clear();
|
||||
lines.Add("# WorkItems");
|
||||
lines.Add(string.Empty);
|
||||
AppendLines(url, spaces, lines, workItemAndChildren, workItemType);
|
||||
WriteFiles(destinationDirectory, workItemType, new(lines));
|
||||
}
|
||||
{
|
||||
lines.Clear();
|
||||
string workItemType = "Feature";
|
||||
lines.Add($"# {nameof(FeatureCheckIterationPath)}");
|
||||
lines.Add(string.Empty);
|
||||
FeatureCheckIterationPath(url, lines, userStoryTaskWorkItemTypes, workItemAndChildren, workItemType);
|
||||
WriteFiles(destinationDirectory, $"{nameof(FeatureCheckIterationPath)}", new(lines));
|
||||
}
|
||||
{
|
||||
lines.Clear();
|
||||
string workItemType = "Feature";
|
||||
lines.Add($"# {nameof(FeatureCheckTag)}");
|
||||
lines.Add(string.Empty);
|
||||
FeatureCheckTag(url, lines, userStoryWorkItemTypes, workItemAndChildren, workItemType);
|
||||
WriteFiles(destinationDirectory, $"{nameof(FeatureCheckTag)}", new(lines));
|
||||
}
|
||||
{
|
||||
lines.Clear();
|
||||
string workItemType = "Feature";
|
||||
lines.Add($"# {nameof(FeatureCheckPriority)}");
|
||||
lines.Add(string.Empty);
|
||||
FeatureCheckPriority(url, lines, userStoryWorkItemTypes, workItemAndChildren, workItemType);
|
||||
WriteFiles(destinationDirectory, $"{nameof(FeatureCheckPriority)}", new(lines));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user