Skip to content

Commit

Permalink
refactor(WorkItemCloneCommand.cs): merge two tasks into one for loadi…
Browse files Browse the repository at this point in the history
…ng template items

feat(WorkItemCloneCommand.cs): replace direct API calls with repository pattern for better code organization and separation of concerns
refactor(WorkItemRepo.cs): update WorkItemRepository to include loading source in GetWorkItemsFullAsync method
fix(WorkItemRepo.cs): change parentId type from string to int for correct type usage
refactor(WorkItemRepo.cs): update GetWorkItemsFullAsync method to return loading source along with total and processed count
  • Loading branch information
MrHinsh committed Jul 17, 2024
1 parent 0e02d48 commit b96f263
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 93 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Microsoft.VisualStudio.Services.CircuitBreaker;
using Newtonsoft.Json.Linq;
using System.Diagnostics.Eventing.Reader;
using AzureDevOps.WorkItemClone.Repositories;

namespace AzureDevOps.WorkItemClone.ConsoleUI.Commands
{
Expand Down Expand Up @@ -70,8 +71,7 @@ await AnsiConsole.Progress()
.StartAsync(async ctx =>
{
// Define tasks
var task1 = ctx.AddTask("[bold]Stage 1[/]: Get Template Items", false);
var task2 = ctx.AddTask("[bold]Stage 2[/]: Load Template Items", false);
var task1 = ctx.AddTask("[bold]Stage 1+2[/]: Load Template Items", false);
var task3 = ctx.AddTask("[bold]Stage 3[/]: Get Target Project", false);
var task4 = ctx.AddTask("[bold]Stage 4[/]: Create Output Plan", false);
var task5 = ctx.AddTask("[bold]Stage 5[/]: Create Output Plan Relations ", false);
Expand All @@ -85,85 +85,21 @@ await AnsiConsole.Progress()
System.IO.File.Delete(cacheTemplateWorkItemsFile);
}

task1.MaxValue = 1;
CashedWorkItems templateWorkItems = null;



task1.StartTask();
task2.StartTask();


if (System.IO.File.Exists(cacheTemplateWorkItemsFile))
IWorkItemRepository templateWor = new WorkItemRepository(config.CachePath, config.templateOrganization, config.templateProject, config.templateAccessToken, (int)config.templateParentId);
await foreach (var result in templateWor.GetWorkItemsFullAsync())
{
// load Cache
try
//AnsiConsole.WriteLine($"Stage 2: Processing {workItem.id}:`{workItem.fields.SystemTitle}`");
task1.MaxValue = result.total;
if (result.total == result.processed)
{
templateWorkItems = JsonConvert.DeserializeObject<CashedWorkItems>(System.IO.File.ReadAllText(cacheTemplateWorkItemsFile));
task1.Increment(result.processed);
await Task.Delay(250);
}
catch (Exception ex)
{
// failed to load
AnsiConsole.WriteLine($"Cache is moldy, reloading..");
}
if (templateWorkItems != null)
{
//Test Cache date
QueryResults changedWorkItems = await templateApi.GetWiqlQueryResults("Select [System.Id] From WorkItems Where [System.TeamProject] = '@project' AND [System.Parent] = @id AND [System.ChangedDate] > '@changeddate' order by [System.CreatedDate] desc", new Dictionary<string, string>() { { "@id", config.templateParentId.ToString() }, { "@changeddate", templateWorkItems.queryDatetime.AddDays(-1).ToString("yyyy-MM-dd") } });
if (changedWorkItems.workItems.Length == 0)
{
AnsiConsole.WriteLine($"Stage 1: Checked template for changes. None Detected. Loading Cache");

// Load from Cache

task1.Increment(1);
task1.Description = task1.Description + " (cache)";
await Task.Delay(250);
task1.StopTask();
//////////////////////
task2.Increment(templateWorkItems.workitems.Count());
task2.Description = task2.Description + " (cache)";
AnsiConsole.WriteLine($"Stage 2: Loaded {templateWorkItems.workitems.Count()} work items from cache.");
}
else
{
AnsiConsole.WriteLine($"Cache is stale, reloading..");
templateWorkItems = null;
}
}
}

if (templateWorkItems == null)
{
// Get From Server
// --------------------------------------------------------------
// Task 1: query for template work items
task1.StartTask();
templateWorkItems = new CashedWorkItems() { workitems = new List<WorkItemFull>(), queryDatetime = DateTime.Now };
//AnsiConsole.WriteLine("Stage 1: Executing items from Query");
QueryResults templateWorkItemLight;
templateWorkItemLight = await templateApi.GetWiqlQueryResults("Select [System.Id] From WorkItems Where [System.TeamProject] = '@project' AND [System.Parent] = @id order by [System.CreatedDate] desc", new Dictionary<string, string>() { { "@id", config.templateParentId.ToString() } });
AnsiConsole.WriteLine($"Stage 1: Query returned {templateWorkItemLight.workItems.Count()} items id's from the template.");
task1.Description = $"[bold]Stage 1[/]: Load Template Items ({result.loadingFrom})";
task1.Increment(1);
task1.StopTask();
// --------------------------------------------------------------
// Task 2: getting work items and their full data
task2.MaxValue = templateWorkItemLight.workItems.Count();
task2.StartTask();
await Task.Delay(250);
//AnsiConsole.WriteLine($"Stage 2: Loading {fakeItemsFromTemplateQuery.workItems.Count()} work items from template.");
await foreach (var workItem in templateApi.GetWorkItemsFullAsync(templateWorkItemLight.workItems))
{
//AnsiConsole.WriteLine($"Stage 2: Processing {workItem.id}:`{workItem.fields.SystemTitle}`");
templateWorkItems.workitems.Add(workItem);
task2.Increment(1);
}
System.IO.File.WriteAllText(cacheTemplateWorkItemsFile, JsonConvert.SerializeObject(templateWorkItems, Formatting.Indented));
//AnsiConsole.WriteLine($"Stage 2: All {task2.MaxValue} work items loaded");
await Task.Delay(250);
task2.StopTask();
}
await Task.Delay(250);
task1.StopTask();

// --------------------------------------------------------------
string targetProjectRunFile = $"{runCache}\\targetProject.json";
Expand Down Expand Up @@ -219,7 +155,7 @@ await AnsiConsole.Progress()
await Task.Delay(250);
//AnsiConsole.WriteLine($"Stage 4: First Pass generation of Work Items to build will merge the provided json work items with the data from the template.");
buildItems = new List<WorkItemToBuild>();
await foreach (WorkItemToBuild witb in generateWorkItemsToBuildList(inputWorkItems, templateWorkItems.workitems, projectItem, config.targetProject))
await foreach (WorkItemToBuild witb in generateWorkItemsToBuildList(inputWorkItems, templateWor.Data.workitems, projectItem, config.targetProject))
{
// AnsiConsole.WriteLine($"Stage 4: processing {witb.guid}");
buildItems.Add(witb);
Expand All @@ -234,7 +170,7 @@ await AnsiConsole.Progress()
//AnsiConsole.WriteLine($"Stage 5: Second Pass generate relations.");
task5.StartTask();
await Task.Delay(250);
await foreach (WorkItemToBuild witb in generateWorkItemsToBuildRelations(buildItems, templateWorkItems.workitems))
await foreach (WorkItemToBuild witb in generateWorkItemsToBuildRelations(buildItems, templateWor.Data.workitems))
{
//AnsiConsole.WriteLine($"Stage 5: processing {witb.guid} for output of {witb.relations.Count-1} relations");
task5.Increment(1);
Expand Down
29 changes: 13 additions & 16 deletions AzureDevOps.WorkItemClone/Repositories/WorkItemRepo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,8 @@ namespace AzureDevOps.WorkItemClone.Repositories
{
public interface IWorkItemRepository
{
IAsyncEnumerable<(int total, int processed)> GetWorkItemsFullAsync();
//Task<WorkItemFull> GetWorkItemByIdAsync(int id);
//Task<IEnumerable<WorkItemFull>> GetAllWorkItemAsync();
//Task AddWorkItemAsync(WorkItemFull wif);
//Task UpdateWorkItemAsync(WorkItemFull wif);
//Task DeleteWorkItemAsync(int id);
CashedWorkItems Data {get;}
IAsyncEnumerable<(int total, int processed, string loadingFrom)> GetWorkItemsFullAsync();
}
public interface IPersistantCache
{
Expand All @@ -29,15 +25,15 @@ public class WorkItemRepository : IWorkItemRepository
public string OrganisationName { get; private set; }
public string ProjectName { get; private set; }
private string AccesToken { get; set; }
public string ParentId { get; private set; }
public int ParentId { get; private set; }

private AzureDevOpsApi _context;
private string cacheWorkItemsFile;
public CashedWorkItems WorkItems { get { return cachedWorkItems; } }
public CashedWorkItems Data { get { return cachedWorkItems; } }

CashedWorkItems cachedWorkItems = null;

public WorkItemRepository(string cachePath, string organisationName, string projectName, string accessToken, string parentId)
public WorkItemRepository(string cachePath, string organisationName, string projectName, string accessToken, int parentId)
{
if (string.IsNullOrEmpty(organisationName))
{
Expand All @@ -54,17 +50,17 @@ public WorkItemRepository(string cachePath, string organisationName, string proj
throw new ArgumentNullException(nameof(accessToken));
}
this.AccesToken = accessToken;
if (string.IsNullOrEmpty(ParentId))
if (parentId == 0)
{
throw new ArgumentNullException(nameof(parentId));
}
this.ParentId = parentId;
_context = new AzureDevOpsApi(organisationName, projectName, accessToken);
_context = new AzureDevOpsApi(accessToken, organisationName, projectName);
cacheWorkItemsFile = $"{cachePath}\\cache-{organisationName}-{projectName}-{ParentId}.json";
}


public async IAsyncEnumerable<(int total, int processed)> GetWorkItemsFullAsync()
public async IAsyncEnumerable<(int total, int processed, string loadingFrom)> GetWorkItemsFullAsync()
{
if (System.IO.File.Exists(cacheWorkItemsFile))
{
Expand All @@ -80,10 +76,10 @@ public WorkItemRepository(string cachePath, string organisationName, string proj
if (cachedWorkItems != null)
{
//Test Cache date
QueryResults? changedWorkItems = await _context.GetWiqlQueryResults("Select [System.Id] From WorkItems Where [System.TeamProject] = '@project' AND [System.Parent] = @id AND [System.ChangedDate] > '@changeddate' order by [System.CreatedDate] desc", new Dictionary<string, string>() { { "@id", ParentId }, { "@changeddate", cachedWorkItems.queryDatetime.AddDays(-1).ToString("yyyy-MM-dd") } });
QueryResults? changedWorkItems = await _context.GetWiqlQueryResults("Select [System.Id] From WorkItems Where [System.TeamProject] = '@project' AND [System.Parent] = @id AND [System.ChangedDate] > '@changeddate' order by [System.CreatedDate] desc", new Dictionary<string, string>() { { "@id", ParentId.ToString() }, { "@changeddate", cachedWorkItems.queryDatetime.AddDays(-1).ToString("yyyy-MM-dd") } });
if (changedWorkItems?.workItems.Length == 0)
{
yield return (cachedWorkItems.workitems.Count(), cachedWorkItems.workitems.Count());
yield return (cachedWorkItems.workitems.Count(), cachedWorkItems.workitems.Count(), "cache");
}
else
{
Expand All @@ -93,9 +89,10 @@ public WorkItemRepository(string cachePath, string organisationName, string proj
}
if (cachedWorkItems == null)
{
cachedWorkItems = new CashedWorkItems() { queryDatetime = DateTime.Now, workitems = new List<WorkItemFull>() };

QueryResults? templateWorkItemLight;
templateWorkItemLight = await _context.GetWiqlQueryResults("Select [System.Id] From WorkItems Where [System.TeamProject] = '@project' AND [System.Parent] = @id order by [System.CreatedDate] desc", new Dictionary<string, string>() { { "@id", ParentId.ToString() } });
cachedWorkItems = new CashedWorkItems() { queryDatetime = templateWorkItemLight.asOf, workitems = new List<WorkItemFull>() };
int count = 1;
foreach (var item in templateWorkItemLight?.workItems)
{
Expand All @@ -104,7 +101,7 @@ public WorkItemRepository(string cachePath, string organisationName, string proj
{
cachedWorkItems.workitems.Add(result);
}
yield return (cachedWorkItems.workitems.Count(), count);
yield return (templateWorkItemLight.workItems.Count(), count, "server");
count++;
}
System.IO.File.WriteAllText(cacheWorkItemsFile, JsonConvert.SerializeObject(cachedWorkItems, Formatting.Indented));
Expand Down

0 comments on commit b96f263

Please sign in to comment.