250 lines
13 KiB
C#
250 lines
13 KiB
C#
#if WorkItems
|
|
using File_Folder_Helper.ADO2024.PI3.WorkItems;
|
|
#endif
|
|
using Microsoft.Extensions.Logging;
|
|
#if WorkItems
|
|
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;
|
|
#endif
|
|
|
|
namespace File_Folder_Helper.ADO2024.PI3;
|
|
|
|
internal static partial class Helper20240830
|
|
{
|
|
|
|
#if WorkItems
|
|
|
|
private 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);
|
|
}
|
|
|
|
#else
|
|
|
|
internal static void CompareWorkItems(ILogger<Worker> logger, List<string> args)
|
|
{
|
|
logger.LogError("CompareWorkItems is not available in WorkItems {args[0]}", args[0]);
|
|
logger.LogError("CompareWorkItems is not available in WorkItems {args[1]}", args[1]);
|
|
}
|
|
|
|
#endif
|
|
|
|
} |