Moved to ADO2024 PI#
Ran SortCodeMethods
This commit is contained in:
146
ADO2024/PI3/ConvertExcelToJson/FIBacklogMesa.cs
Normal file
146
ADO2024/PI3/ConvertExcelToJson/FIBacklogMesa.cs
Normal file
@ -0,0 +1,146 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.ADO2024.PI3.ConvertExcelToJson;
|
||||
|
||||
public class FIBacklogMesa
|
||||
{
|
||||
[JsonConstructor]
|
||||
public FIBacklogMesa(string req,
|
||||
string submitted,
|
||||
string requestor,
|
||||
string assignedTo,
|
||||
string secondResource,
|
||||
string subject,
|
||||
string systemS,
|
||||
string priority,
|
||||
string training,
|
||||
string prioritySubset,
|
||||
string status,
|
||||
string definition,
|
||||
string updates,
|
||||
string estEffortDays,
|
||||
string commitDate,
|
||||
string reCommitDate,
|
||||
string uATAsOf,
|
||||
string cmpDate,
|
||||
string f20,
|
||||
string f21,
|
||||
string f22,
|
||||
string f23,
|
||||
string f24,
|
||||
string f25,
|
||||
string f26,
|
||||
string f27,
|
||||
string f28,
|
||||
string f29,
|
||||
string f30,
|
||||
string f31,
|
||||
string f32,
|
||||
string f33)
|
||||
{
|
||||
Req = req;
|
||||
Submitted = submitted;
|
||||
Requestor = requestor;
|
||||
AssignedTo = assignedTo;
|
||||
SecondResource = secondResource;
|
||||
Subject = subject;
|
||||
SystemS = systemS;
|
||||
Priority = priority;
|
||||
Training = training;
|
||||
PrioritySubset = prioritySubset;
|
||||
Status = status;
|
||||
Definition = definition;
|
||||
Updates = updates;
|
||||
EstEffortDays = estEffortDays;
|
||||
CommitDate = commitDate;
|
||||
ReCommitDate = reCommitDate;
|
||||
UATAsOf = uATAsOf;
|
||||
CMPDate = cmpDate;
|
||||
F20 = f20;
|
||||
F21 = f21;
|
||||
F22 = f22;
|
||||
F23 = f23;
|
||||
F24 = f24;
|
||||
F25 = f25;
|
||||
F26 = f26;
|
||||
F27 = f27;
|
||||
F28 = f28;
|
||||
F29 = f29;
|
||||
F30 = f30;
|
||||
F31 = f31;
|
||||
F32 = f32;
|
||||
F33 = f33;
|
||||
}
|
||||
|
||||
public string Req { get; set; } // { init; get; }
|
||||
public string Submitted { get; set; } // { init; get; }
|
||||
public string Requestor { get; set; } // { init; get; }
|
||||
|
||||
[JsonPropertyName("Assigned To")]
|
||||
public string AssignedTo { get; set; } // { init; get; }
|
||||
|
||||
[JsonPropertyName("Second Resource")]
|
||||
public string SecondResource { get; set; } // { init; get; }
|
||||
|
||||
[JsonPropertyName("Subject - from Requestor")]
|
||||
public string Subject { get; set; } // { init; get; }
|
||||
|
||||
[JsonPropertyName("System(s)")]
|
||||
public string SystemS { get; set; } // { init; get; }
|
||||
|
||||
public string Priority { get; set; } // { init; get; }
|
||||
|
||||
[JsonPropertyName("Spec/ECN/Training")]
|
||||
public string Training { get; set; } // { init; get; }
|
||||
|
||||
[JsonPropertyName("Qual/Eff")]
|
||||
public string PrioritySubset { get; set; } // { init; get; }
|
||||
public string Status { get; set; } // { init; get; }
|
||||
|
||||
[JsonPropertyName("Definition - from FI")]
|
||||
public string Definition { get; set; } // { init; get; }
|
||||
public string Updates { get; set; } // { init; get; }
|
||||
|
||||
[JsonPropertyName("Est Effort _(days)")]
|
||||
public string EstEffortDays { get; set; } // { init; get; }
|
||||
|
||||
[JsonPropertyName("Commit Date")]
|
||||
public string CommitDate { get; set; } // { init; get; }
|
||||
|
||||
[JsonPropertyName("Re-Commit Date")]
|
||||
public string ReCommitDate { get; set; } // { init; get; }
|
||||
|
||||
[JsonPropertyName("UAT as of")]
|
||||
public string UATAsOf { get; set; } // { init; get; }
|
||||
|
||||
[JsonPropertyName("CMP _Date")]
|
||||
public string CMPDate { get; set; } // { init; get; }
|
||||
public string F20 { get; set; } // { init; get; }
|
||||
public string F21 { get; set; } // { init; get; }
|
||||
public string F22 { get; set; } // { init; get; }
|
||||
public string F23 { get; set; } // { init; get; }
|
||||
public string F24 { get; set; } // { init; get; }
|
||||
public string F25 { get; set; } // { init; get; }
|
||||
public string F26 { get; set; } // { init; get; }
|
||||
public string F27 { get; set; } // { init; get; }
|
||||
public string F28 { get; set; } // { init; get; }
|
||||
public string F29 { get; set; } // { init; get; }
|
||||
public string F30 { get; set; } // { init; get; }
|
||||
public string F31 { get; set; } // { init; get; }
|
||||
public string F32 { get; set; } // { init; get; }
|
||||
public string F33 { get; set; } // { init; get; }
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, PropertyNameCaseInsensitive = true)]
|
||||
[JsonSerializable(typeof(FIBacklogMesa[]))]
|
||||
internal partial class FIBacklogMesaCollectionSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, PropertyNameCaseInsensitive = true)]
|
||||
[JsonSerializable(typeof(FIBacklogMesa))]
|
||||
internal partial class FIBacklogMesaSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
#endif
|
93
ADO2024/PI3/Helper-2024-08-05.cs
Normal file
93
ADO2024/PI3/Helper-2024-08-05.cs
Normal file
@ -0,0 +1,93 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
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;
|
||||
string old;
|
||||
string from;
|
||||
string what;
|
||||
string concat;
|
||||
string checkFile;
|
||||
string extension;
|
||||
string[] matches;
|
||||
string[] segments;
|
||||
string environment;
|
||||
List<string> distinct = [];
|
||||
string globalSettingsLines = File.ReadAllText(globalSettingsFile);
|
||||
foreach (string line in lines)
|
||||
{
|
||||
segments = line.Split('|');
|
||||
if (segments.Length != 7)
|
||||
{
|
||||
logger.LogWarning("Wrong length!");
|
||||
continue;
|
||||
}
|
||||
to = segments[5].Trim();
|
||||
old = segments[1].Trim();
|
||||
from = segments[4].Trim();
|
||||
what = segments[3].Trim();
|
||||
environment = segments[2].Trim();
|
||||
concat = string.Concat(environment, '-', what, '-', from, '-', to);
|
||||
if (distinct.Contains(concat))
|
||||
{
|
||||
logger.LogWarning("Not distinct <{concat}>!", concat);
|
||||
continue;
|
||||
}
|
||||
distinct.Add(concat);
|
||||
globalSettingsLines = globalSettingsLines.Replace(old, concat);
|
||||
matches = (from l in files where l.Contains(old) select l).ToArray();
|
||||
if (matches.Length != 1)
|
||||
{
|
||||
logger.LogWarning("matches == {matchesLength} <{concat}>!", matches.Length, concat);
|
||||
continue;
|
||||
}
|
||||
extension = Path.GetExtension(matches[0]);
|
||||
checkFile = Path.Combine(sourceDirectory, $"{concat}{extension}");
|
||||
File.Move(matches[0], checkFile);
|
||||
}
|
||||
File.WriteAllText(globalSettingsFile, globalSettingsLines);
|
||||
}
|
||||
|
||||
internal static void RenameFiles(ILogger<Worker> logger, List<string> args)
|
||||
{
|
||||
string find = args[6];
|
||||
string replace = args[7];
|
||||
string sourceDirectory = Path.GetFullPath(args[0]);
|
||||
string globalSettingsFile = Path.GetFullPath(args[4]);
|
||||
string[] files = Directory.GetFiles(sourceDirectory, args[2], SearchOption.TopDirectoryOnly);
|
||||
string[] confFiles = Directory.GetFiles(sourceDirectory, $"*{find}", SearchOption.TopDirectoryOnly);
|
||||
string[] ignoreFileNames = args[8].Split(',').Select(l => Path.Combine(sourceDirectory, l)).ToArray();
|
||||
RenameFiles(find, replace, ignoreFileNames, confFiles);
|
||||
string checkFile = Path.Combine(sourceDirectory, args[3]);
|
||||
if (files.Length == 0 || !File.Exists(checkFile))
|
||||
logger.LogWarning("No found!");
|
||||
else
|
||||
{
|
||||
string[] lines = File.ReadAllLines(checkFile);
|
||||
if (lines.Length == 0)
|
||||
logger.LogWarning("No lines!");
|
||||
else
|
||||
RenameFiles(logger, sourceDirectory, files, lines, globalSettingsFile);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
57
ADO2024/PI3/Helper-2024-08-06.cs
Normal file
57
ADO2024/PI3/Helper-2024-08-06.cs
Normal file
@ -0,0 +1,57 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Globalization;
|
||||
|
||||
namespace File_Folder_Helper.ADO2024.PI3;
|
||||
|
||||
internal static partial class Helper20240806
|
||||
{
|
||||
|
||||
private static void TryArchiveFiles(string sourceDirectory, string pattern, string archiveDirectory, int minimumLength, int days)
|
||||
{
|
||||
string checkFile;
|
||||
FileInfo fileInfo;
|
||||
string weekOfYear;
|
||||
string checkDirectory;
|
||||
string[] directorySegments;
|
||||
DateTime dateTime = DateTime.Now.AddDays(-days);
|
||||
Calendar calendar = new CultureInfo("en-US").Calendar;
|
||||
string[] sourceDirectorySegments = sourceDirectory.Split(Path.DirectorySeparatorChar);
|
||||
string[] files = Directory.GetFiles(sourceDirectory, pattern, SearchOption.AllDirectories);
|
||||
if (sourceDirectorySegments.Length < 1)
|
||||
throw new Exception("Can't be root drive!");
|
||||
foreach (string file in files)
|
||||
{
|
||||
fileInfo = new FileInfo(file);
|
||||
if (string.IsNullOrEmpty(fileInfo.DirectoryName) || fileInfo.IsReadOnly || fileInfo.Length < minimumLength || fileInfo.LastWriteTime < dateTime)
|
||||
continue;
|
||||
directorySegments = fileInfo.DirectoryName.Split(Path.DirectorySeparatorChar);
|
||||
if (directorySegments.Length < sourceDirectorySegments.Length)
|
||||
continue;
|
||||
weekOfYear = $"{fileInfo.LastWriteTime.Year}_Week_{calendar.GetWeekOfYear(fileInfo.LastWriteTime, CalendarWeekRule.FirstDay, DayOfWeek.Sunday):00}";
|
||||
checkDirectory = string.Concat(archiveDirectory, Path.DirectorySeparatorChar, weekOfYear);
|
||||
for (int i = sourceDirectorySegments.Length; i < directorySegments.Length; i++)
|
||||
checkDirectory = string.Concat(checkDirectory, Path.DirectorySeparatorChar, directorySegments[i]);
|
||||
checkDirectory = string.Concat(checkDirectory, Path.DirectorySeparatorChar, fileInfo.LastWriteTime.ToString("yyyy-MM-dd"));
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
checkFile = Path.Combine(checkDirectory, string.Concat(fileInfo.LastWriteTime.ToString("HH-mm-ss-fff"), "~", fileInfo.Name));
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
File.Move(fileInfo.FullName, checkFile);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void ArchiveFiles(ILogger<Worker> logger, List<string> args)
|
||||
{
|
||||
string pattern = args[4];
|
||||
int days = int.Parse(args[6]);
|
||||
logger.LogInformation("Hello");
|
||||
string sourceDirectory = args[0];
|
||||
int minimumLength = int.Parse(args[5]);
|
||||
int millisecondsDelay = int.Parse(args[2]);
|
||||
string archiveDirectory = Path.GetFullPath(args[7]);
|
||||
TryArchiveFiles(sourceDirectory, pattern, archiveDirectory, minimumLength, days);
|
||||
Thread.Sleep(millisecondsDelay);
|
||||
}
|
||||
|
||||
}
|
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
40
ADO2024/PI3/Helper-2024-08-20.cs
Normal file
40
ADO2024/PI3/Helper-2024-08-20.cs
Normal file
@ -0,0 +1,40 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
namespace File_Folder_Helper.ADO2024.PI3;
|
||||
|
||||
internal static partial class Helper20240820
|
||||
{
|
||||
|
||||
internal static void MoveFilesWithSleep(ILogger<Worker> logger, List<string> args)
|
||||
{
|
||||
string checkFile;
|
||||
string checkDirectory;
|
||||
int sleep = int.Parse(args[4]);
|
||||
string searchPattern = args[3];
|
||||
string sourceDirectory = args[0];
|
||||
string destinationDirectory = args[2];
|
||||
string source = Path.GetFullPath(sourceDirectory);
|
||||
FileInfo[] collection = Directory.GetFiles(source, "*", SearchOption.TopDirectoryOnly).Select(l => new FileInfo(l)).ToArray();
|
||||
string[] files = (from l in collection orderby l.LastWriteTime select l.FullName).ToArray();
|
||||
logger.LogInformation("With search pattern '{SearchPattern}' found {files}", searchPattern, files.Length);
|
||||
foreach (string file in files)
|
||||
{
|
||||
Thread.Sleep(500);
|
||||
checkFile = file.Replace(source, destinationDirectory);
|
||||
if (checkFile == file)
|
||||
throw new NotSupportedException("Replace failed!");
|
||||
checkDirectory = Path.GetDirectoryName(checkFile) ?? throw new NotSupportedException();
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
File.Move(file, checkFile);
|
||||
Thread.Sleep(sleep);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{ logger.LogInformation(ex, "Inner loop error!"); }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
228
ADO2024/PI3/Helper-2024-08-22.cs
Normal file
228
ADO2024/PI3/Helper-2024-08-22.cs
Normal file
@ -0,0 +1,228 @@
|
||||
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 Helper20240822
|
||||
{
|
||||
|
||||
public record Record(string? Title, ReadOnlyCollection<string> Tags, string? Completed);
|
||||
|
||||
public record Root([property: JsonPropertyName("headings")] Heading[] Headings,
|
||||
[property: JsonPropertyName("lanes")] Lane[] Lanes);
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Root))]
|
||||
internal partial class Helper20240822RootSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
public record Welcome2([property: JsonPropertyName("headings")] Heading[] Headings,
|
||||
[property: JsonPropertyName("lanes")] Lane[] Lanes);
|
||||
|
||||
public record Heading([property: JsonPropertyName("name")] string Name,
|
||||
[property: JsonPropertyName("heading")] string HeadingHeading);
|
||||
|
||||
public record Lane([property: JsonPropertyName("name")] string Name,
|
||||
[property: JsonPropertyName("columns")] Column[][] Columns);
|
||||
|
||||
public record Column([property: JsonPropertyName("id")] string Id,
|
||||
[property: JsonPropertyName("name")] string Name,
|
||||
[property: JsonPropertyName("description")] string Description,
|
||||
[property: JsonPropertyName("metadata")] Metadata? Metadata,
|
||||
[property: JsonPropertyName("subTasks")] SubTask[]? SubTasks,
|
||||
[property: JsonPropertyName("relations")] object[] Relations,
|
||||
[property: JsonPropertyName("comments")] Comment[] Comments,
|
||||
[property: JsonPropertyName("column")] string ColumnColumn,
|
||||
[property: JsonPropertyName("workload")] long Workload,
|
||||
[property: JsonPropertyName("progress")] long Progress,
|
||||
[property: JsonPropertyName("remainingWorkload")] long RemainingWorkload,
|
||||
[property: JsonPropertyName("dueData")] DueData DueData);
|
||||
|
||||
public record Comment([property: JsonPropertyName("text")] string Text,
|
||||
[property: JsonPropertyName("date")] DateTimeOffset Date);
|
||||
|
||||
public record DueData([property: JsonPropertyName("completed")] bool Completed,
|
||||
[property: JsonPropertyName("completedDate")] object CompletedDate,
|
||||
[property: JsonPropertyName("dueDate")] DateTimeOffset DueDate,
|
||||
[property: JsonPropertyName("overdue")] bool Overdue,
|
||||
[property: JsonPropertyName("dueDelta")] long DueDelta,
|
||||
[property: JsonPropertyName("dueMessage")] string DueMessage);
|
||||
|
||||
public record Metadata([property: JsonPropertyName("assigned")] string Assigned,
|
||||
[property: JsonPropertyName("created")] DateTimeOffset Created,
|
||||
[property: JsonPropertyName("progress")] long? Progress,
|
||||
[property: JsonPropertyName("started")] DateTimeOffset? Started,
|
||||
[property: JsonPropertyName("status")] string? Status,
|
||||
[property: JsonPropertyName("tags")] string[]? Tags,
|
||||
[property: JsonPropertyName("type")] string? Type,
|
||||
[property: JsonPropertyName("updated")] DateTimeOffset Updated,
|
||||
[property: JsonPropertyName("due")] DateTimeOffset? Due,
|
||||
[property: JsonPropertyName("completed")] DateTimeOffset? Completed);
|
||||
|
||||
public record SubTask([property: JsonPropertyName("text")] string Text,
|
||||
[property: JsonPropertyName("completed")] bool Completed);
|
||||
|
||||
private static ReadOnlyCollection<ReadOnlyCollection<Record>> GetRecords(Column[][] columnCollection)
|
||||
{
|
||||
List<ReadOnlyCollection<Record>> results = [];
|
||||
bool check;
|
||||
int subTasks;
|
||||
Column column;
|
||||
int completed;
|
||||
List<Record> row;
|
||||
string? subtasks;
|
||||
List<string> tags;
|
||||
for (int i = 0; i < int.MaxValue; i++)
|
||||
{
|
||||
row = [];
|
||||
check = false;
|
||||
foreach (Column[] columns in columnCollection)
|
||||
{
|
||||
if (columns.Length <= i)
|
||||
row.Add(new(null, new([]), null));
|
||||
else
|
||||
{
|
||||
tags = [];
|
||||
subTasks = 0;
|
||||
completed = 0;
|
||||
column = columns[i];
|
||||
if (!check)
|
||||
check = true;
|
||||
if (column.Metadata?.Tags is not null && column.Metadata.Tags.Length != 0)
|
||||
{
|
||||
foreach (string tag in column.Metadata.Tags)
|
||||
tags.Add(tag);
|
||||
}
|
||||
if (column.SubTasks is not null && column.SubTasks.Length != 0)
|
||||
{
|
||||
foreach (SubTask subTask in column.SubTasks)
|
||||
{
|
||||
subTasks += 1;
|
||||
if (subTask.Completed)
|
||||
completed += 1;
|
||||
}
|
||||
}
|
||||
subtasks = subTasks == 0 ? subtasks = null : $"{completed} / {subTasks}";
|
||||
row.Add(new(column.Name, new(tags), subtasks));
|
||||
}
|
||||
}
|
||||
if (!check)
|
||||
break;
|
||||
if (results.Count > 0)
|
||||
{
|
||||
if (results[0].Count != row.Count)
|
||||
throw new Exception("Rows must match!");
|
||||
}
|
||||
results.Add(new(row));
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static void WriteFile(string destinationFile, Heading[] headings, ReadOnlyCollection<ReadOnlyCollection<Record>> recordCollection)
|
||||
{
|
||||
string title;
|
||||
string completed;
|
||||
List<string> lines =
|
||||
[
|
||||
"<html>",
|
||||
"<head>",
|
||||
"<style>",
|
||||
":root {",
|
||||
"color-scheme: light dark;",
|
||||
"}",
|
||||
"body {",
|
||||
"color: light-dark(#333b3c, #efedea);",
|
||||
"background-color: light-dark(#efedea, #333b3c);",
|
||||
"}",
|
||||
"td {",
|
||||
"vertical-align: top;",
|
||||
"}",
|
||||
".title {",
|
||||
"font-weight: bold;",
|
||||
"}",
|
||||
".complete {",
|
||||
"font-size: small;",
|
||||
"}",
|
||||
".speech-bubble {",
|
||||
"position: relative;",
|
||||
"background: darkCyan;",
|
||||
"border-radius: .4em;",
|
||||
"}",
|
||||
".speech-bubble:after {",
|
||||
"content: '';",
|
||||
"position: absolute;",
|
||||
"bottom: 0;",
|
||||
"left: 50%;",
|
||||
"width: 0;",
|
||||
"height: 0;",
|
||||
"border: 2px solid transparent;",
|
||||
"border-top-color: #00aabb;",
|
||||
"border-bottom: 0;",
|
||||
"margin-left: -2px;",
|
||||
"margin-bottom: -2px;",
|
||||
"}",
|
||||
"</style>",
|
||||
"</head>",
|
||||
"<table border=\"1\">",
|
||||
"<tr>"
|
||||
];
|
||||
foreach (Heading heading in headings)
|
||||
lines.Add($"<th>{heading.Name}</th>");
|
||||
lines.Add("</tr>");
|
||||
foreach (ReadOnlyCollection<Record> records in recordCollection)
|
||||
{
|
||||
lines.Add("<tr>");
|
||||
foreach (Record record in records)
|
||||
{
|
||||
lines.Add("<td>");
|
||||
title = record.Title is null ? " " : record.Title;
|
||||
completed = record.Completed is null ? " " : record.Completed;
|
||||
lines.Add($"<div class=\"title\">{title}</div>");
|
||||
lines.Add("<div>");
|
||||
foreach (string tag in record.Tags)
|
||||
lines.Add($"<span class=\"speech-bubble\">{tag}</span>");
|
||||
lines.Add("</div>");
|
||||
lines.Add($"<div class=\"completed\">{completed}</div>");
|
||||
lines.Add("</td>");
|
||||
}
|
||||
lines.Add("</tr>");
|
||||
}
|
||||
lines.Add("</table>");
|
||||
lines.Add("</html>");
|
||||
File.WriteAllLines(destinationFile, lines);
|
||||
}
|
||||
|
||||
private static void ParseKanbn(ILogger<Worker> logger, string destinationFile, string json)
|
||||
{
|
||||
Root? root = JsonSerializer.Deserialize(json, Helper20240822RootSourceGenerationContext.Default.Root);
|
||||
if (root is null)
|
||||
logger.LogInformation("<{root}> is null!", root);
|
||||
else if (root.Lanes.Length != 1)
|
||||
logger.LogInformation("{root.Lanes} != 1", root.Lanes.Length);
|
||||
else if (root.Lanes[0].Columns.Length != root.Headings.Length)
|
||||
logger.LogInformation("{root[0].Columns.Lanes} != {root.Headings}", root.Lanes[0].Columns.Length, root.Headings.Length);
|
||||
else
|
||||
{
|
||||
ReadOnlyCollection<ReadOnlyCollection<Record>> recordCollection = GetRecords(root.Lanes[0].Columns);
|
||||
WriteFile(destinationFile, root.Headings, recordCollection);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void ParseKanbn(ILogger<Worker> logger, List<string> args)
|
||||
{
|
||||
string sourceDirectory = Path.GetFullPath(args[0]);
|
||||
string sourceFile = Path.Combine(sourceDirectory, args[2]);
|
||||
string destinationFile = Path.Combine(sourceDirectory, $"{DateTime.Now.Ticks}-{args[3]}");
|
||||
if (!File.Exists(sourceFile))
|
||||
logger.LogInformation("<{sourceFile}> doesn't exist!", sourceFile);
|
||||
else
|
||||
{
|
||||
string json = File.ReadAllText(sourceFile);
|
||||
ParseKanbn(logger, destinationFile, json);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
248
ADO2024/PI3/Helper-2024-08-28.cs
Normal file
248
ADO2024/PI3/Helper-2024-08-28.cs
Normal file
@ -0,0 +1,248 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace File_Folder_Helper.ADO2024.PI3;
|
||||
|
||||
internal static partial class Helper20240828
|
||||
{
|
||||
|
||||
public record HeaderCommon(DateTime Date,
|
||||
string? Employee,
|
||||
string? Layer,
|
||||
string? MesEntity,
|
||||
string? PSN,
|
||||
string? Quantity,
|
||||
string? RDS,
|
||||
string? Reactor,
|
||||
string? Recipe,
|
||||
string? Zone);
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(HeaderCommon))]
|
||||
internal partial class HeaderCommonSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
public record Record(string? CassetteId,
|
||||
ReadOnlyCollection<string>? CassetteSegments,
|
||||
DateTime? Date,
|
||||
string? Employee,
|
||||
ReadOnlyCollection<string>? EquipmentSegments,
|
||||
int I,
|
||||
string? LastDate,
|
||||
ReadOnlyCollection<ReadOnlyCollection<string>>? Matches);
|
||||
|
||||
private static Record GetRecord(int i, string? lastDate, ReadOnlyCollection<ReadOnlyCollection<string>> matches)
|
||||
{
|
||||
Record result;
|
||||
if (matches.Count != 4 || matches[0].Count != 3 || matches[3].Count != 3)
|
||||
result = new Record(null, null, null, null, null, i, null, null);
|
||||
else
|
||||
{
|
||||
string[] equipmentSegments = matches[1][2].Split('|');
|
||||
if (equipmentSegments.Length != 2)
|
||||
result = new Record(null, null, null, null, null, i, null, null);
|
||||
else
|
||||
{
|
||||
string[] cassetteIdSegments = matches[3][2].Split('|');
|
||||
if (cassetteIdSegments.Length <= 3)
|
||||
result = new Record(null, null, null, null, null, i, null, null);
|
||||
else
|
||||
{
|
||||
string cassetteId = Regex.Replace(cassetteIdSegments[2], @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]", "_").Split('\r')[0].Split('\n')[0];
|
||||
result = new Record(cassetteId,
|
||||
new(cassetteIdSegments),
|
||||
DateTime.Parse(matches[0][0]),
|
||||
matches[0][1],
|
||||
new(equipmentSegments),
|
||||
i,
|
||||
lastDate,
|
||||
new(matches));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<Record> GetRecords(string logDirectory, string logSearchPattern)
|
||||
{
|
||||
List<Record> results = [];
|
||||
Record record;
|
||||
string[] lines;
|
||||
string[] logFiles = Directory.GetFiles(logDirectory, logSearchPattern, SearchOption.TopDirectoryOnly);
|
||||
if (logFiles.Length > 0)
|
||||
{ }
|
||||
foreach (string logFile in new List<string>()) // logFiles)
|
||||
{
|
||||
lines = File.ReadAllLines(logFile);
|
||||
for (int i = lines.Length - 1; i >= 0; i--)
|
||||
{
|
||||
record = GetRecord(lines, i);
|
||||
i = record.I;
|
||||
if (record.CassetteId is null || record.CassetteSegments is null || record.Date is null || record.Employee is null || record.EquipmentSegments is null || record.Matches is null)
|
||||
{
|
||||
if (i < 4)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
results.Add(record);
|
||||
}
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static Dictionary<int, ReadOnlyCollection<Record>> GetKeyValuePairs(Dictionary<int, List<Record>> keyValuePairs)
|
||||
{
|
||||
Dictionary<int, ReadOnlyCollection<Record>> results = [];
|
||||
foreach (KeyValuePair<int, List<Record>> keyValuePair in keyValuePairs)
|
||||
results.Add(keyValuePair.Key, new(keyValuePair.Value));
|
||||
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;
|
||||
int totalMinutes;
|
||||
TimeSpan timeSpan;
|
||||
List<Record>? collection;
|
||||
Dictionary<int, List<Record>> keyValuePairs = [];
|
||||
ReadOnlyCollection<Record> records = GetRecords(logDirectory, logSearchPattern);
|
||||
foreach (Record record in records)
|
||||
{
|
||||
if (record.CassetteId is null || record.CassetteSegments is null || record.Date is null || record.Employee is null || record.EquipmentSegments is null || record.Matches is null)
|
||||
continue;
|
||||
timeSpan = TimeSpan.FromTicks(record.Date.Value.Ticks);
|
||||
totalMinutes = (int)Math.Floor(timeSpan.TotalMinutes);
|
||||
if (!keyValuePairs.TryGetValue(totalMinutes, out collection))
|
||||
{
|
||||
keyValuePairs.Add(totalMinutes, []);
|
||||
if (!keyValuePairs.TryGetValue(totalMinutes, out collection))
|
||||
throw new Exception();
|
||||
}
|
||||
collection.Add(record);
|
||||
}
|
||||
results = GetKeyValuePairs(keyValuePairs);
|
||||
return results;
|
||||
}
|
||||
|
||||
internal static void MoveWaferCounterToArchive(ILogger<Worker> logger, List<string> args)
|
||||
{
|
||||
string json;
|
||||
string keyFile;
|
||||
string? recipe;
|
||||
string[] lines;
|
||||
string checkFile;
|
||||
string directory;
|
||||
string? quantity;
|
||||
string runDataSheet;
|
||||
string checkDirectory;
|
||||
HeaderCommon headerCommon;
|
||||
string logDateFormat = args[3];
|
||||
string wcSearchPattern = args[5];
|
||||
string logSearchPattern = $"SKIP---{args[2]}";
|
||||
string logDirectory = Path.GetFullPath(args[0]);
|
||||
string sourceDirectory = Path.GetFullPath(args[4]);
|
||||
string archiveDirectory = Path.GetFullPath(args[6]);
|
||||
FileInfo[] collection = Directory.GetFiles(sourceDirectory, wcSearchPattern, SearchOption.AllDirectories).Select(l => new FileInfo(l)).ToArray();
|
||||
logger.LogInformation("Found {collection}(s)", collection.Length);
|
||||
foreach (FileInfo fileInfo in collection)
|
||||
{
|
||||
if (fileInfo.DirectoryName is null || !fileInfo.DirectoryName.Contains('-'))
|
||||
continue;
|
||||
lines = File.ReadAllLines(fileInfo.FullName);
|
||||
recipe = lines.Length < 2 ? null : lines[1];
|
||||
quantity = lines.Length < 1 ? null : lines[0];
|
||||
keyFile = $"{fileInfo.FullName}.txt";
|
||||
if (!File.Exists(keyFile))
|
||||
continue;
|
||||
lines = File.ReadAllLines(keyFile);
|
||||
if (lines.Length != 1)
|
||||
continue;
|
||||
runDataSheet = Regex.Replace(lines[0], @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]", ".").Split('\r')[0].Split('\n')[0];
|
||||
directory = Path.Combine(fileInfo.DirectoryName, runDataSheet);
|
||||
checkDirectory = Path.Combine(directory, fileInfo.LastWriteTime.Ticks.ToString());
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
checkFile = Path.Combine(directory, fileInfo.Name);
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
headerCommon = new(fileInfo.LastWriteTime, null, null, null, null, quantity, runDataSheet, null, recipe, null);
|
||||
json = JsonSerializer.Serialize(headerCommon, HeaderCommonSourceGenerationContext.Default.HeaderCommon);
|
||||
File.Move(fileInfo.FullName, checkFile);
|
||||
File.Delete(keyFile);
|
||||
checkFile = Path.Combine(checkDirectory, $"{fileInfo.Name}.json");
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
File.WriteAllText(checkFile, json);
|
||||
Directory.SetLastWriteTime(checkDirectory, fileInfo.LastWriteTime);
|
||||
}
|
||||
Record record;
|
||||
int totalMinutes;
|
||||
string weekOfYear;
|
||||
TimeSpan timeSpan;
|
||||
ReadOnlyCollection<Record>? records;
|
||||
Calendar calendar = new CultureInfo("en-US").Calendar;
|
||||
Dictionary<int, ReadOnlyCollection<Record>> keyValuePairs = GetKeyValuePairs(logSearchPattern, logDirectory);
|
||||
logger.LogInformation("Mapped {keyValuePairs}(s)", keyValuePairs.Count);
|
||||
foreach (FileInfo fileInfo in collection)
|
||||
{
|
||||
if (fileInfo.DirectoryName is null || fileInfo.DirectoryName.Contains('-'))
|
||||
continue;
|
||||
timeSpan = TimeSpan.FromTicks(fileInfo.LastWriteTime.Ticks);
|
||||
totalMinutes = (int)Math.Floor(timeSpan.TotalMinutes);
|
||||
if (!keyValuePairs.TryGetValue(totalMinutes, out records))
|
||||
continue;
|
||||
if (records.Count != 1)
|
||||
continue;
|
||||
record = records[0];
|
||||
if (record.CassetteId is null || record.CassetteSegments is null || record.Date is null || record.Employee is null || record.EquipmentSegments is null || record.Matches is null)
|
||||
continue;
|
||||
weekOfYear = $"{record.Date.Value.Year}_Week_{calendar.GetWeekOfYear(record.Date.Value, CalendarWeekRule.FirstDay, DayOfWeek.Sunday):00}";
|
||||
checkDirectory = Path.Combine(archiveDirectory,
|
||||
string.Join('-', record.EquipmentSegments.Reverse()),
|
||||
weekOfYear,
|
||||
record.Date.Value.ToString("yyyy-MM-dd"),
|
||||
record.CassetteId);
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
checkFile = Path.Combine(checkDirectory, fileInfo.Name);
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
File.Move(fileInfo.FullName, checkFile);
|
||||
lines = record.Matches.Select(l => string.Join(',', l)).ToArray();
|
||||
File.WriteAllLines($"{checkFile}.txt", lines);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
236
ADO2024/PI3/Helper-2024-08-30.cs
Normal file
236
ADO2024/PI3/Helper-2024-08-30.cs
Normal file
@ -0,0 +1,236 @@
|
||||
#if WorkItems
|
||||
using File_Folder_Helper.ADO2024.PI3.WorkItems;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.TeamFoundation.WorkItemTracking.WebApi;
|
||||
using Microsoft.VisualStudio.Services.Common;
|
||||
using Microsoft.VisualStudio.Services.WebApi;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Web;
|
||||
|
||||
namespace File_Folder_Helper.ADO2024.PI3;
|
||||
|
||||
internal static partial class Helper20240830
|
||||
{
|
||||
|
||||
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,
|
||||
object[] 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);
|
||||
|
||||
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 = [];
|
||||
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)
|
||||
{
|
||||
results.Add(workItem.Id);
|
||||
if (results.Count > 199)
|
||||
break;
|
||||
}
|
||||
foreach (int id in results)
|
||||
_ = result.Append(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 targetFileLocation, string ids)
|
||||
{
|
||||
List<ValueWithReq> results = [];
|
||||
string json;
|
||||
string file;
|
||||
Value? value;
|
||||
JsonElement[] jsonElements;
|
||||
Task<HttpResponseMessage> httpResponseMessageTask = httpClient.GetAsync(string.Concat(basePage, api, $"/workitems?ids={ids}&$expand=Relations"));
|
||||
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;
|
||||
if (value.Id == 120593)
|
||||
GetSingle(httpClient, basePage, api, targetFileLocation, value.Id);
|
||||
file = Path.Combine(targetFileLocation, $"{-1}-{value.Id}.json");
|
||||
File.WriteAllText(file, json);
|
||||
results.Add(new(value, -1, json));
|
||||
}
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static void CompareWorkItems(WorkItemTrackingHttpClient workItemTrackingHttpClient,
|
||||
string sourceDirectory,
|
||||
string project,
|
||||
string site,
|
||||
ReadOnlyCollection<ValueWithReq> valueWithReqCollection)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(workItemTrackingHttpClient);
|
||||
if (string.IsNullOrEmpty(project))
|
||||
throw new ArgumentException($"'{nameof(project)}' cannot be null or empty.", nameof(project));
|
||||
if (string.IsNullOrEmpty(sourceDirectory))
|
||||
throw new ArgumentException($"'{nameof(sourceDirectory)}' cannot be null or empty.", nameof(site));
|
||||
if (string.IsNullOrEmpty(site))
|
||||
throw new ArgumentException($"'{nameof(site)}' cannot be null or empty.", nameof(site));
|
||||
ReadOnlyCollection<WorkItem> workItems = GetWorkItems(valueWithReqCollection);
|
||||
string file = Path.Combine(sourceDirectory, $"_.json");
|
||||
string json = JsonSerializer.Serialize(workItems);
|
||||
File.WriteAllText(file, json);
|
||||
foreach (WorkItem workItem in workItems)
|
||||
{
|
||||
if (workItem is null)
|
||||
{ }
|
||||
}
|
||||
// https://stackoverflow.com/questions/18153998/how-do-i-remove-all-html-tags-from-a-string-without-knowing-which-tags-are-in-it
|
||||
}
|
||||
|
||||
private static void CompareWorkItems(HttpClient httpClient,
|
||||
string targetFileLocation,
|
||||
string basePage,
|
||||
string api,
|
||||
string query,
|
||||
WorkItemTrackingHttpClient workItemTrackingHttpClient,
|
||||
string project,
|
||||
string site)
|
||||
{
|
||||
string ids = GetIds(httpClient, basePage, api, query);
|
||||
ReadOnlyCollection<ValueWithReq> valueWithReqCollection = string.IsNullOrEmpty(ids) ? new([]) : GetWorkItems(httpClient, basePage, api, targetFileLocation, ids);
|
||||
CompareWorkItems(workItemTrackingHttpClient, targetFileLocation, project, site, valueWithReqCollection);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
65
ADO2024/PI3/Helper-2024-09-10.cs
Normal file
65
ADO2024/PI3/Helper-2024-09-10.cs
Normal file
@ -0,0 +1,65 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Globalization;
|
||||
namespace File_Folder_Helper.ADO2024.PI3;
|
||||
|
||||
internal static partial class Helper20240910
|
||||
{
|
||||
|
||||
internal static void MoveFilesToWeekOfYear(ILogger<Worker> logger, List<string> args)
|
||||
{
|
||||
string day;
|
||||
string year;
|
||||
string yearB;
|
||||
string yearC;
|
||||
string checkFile;
|
||||
FileInfo fileInfo;
|
||||
string weekOfYear;
|
||||
int weekOfYearValue;
|
||||
string checkDirectory;
|
||||
string searchPattern = args[2];
|
||||
ReadOnlyCollection<string> directoryNames;
|
||||
string sourceDirectory = Path.GetFullPath(args[0]);
|
||||
Calendar calendar = new CultureInfo("en-US").Calendar;
|
||||
string[] files = Directory.GetFiles(sourceDirectory, searchPattern, SearchOption.AllDirectories);
|
||||
logger.LogInformation("With search pattern '{SearchPattern}' found {files}", searchPattern, files.Length);
|
||||
foreach (string file in files)
|
||||
{
|
||||
fileInfo = new(file);
|
||||
if (string.IsNullOrEmpty(fileInfo.DirectoryName))
|
||||
continue;
|
||||
checkDirectory = string.Empty;
|
||||
year = $"{fileInfo.LastWriteTime:yyyy}";
|
||||
yearB = $"{fileInfo.LastWriteTime:yyyy}_Year";
|
||||
day = fileInfo.LastWriteTime.ToString("yyyy-MM-dd");
|
||||
directoryNames = Helpers.HelperDirectory.GetDirectoryNames(fileInfo.DirectoryName);
|
||||
weekOfYearValue = calendar.GetWeekOfYear(fileInfo.LastWriteTime, CalendarWeekRule.FirstDay, DayOfWeek.Sunday);
|
||||
yearC = weekOfYearValue < 27 ? $"{fileInfo.LastWriteTime:yyyy}_Year_A" : $"{fileInfo.LastWriteTime:yyyy}_Year_Z";
|
||||
weekOfYear = $"{fileInfo.LastWriteTime.Year}_Week_{weekOfYearValue:00}";
|
||||
foreach (string directoryName in directoryNames)
|
||||
{
|
||||
if (directoryName == year || directoryName == yearB || directoryName == yearC || directoryName == weekOfYear || directoryName == day)
|
||||
continue;
|
||||
checkDirectory = Path.Combine(checkDirectory, directoryName);
|
||||
}
|
||||
if (string.IsNullOrEmpty(checkDirectory))
|
||||
continue;
|
||||
checkDirectory = Path.Combine(checkDirectory, yearC, weekOfYear, day);
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
checkFile = Path.Combine(checkDirectory, fileInfo.Name);
|
||||
if (checkFile.Length > 256 || checkFile == fileInfo.FullName)
|
||||
continue;
|
||||
try
|
||||
{
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
File.Move(fileInfo.FullName, checkFile);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{ logger.LogInformation(ex, $"Inner loop error <{fileInfo.FullName}>!"); }
|
||||
}
|
||||
Helpers.HelperDeleteEmptyDirectories.DeleteEmptyDirectories(logger, sourceDirectory);
|
||||
}
|
||||
|
||||
}
|
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");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
58
ADO2024/PI3/Helper-2024-09-16.cs
Normal file
58
ADO2024/PI3/Helper-2024-09-16.cs
Normal file
@ -0,0 +1,58 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Collections.ObjectModel;
|
||||
namespace File_Folder_Helper.ADO2024.PI3;
|
||||
|
||||
internal static partial class Helper20240916
|
||||
{
|
||||
|
||||
private static ReadOnlyCollection<string> Get(string searchPattern, string[] configFileLines)
|
||||
{
|
||||
List<string> results = [];
|
||||
string[] segments;
|
||||
foreach (string line in configFileLines)
|
||||
{
|
||||
if (line.Length < 2 || line[0] == '#')
|
||||
continue;
|
||||
segments = line.Split(searchPattern);
|
||||
if (segments.Length < 2)
|
||||
continue;
|
||||
results.Add(segments[1].Split(';')[0]);
|
||||
}
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
internal static void DebugProxyPass(ILogger<Worker> logger, List<string> args)
|
||||
{
|
||||
string debug;
|
||||
string enable;
|
||||
string[] lines;
|
||||
string fileName;
|
||||
string[] segments;
|
||||
string configFile = args[3];
|
||||
string searchPattern = args[2];
|
||||
string searchPatternB = args[4];
|
||||
string searchPatternC = args[5];
|
||||
string sourceDirectory = Path.GetFullPath(args[0]);
|
||||
string[] configFileLines = File.ReadAllLines(configFile);
|
||||
ReadOnlyCollection<string> enabledSites = Get(searchPatternB, configFileLines);
|
||||
logger.LogInformation("Found {files} file(s)", enabledSites.Count);
|
||||
string[] files = Directory.GetFiles(sourceDirectory, searchPattern, SearchOption.AllDirectories);
|
||||
logger.LogInformation("With search pattern '{SearchPattern}' found {files} file(s)", searchPattern, files.Length);
|
||||
foreach (string file in files)
|
||||
{
|
||||
debug = string.Empty;
|
||||
lines = File.ReadAllLines(file);
|
||||
fileName = Path.GetFileName(file);
|
||||
foreach (string line in lines)
|
||||
{
|
||||
segments = line.Split(searchPatternC);
|
||||
if (segments.Length < 2)
|
||||
continue;
|
||||
debug = segments[1].Trim();
|
||||
}
|
||||
enable = enabledSites.Contains(fileName) ? string.Empty : "# ";
|
||||
logger.LogInformation("{enable}{searchPatternB}{fileName}; # https://{fileName}.phares.duckddns.org # {debug}", enable, searchPatternB, fileName, fileName, debug);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
65
ADO2024/PI3/Helper-2024-09-25.cs
Normal file
65
ADO2024/PI3/Helper-2024-09-25.cs
Normal file
@ -0,0 +1,65 @@
|
||||
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 Helper20240925
|
||||
{
|
||||
|
||||
public record Test(string Name,
|
||||
long Value);
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(ReadOnlyCollection<Test>))]
|
||||
internal partial class TestCollectionSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<Test> GetTests(string sourceDirectory, string searchPattern, string searchPatternB)
|
||||
{
|
||||
List<Test> results = [];
|
||||
long test;
|
||||
string[] lines;
|
||||
string[] segments;
|
||||
string[] segmentsB;
|
||||
List<long> distinct = [];
|
||||
string[] files = Directory.GetFiles(sourceDirectory, searchPattern, SearchOption.AllDirectories);
|
||||
foreach (string file in files)
|
||||
{
|
||||
lines = File.ReadAllLines(file);
|
||||
foreach (string line in lines)
|
||||
{
|
||||
segments = line.Split(searchPatternB);
|
||||
if (segments.Length < 2)
|
||||
continue;
|
||||
segmentsB = segments[1].Split(',');
|
||||
if (segmentsB.Length < 2)
|
||||
continue;
|
||||
if (!long.TryParse(segmentsB[0], out test))
|
||||
continue;
|
||||
if (distinct.Contains(test))
|
||||
continue;
|
||||
distinct.Add(test);
|
||||
results.Add(new(segmentsB[1].Trim('"'), test));
|
||||
}
|
||||
}
|
||||
return (from l in results orderby l.Name.Length, l.Name select l).ToArray().AsReadOnly();
|
||||
}
|
||||
|
||||
internal static void DistinctTests(ILogger<Worker> logger, List<string> args)
|
||||
{
|
||||
string searchPattern = args[2];
|
||||
string searchPatternB = args[3];
|
||||
string destinationDirectory = args[4];
|
||||
string sourceDirectory = Path.GetFullPath(args[0]);
|
||||
if (!Directory.Exists(destinationDirectory))
|
||||
_ = Directory.CreateDirectory(destinationDirectory);
|
||||
ReadOnlyCollection<Test> tests = GetTests(sourceDirectory, searchPattern, searchPatternB);
|
||||
logger.LogInformation("Found {files} file(s)", tests.Count);
|
||||
string json = JsonSerializer.Serialize(tests, TestCollectionSourceGenerationContext.Default.ReadOnlyCollectionTest);
|
||||
string fileName = Path.Combine(destinationDirectory, ".json");
|
||||
File.WriteAllText(fileName, json);
|
||||
}
|
||||
|
||||
}
|
177
ADO2024/PI3/Helper-2024-10-02.cs
Normal file
177
ADO2024/PI3/Helper-2024-10-02.cs
Normal file
@ -0,0 +1,177 @@
|
||||
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 Helper20241002
|
||||
{
|
||||
|
||||
public record Record(string? Calculation,
|
||||
string Chart,
|
||||
string Group,
|
||||
string GroupId,
|
||||
long Id,
|
||||
string? RawCalculation,
|
||||
string Test,
|
||||
string TestId)
|
||||
{
|
||||
|
||||
public static Record Get(Record record, string? calculation) =>
|
||||
new(calculation,
|
||||
record.Chart,
|
||||
record.Group,
|
||||
record.GroupId,
|
||||
record.Id,
|
||||
record.RawCalculation,
|
||||
record.Test,
|
||||
record.TestId);
|
||||
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(ReadOnlyCollection<Record>))]
|
||||
internal partial class RecordCollectionSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(ReadOnlyDictionary<string, Record>))]
|
||||
internal partial class RecordDictionarySourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
private static string? GetCalculation(string searchPatternC, string[] lines, int i, string id, long idValue)
|
||||
{
|
||||
string? result = null;
|
||||
string line;
|
||||
long check;
|
||||
string[] segments;
|
||||
string[] segmentsB;
|
||||
for (int j = i + 1; j < lines.Length; j++)
|
||||
{
|
||||
line = lines[j];
|
||||
if (!line.Contains(id))
|
||||
break;
|
||||
segments = line.Split(searchPatternC);
|
||||
if (segments.Length < 2)
|
||||
continue;
|
||||
segmentsB = segments[1].Split('=');
|
||||
if (segmentsB.Length < 2)
|
||||
continue;
|
||||
if (!long.TryParse(segmentsB[0], out check))
|
||||
continue;
|
||||
if (check != idValue)
|
||||
break;
|
||||
result = segmentsB[1];
|
||||
}
|
||||
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 = [];
|
||||
string id;
|
||||
string line;
|
||||
long idValue;
|
||||
string[] lines;
|
||||
string[] segments;
|
||||
string[] segmentsB;
|
||||
string[] segmentsC;
|
||||
string? calculation;
|
||||
string[] files = Directory.GetFiles(sourceDirectory, searchPattern, SearchOption.AllDirectories);
|
||||
foreach (string file in files)
|
||||
{
|
||||
lines = File.ReadAllLines(file);
|
||||
for (int i = 0; i < lines.Length; i++)
|
||||
{
|
||||
line = lines[i];
|
||||
segments = line.Split(searchPatternB);
|
||||
if (segments.Length < 2)
|
||||
continue;
|
||||
segmentsB = segments[1].Split('=');
|
||||
if (segmentsB.Length < 2)
|
||||
continue;
|
||||
if (!long.TryParse(segmentsB[0], out idValue))
|
||||
continue;
|
||||
id = segmentsB[0];
|
||||
segmentsC = segments[1].Split(',');
|
||||
if (segmentsC.Length < 4)
|
||||
continue;
|
||||
calculation = GetCalculation(searchPatternC, lines, i, id, idValue);
|
||||
results.Add(new(null,
|
||||
Path.GetFileName(file),
|
||||
segmentsC[2].Trim('"'),
|
||||
segmentsC[1],
|
||||
idValue,
|
||||
calculation,
|
||||
segmentsC[4].Trim('"'),
|
||||
segmentsC[3]));
|
||||
}
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static ReadOnlyDictionary<string, Record> GetKeyValuePairs(ReadOnlyCollection<Record> records)
|
||||
{
|
||||
Dictionary<string, Record> results = [];
|
||||
string key;
|
||||
string? last = null;
|
||||
foreach (Record record in records)
|
||||
{
|
||||
if (last is not null && record.Chart != last)
|
||||
continue;
|
||||
last = record.Chart;
|
||||
key = GetKey(record);
|
||||
if (results.ContainsKey(key))
|
||||
continue;
|
||||
results.Add(key, record);
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
internal static void ConvertInfinityQSProjectFiles(ILogger<Worker> logger, List<string> args)
|
||||
{
|
||||
string searchPattern = args[2];
|
||||
string searchPatternB = args[3];
|
||||
string searchPatternC = args[4];
|
||||
string destinationDirectory = args[5];
|
||||
string sourceDirectory = Path.GetFullPath(args[0]);
|
||||
if (!Directory.Exists(destinationDirectory))
|
||||
_ = Directory.CreateDirectory(destinationDirectory);
|
||||
ReadOnlyCollection<Record> records = GetRecords(sourceDirectory, searchPattern, searchPatternB, searchPatternC);
|
||||
logger.LogInformation("Found {records} records(s)", records.Count);
|
||||
ReadOnlyDictionary<string, Record> collection = GetKeyValuePairs(records);
|
||||
logger.LogInformation("Found {collection} collection(s)", collection.Count);
|
||||
ReadOnlyDictionary<string, Record> keyValuePairs = GetKeyValuePairs(collection);
|
||||
logger.LogInformation("Found {keyValuePairs}", keyValuePairs.Count);
|
||||
string json = JsonSerializer.Serialize(keyValuePairs, RecordDictionarySourceGenerationContext.Default.ReadOnlyDictionaryStringRecord);
|
||||
string fileName = Path.Combine(destinationDirectory, ".json");
|
||||
File.WriteAllText(fileName, json);
|
||||
}
|
||||
|
||||
}
|
24
ADO2024/PI3/WIQL/Column.cs
Normal file
24
ADO2024/PI3/WIQL/Column.cs
Normal file
@ -0,0 +1,24 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WIQL;
|
||||
|
||||
public class Column
|
||||
{
|
||||
[JsonConstructor]
|
||||
public Column(
|
||||
string referenceName,
|
||||
string name,
|
||||
string url
|
||||
)
|
||||
{
|
||||
ReferenceName = referenceName;
|
||||
Name = name;
|
||||
Url = url;
|
||||
}
|
||||
|
||||
public string ReferenceName { get; set; } // { init; get; }
|
||||
public string Name { get; set; } // { init; get; }
|
||||
public string Url { get; set; } // { init; get; }
|
||||
}
|
||||
#endif
|
24
ADO2024/PI3/WIQL/Field.cs
Normal file
24
ADO2024/PI3/WIQL/Field.cs
Normal file
@ -0,0 +1,24 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WIQL;
|
||||
|
||||
public class Field
|
||||
{
|
||||
[JsonConstructor]
|
||||
public Field(
|
||||
string referenceName,
|
||||
string name,
|
||||
string url
|
||||
)
|
||||
{
|
||||
ReferenceName = referenceName;
|
||||
Name = name;
|
||||
Url = url;
|
||||
}
|
||||
|
||||
public string ReferenceName { get; set; } // { init; get; }
|
||||
public string Name { get; set; } // { init; get; }
|
||||
public string Url { get; set; } // { init; get; }
|
||||
}
|
||||
#endif
|
39
ADO2024/PI3/WIQL/Root.cs
Normal file
39
ADO2024/PI3/WIQL/Root.cs
Normal file
@ -0,0 +1,39 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WIQL;
|
||||
|
||||
public class Root
|
||||
{
|
||||
[JsonConstructor]
|
||||
public Root(
|
||||
string queryType,
|
||||
string queryResultType,
|
||||
DateTime asOf,
|
||||
Column[] columns,
|
||||
SortColumn[] sortColumns,
|
||||
WorkItem[] workItems
|
||||
)
|
||||
{
|
||||
QueryType = queryType;
|
||||
QueryResultType = queryResultType;
|
||||
AsOf = asOf;
|
||||
Columns = columns;
|
||||
SortColumns = sortColumns;
|
||||
WorkItems = workItems;
|
||||
}
|
||||
|
||||
public string QueryType { get; set; } // { init; get; }
|
||||
public string QueryResultType { get; set; } // { init; get; }
|
||||
public DateTime AsOf { get; set; } // { init; get; }
|
||||
public Column[] Columns { get; set; } // { init; get; }
|
||||
public SortColumn[] SortColumns { get; set; } // { init; get; }
|
||||
public WorkItem[] WorkItems { get; set; } // { init; get; }
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, PropertyNameCaseInsensitive = true)]
|
||||
[JsonSerializable(typeof(Root))]
|
||||
internal partial class WIQLRootSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
#endif
|
21
ADO2024/PI3/WIQL/SortColumn.cs
Normal file
21
ADO2024/PI3/WIQL/SortColumn.cs
Normal file
@ -0,0 +1,21 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WIQL;
|
||||
|
||||
public class SortColumn
|
||||
{
|
||||
[JsonConstructor]
|
||||
public SortColumn(
|
||||
Field field,
|
||||
bool descending
|
||||
)
|
||||
{
|
||||
Field = field;
|
||||
Descending = descending;
|
||||
}
|
||||
|
||||
public Field Field { get; set; } // { init; get; }
|
||||
public bool Descending { get; set; } // { init; get; }
|
||||
}
|
||||
#endif
|
21
ADO2024/PI3/WIQL/WorkItem.cs
Normal file
21
ADO2024/PI3/WIQL/WorkItem.cs
Normal file
@ -0,0 +1,21 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WIQL;
|
||||
|
||||
public class WorkItem
|
||||
{
|
||||
[JsonConstructor]
|
||||
public WorkItem(
|
||||
int id,
|
||||
string url
|
||||
)
|
||||
{
|
||||
Id = id;
|
||||
Url = url;
|
||||
}
|
||||
|
||||
public int Id { get; set; } // { init; get; }
|
||||
public string Url { get; set; } // { init; get; }
|
||||
}
|
||||
#endif
|
15
ADO2024/PI3/WorkItems/Avatar.cs
Normal file
15
ADO2024/PI3/WorkItems/Avatar.cs
Normal file
@ -0,0 +1,15 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WorkItems;
|
||||
|
||||
public class Avatar
|
||||
{
|
||||
[JsonConstructor]
|
||||
public Avatar(
|
||||
string href
|
||||
) => Href = href;
|
||||
|
||||
public string Href { get; } // { init; get; }
|
||||
}
|
||||
#endif
|
29
ADO2024/PI3/WorkItems/CommentVersionRef.cs
Normal file
29
ADO2024/PI3/WorkItems/CommentVersionRef.cs
Normal file
@ -0,0 +1,29 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WorkItems;
|
||||
|
||||
public class CommentVersionRef
|
||||
{
|
||||
[JsonConstructor]
|
||||
public CommentVersionRef(
|
||||
int commentId,
|
||||
int version,
|
||||
string url
|
||||
)
|
||||
{
|
||||
CommentId = commentId;
|
||||
Version = version;
|
||||
URL = url;
|
||||
}
|
||||
|
||||
[JsonPropertyName("commentId")]
|
||||
public int CommentId { get; } // { init; get; }
|
||||
|
||||
[JsonPropertyName("version")]
|
||||
public int Version { get; } // { init; get; }
|
||||
|
||||
[JsonPropertyName("url")]
|
||||
public string URL { get; } // { init; get; }
|
||||
}
|
||||
#endif
|
36
ADO2024/PI3/WorkItems/CustomRequester.cs
Normal file
36
ADO2024/PI3/WorkItems/CustomRequester.cs
Normal file
@ -0,0 +1,36 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WorkItems;
|
||||
|
||||
public class CustomRequester
|
||||
{
|
||||
[JsonConstructor]
|
||||
public CustomRequester(
|
||||
string descriptor,
|
||||
string displayName,
|
||||
string id,
|
||||
string imageUrl,
|
||||
Links links,
|
||||
string uniqueName,
|
||||
string url
|
||||
)
|
||||
{
|
||||
Descriptor = descriptor;
|
||||
DisplayName = displayName;
|
||||
Id = id;
|
||||
ImageUrl = imageUrl;
|
||||
Links = links;
|
||||
UniqueName = uniqueName;
|
||||
Url = url;
|
||||
}
|
||||
|
||||
[JsonPropertyName("descriptor")] public string Descriptor { get; }
|
||||
[JsonPropertyName("displayName")] public string DisplayName { get; }
|
||||
[JsonPropertyName("id")] public string Id { get; }
|
||||
[JsonPropertyName("imageUrl")] public string ImageUrl { get; }
|
||||
[JsonPropertyName("_links")] public Links Links { get; }
|
||||
[JsonPropertyName("uniqueName")] public string UniqueName { get; }
|
||||
[JsonPropertyName("url")] public string Url { get; }
|
||||
}
|
||||
#endif
|
101
ADO2024/PI3/WorkItems/Fields.cs
Normal file
101
ADO2024/PI3/WorkItems/Fields.cs
Normal file
@ -0,0 +1,101 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WorkItems;
|
||||
|
||||
public class Fields
|
||||
{
|
||||
[JsonConstructor]
|
||||
public Fields(int customRRminusOE,
|
||||
CustomRequester? customRequester,
|
||||
float customWSJF,
|
||||
int microsoftVSTSCommonBusinessValue,
|
||||
DateTime microsoftVSTSCommonClosedDate,
|
||||
int microsoftVSTSCommonPriority,
|
||||
DateTime microsoftVSTSCommonResolvedDate,
|
||||
DateTime microsoftVSTSCommonStateChangeDate,
|
||||
float microsoftVSTSCommonTimeCriticality,
|
||||
float? microsoftVSTSSchedulingEffort,
|
||||
DateTime microsoftVSTSSchedulingStartDate,
|
||||
DateTime microsoftVSTSSchedulingTargetDate,
|
||||
string systemAreaPath,
|
||||
SystemAssignedTo systemAssignedTo,
|
||||
SystemChangedBy systemChangedBy,
|
||||
DateTime systemChangedDate,
|
||||
int systemCommentCount,
|
||||
SystemCreatedBy systemCreatedBy,
|
||||
DateTime systemCreatedDate,
|
||||
string systemDescription,
|
||||
string systemHistory,
|
||||
string systemIterationPath,
|
||||
int systemParent,
|
||||
string systemReason,
|
||||
string systemState,
|
||||
string systemTags,
|
||||
string systemTeamProject,
|
||||
string systemTitle,
|
||||
string systemWorkItemType)
|
||||
{
|
||||
CustomRequester = customRequester;
|
||||
CustomRRminusOE = customRRminusOE;
|
||||
CustomWSJF = customWSJF;
|
||||
MicrosoftVSTSCommonBusinessValue = microsoftVSTSCommonBusinessValue;
|
||||
MicrosoftVSTSCommonClosedDate = microsoftVSTSCommonClosedDate;
|
||||
MicrosoftVSTSCommonPriority = microsoftVSTSCommonPriority;
|
||||
MicrosoftVSTSCommonResolvedDate = microsoftVSTSCommonResolvedDate;
|
||||
MicrosoftVSTSCommonStateChangeDate = microsoftVSTSCommonStateChangeDate;
|
||||
MicrosoftVSTSCommonTimeCriticality = microsoftVSTSCommonTimeCriticality;
|
||||
MicrosoftVSTSSchedulingEffort = microsoftVSTSSchedulingEffort;
|
||||
MicrosoftVSTSSchedulingStartDate = microsoftVSTSSchedulingStartDate;
|
||||
MicrosoftVSTSSchedulingTargetDate = microsoftVSTSSchedulingTargetDate;
|
||||
SystemAreaPath = systemAreaPath;
|
||||
SystemAssignedTo = systemAssignedTo;
|
||||
SystemChangedBy = systemChangedBy;
|
||||
SystemChangedDate = systemChangedDate;
|
||||
SystemCommentCount = systemCommentCount;
|
||||
SystemCreatedBy = systemCreatedBy;
|
||||
SystemCreatedDate = systemCreatedDate;
|
||||
SystemDescription = systemDescription;
|
||||
SystemHistory = systemHistory;
|
||||
SystemIterationPath = systemIterationPath;
|
||||
SystemParent = systemParent;
|
||||
SystemReason = systemReason;
|
||||
SystemState = systemState;
|
||||
SystemTags = systemTags;
|
||||
SystemTeamProject = systemTeamProject;
|
||||
SystemTitle = systemTitle;
|
||||
SystemWorkItemType = systemWorkItemType;
|
||||
}
|
||||
|
||||
[JsonPropertyName("Custom.Requester")] public CustomRequester? CustomRequester { get; } // { init; get; }
|
||||
[JsonPropertyName("Custom.RRminusOE")] public int CustomRRminusOE { get; } // { init; get; }
|
||||
[JsonPropertyName("Custom.WSJF")] public float CustomWSJF { get; } // { init; get; }
|
||||
[JsonPropertyName("Microsoft.VSTS.Common.BusinessValue")] public int MicrosoftVSTSCommonBusinessValue { get; } // { init; get; }
|
||||
[JsonPropertyName("Microsoft.VSTS.Common.ClosedDate")] public DateTime MicrosoftVSTSCommonClosedDate { get; } // { init; get; }
|
||||
[JsonPropertyName("Microsoft.VSTS.Common.Priority")] public int MicrosoftVSTSCommonPriority { get; } // { init; get; }
|
||||
[JsonPropertyName("Microsoft.VSTS.Common.ResolvedDate")] public DateTime MicrosoftVSTSCommonResolvedDate { get; } // { init; get; }
|
||||
[JsonPropertyName("Microsoft.VSTS.Common.StateChangeDate")] public DateTime MicrosoftVSTSCommonStateChangeDate { get; } // { init; get; }
|
||||
[JsonPropertyName("Microsoft.VSTS.Common.TimeCriticality")] public float MicrosoftVSTSCommonTimeCriticality { get; } // { init; get; }
|
||||
[JsonPropertyName("Microsoft.VSTS.Scheduling.Effort")] public float? MicrosoftVSTSSchedulingEffort { get; } // { init; get; }
|
||||
[JsonPropertyName("Microsoft.VSTS.Scheduling.StartDate")] public DateTime MicrosoftVSTSSchedulingStartDate { get; } // { init; get; }
|
||||
[JsonPropertyName("Microsoft.VSTS.Scheduling.TargetDate")] public DateTime MicrosoftVSTSSchedulingTargetDate { get; } // { init; get; }
|
||||
[JsonPropertyName("System.AreaPath")] public string SystemAreaPath { get; } // { init; get; }
|
||||
[JsonPropertyName("System.AssignedTo")] public SystemAssignedTo? SystemAssignedTo { get; } // { init; get; }
|
||||
[JsonPropertyName("System.ChangedBy")] public SystemChangedBy SystemChangedBy { get; } // { init; get; }
|
||||
[JsonPropertyName("System.ChangedDate")] public DateTime SystemChangedDate { get; } // { init; get; }
|
||||
[JsonPropertyName("System.CommentCount")] public int SystemCommentCount { get; } // { init; get; }
|
||||
[JsonPropertyName("System.CreatedBy")] public SystemCreatedBy SystemCreatedBy { get; } // { init; get; }
|
||||
[JsonPropertyName("System.CreatedDate")] public DateTime SystemCreatedDate { get; } // { init; get; }
|
||||
[JsonPropertyName("System.Description")] public string SystemDescription { get; } // { init; get; }
|
||||
[JsonPropertyName("System.History")] public string SystemHistory { get; } // { init; get; }
|
||||
[JsonPropertyName("System.IterationPath")] public string SystemIterationPath { get; } // { init; get; }
|
||||
[JsonPropertyName("System.Parent")] public int SystemParent { get; } // { init; get; }
|
||||
[JsonPropertyName("System.Reason")] public string SystemReason { get; } // { init; get; }
|
||||
[JsonPropertyName("System.State")] public string SystemState { get; } // { init; get; }
|
||||
[JsonPropertyName("System.Tags")] public string SystemTags { get; } // { init; get; }
|
||||
[JsonPropertyName("System.TeamProject")] public string SystemTeamProject { get; } // { init; get; }
|
||||
[JsonPropertyName("System.Title")] public string SystemTitle { get; } // { init; get; }
|
||||
[JsonPropertyName("System.WorkItemType")] public string SystemWorkItemType { get; } // { init; get; }
|
||||
|
||||
}
|
||||
#endif
|
15
ADO2024/PI3/WorkItems/Html.cs
Normal file
15
ADO2024/PI3/WorkItems/Html.cs
Normal file
@ -0,0 +1,15 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WorkItems;
|
||||
|
||||
public class Html
|
||||
{
|
||||
[JsonConstructor]
|
||||
public Html(
|
||||
string href
|
||||
) => Href = href;
|
||||
|
||||
public string Href { get; } // { init; get; }
|
||||
}
|
||||
#endif
|
16
ADO2024/PI3/WorkItems/Links.cs
Normal file
16
ADO2024/PI3/WorkItems/Links.cs
Normal file
@ -0,0 +1,16 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WorkItems;
|
||||
|
||||
public class Links
|
||||
{
|
||||
[JsonConstructor]
|
||||
public Links(
|
||||
Avatar avatar
|
||||
) => Avatar = avatar;
|
||||
|
||||
[JsonPropertyName("avatar")]
|
||||
public Avatar Avatar { get; }
|
||||
}
|
||||
#endif
|
49
ADO2024/PI3/WorkItems/SystemAssignedTo.cs
Normal file
49
ADO2024/PI3/WorkItems/SystemAssignedTo.cs
Normal file
@ -0,0 +1,49 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WorkItems;
|
||||
|
||||
public class SystemAssignedTo
|
||||
{
|
||||
[JsonConstructor]
|
||||
public SystemAssignedTo(
|
||||
string displayName,
|
||||
string url,
|
||||
Links links,
|
||||
string id,
|
||||
string uniqueName,
|
||||
string imageUrl,
|
||||
string descriptor
|
||||
)
|
||||
{
|
||||
DisplayName = displayName;
|
||||
Url = url;
|
||||
Links = links;
|
||||
Id = id;
|
||||
UniqueName = uniqueName;
|
||||
ImageUrl = imageUrl;
|
||||
Descriptor = descriptor;
|
||||
}
|
||||
|
||||
[JsonPropertyName("displayName")]
|
||||
public string DisplayName { get; }
|
||||
|
||||
[JsonPropertyName("url")]
|
||||
public string Url { get; }
|
||||
|
||||
[JsonPropertyName("_links")]
|
||||
public Links Links { get; }
|
||||
|
||||
[JsonPropertyName("id")]
|
||||
public string Id { get; }
|
||||
|
||||
[JsonPropertyName("uniqueName")]
|
||||
public string UniqueName { get; }
|
||||
|
||||
[JsonPropertyName("imageUrl")]
|
||||
public string ImageUrl { get; }
|
||||
|
||||
[JsonPropertyName("descriptor")]
|
||||
public string Descriptor { get; }
|
||||
}
|
||||
#endif
|
49
ADO2024/PI3/WorkItems/SystemChangedBy.cs
Normal file
49
ADO2024/PI3/WorkItems/SystemChangedBy.cs
Normal file
@ -0,0 +1,49 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WorkItems;
|
||||
|
||||
public class SystemChangedBy
|
||||
{
|
||||
[JsonConstructor]
|
||||
public SystemChangedBy(
|
||||
string displayName,
|
||||
string url,
|
||||
Links links,
|
||||
string id,
|
||||
string uniqueName,
|
||||
string imageUrl,
|
||||
string descriptor
|
||||
)
|
||||
{
|
||||
DisplayName = displayName;
|
||||
Url = url;
|
||||
Links = links;
|
||||
Id = id;
|
||||
UniqueName = uniqueName;
|
||||
ImageUrl = imageUrl;
|
||||
Descriptor = descriptor;
|
||||
}
|
||||
|
||||
[JsonPropertyName("displayName")]
|
||||
public string DisplayName { get; }
|
||||
|
||||
[JsonPropertyName("url")]
|
||||
public string Url { get; }
|
||||
|
||||
[JsonPropertyName("_links")]
|
||||
public Links Links { get; }
|
||||
|
||||
[JsonPropertyName("id")]
|
||||
public string Id { get; }
|
||||
|
||||
[JsonPropertyName("uniqueName")]
|
||||
public string UniqueName { get; }
|
||||
|
||||
[JsonPropertyName("imageUrl")]
|
||||
public string ImageUrl { get; }
|
||||
|
||||
[JsonPropertyName("descriptor")]
|
||||
public string Descriptor { get; }
|
||||
}
|
||||
#endif
|
49
ADO2024/PI3/WorkItems/SystemCreatedBy.cs
Normal file
49
ADO2024/PI3/WorkItems/SystemCreatedBy.cs
Normal file
@ -0,0 +1,49 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WorkItems;
|
||||
|
||||
public class SystemCreatedBy
|
||||
{
|
||||
[JsonConstructor]
|
||||
public SystemCreatedBy(
|
||||
string displayName,
|
||||
string url,
|
||||
Links links,
|
||||
string id,
|
||||
string uniqueName,
|
||||
string imageUrl,
|
||||
string descriptor
|
||||
)
|
||||
{
|
||||
DisplayName = displayName;
|
||||
Url = url;
|
||||
Links = links;
|
||||
Id = id;
|
||||
UniqueName = uniqueName;
|
||||
ImageUrl = imageUrl;
|
||||
Descriptor = descriptor;
|
||||
}
|
||||
|
||||
[JsonPropertyName("displayName")]
|
||||
public string DisplayName { get; }
|
||||
|
||||
[JsonPropertyName("url")]
|
||||
public string Url { get; }
|
||||
|
||||
[JsonPropertyName("_links")]
|
||||
public Links Links { get; }
|
||||
|
||||
[JsonPropertyName("id")]
|
||||
public string Id { get; }
|
||||
|
||||
[JsonPropertyName("uniqueName")]
|
||||
public string UniqueName { get; }
|
||||
|
||||
[JsonPropertyName("imageUrl")]
|
||||
public string ImageUrl { get; }
|
||||
|
||||
[JsonPropertyName("descriptor")]
|
||||
public string Descriptor { get; }
|
||||
}
|
||||
#endif
|
56
ADO2024/PI3/WorkItems/Value.cs
Normal file
56
ADO2024/PI3/WorkItems/Value.cs
Normal file
@ -0,0 +1,56 @@
|
||||
#if WorkItems
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WorkItems;
|
||||
|
||||
public class Value
|
||||
{
|
||||
[JsonConstructor]
|
||||
public Value(
|
||||
int id,
|
||||
int rev,
|
||||
Fields fields,
|
||||
object[] relations,
|
||||
CommentVersionRef commentVersionRef,
|
||||
string url
|
||||
)
|
||||
{
|
||||
Id = id;
|
||||
Rev = rev;
|
||||
Fields = fields;
|
||||
Relations = relations;
|
||||
CommentVersionRef = commentVersionRef;
|
||||
Url = url;
|
||||
}
|
||||
|
||||
[JsonPropertyName("id")]
|
||||
public int Id { get; }
|
||||
|
||||
[JsonPropertyName("rev")]
|
||||
public int Rev { get; }
|
||||
|
||||
[JsonPropertyName("fields")]
|
||||
public Fields Fields { get; }
|
||||
|
||||
[JsonPropertyName("relations")]
|
||||
public object[] Relations { get; }
|
||||
|
||||
[JsonPropertyName("commentVersionRef")]
|
||||
public CommentVersionRef CommentVersionRef { get; }
|
||||
|
||||
[JsonPropertyName("url")]
|
||||
public string Url { get; }
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, PropertyNameCaseInsensitive = true)]
|
||||
[JsonSerializable(typeof(Value[]))]
|
||||
internal partial class ValueCollectionSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, PropertyNameCaseInsensitive = true)]
|
||||
[JsonSerializable(typeof(Value))]
|
||||
internal partial class ValueSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
#endif
|
21
ADO2024/PI3/WorkItems/ValueWithReq.cs
Normal file
21
ADO2024/PI3/WorkItems/ValueWithReq.cs
Normal file
@ -0,0 +1,21 @@
|
||||
#if WorkItems
|
||||
namespace File_Folder_Helper.ADO2024.PI3.WorkItems;
|
||||
|
||||
public class ValueWithReq
|
||||
{
|
||||
public ValueWithReq(
|
||||
Value value,
|
||||
int req,
|
||||
string json
|
||||
)
|
||||
{
|
||||
Value = value;
|
||||
Req = req;
|
||||
Json = json;
|
||||
}
|
||||
|
||||
public Value Value { get; set; } // { init; get; }
|
||||
public int Req { get; set; } // { init; get; }
|
||||
public string Json { get; set; } // { init; get; }
|
||||
}
|
||||
#endif
|
Reference in New Issue
Block a user