From 7ab1e5e27eb9862754bfed653491575376355255 Mon Sep 17 00:00:00 2001 From: Elvis Souza Date: Tue, 10 Aug 2021 08:42:01 -0300 Subject: [PATCH 01/11] Adjustments in ToTime Function --- .../local.settings.json | 7 ++++ .../20210720105645_FunctionToTimeInitial.cs | 36 ++++++++++++++++--- 2 files changed, 38 insertions(+), 5 deletions(-) create mode 100644 AzureDevOpsStateTracker.Functions/local.settings.json diff --git a/AzureDevOpsStateTracker.Functions/local.settings.json b/AzureDevOpsStateTracker.Functions/local.settings.json new file mode 100644 index 0000000..4fce9ff --- /dev/null +++ b/AzureDevOpsStateTracker.Functions/local.settings.json @@ -0,0 +1,7 @@ +{ + "IsEncrypted": false, + "Values": { + "AzureWebJobsStorage": "UseDevelopmentStorage=true", + "FUNCTIONS_WORKER_RUNTIME": "dotnet" + } +} \ No newline at end of file diff --git a/AzureDevopsStateTracker/Migrations/20210720105645_FunctionToTimeInitial.cs b/AzureDevopsStateTracker/Migrations/20210720105645_FunctionToTimeInitial.cs index 6edbad0..d7f9ca3 100644 --- a/AzureDevopsStateTracker/Migrations/20210720105645_FunctionToTimeInitial.cs +++ b/AzureDevopsStateTracker/Migrations/20210720105645_FunctionToTimeInitial.cs @@ -7,11 +7,37 @@ public partial class FunctionToTimeInitial : Migration { protected override void Up(MigrationBuilder migrationBuilder) { - var rawFunction = @"CREATE OR ALTER FUNCTION ToTime (@segundos float) - RETURNS TIME - AS BEGIN - return CONVERT(TIME, DATEADD(SECOND, @segundos + 86400000, 0), 114) - END"; + var rawFunction = @"CREATE OR ALTER FUNCTION ToTime (@seconds int) + RETURNS varchar(50) + AS BEGIN + declare @seconds_in_a_day int = 86400; + declare @seconds_in_an_hour int = 3600; + declare @seconds_in_a_minute int = 60; + + declare @text_to_return varchar(50) = ''; + if(@seconds >= @seconds_in_a_day) + begin + declare @completed_days int = @seconds/@seconds_in_a_day; + select @text_to_return = CONCAT(@text_to_return, @completed_days, ' day(s)') + select @seconds = @seconds - (@seconds_in_a_day * @completed_days) + end + + if(@seconds >= @seconds_in_an_hour) + begin + declare @completed_hours int = @seconds/@seconds_in_an_hour; + select @text_to_return = CONCAT(@text_to_return, ' ', @completed_hours, ' hour(s)') + select @seconds = @seconds - (@seconds_in_an_hour * @completed_hours) + end + + if(@seconds >= @seconds_in_a_minute) + begin + declare @completed_minutes int = @seconds/@seconds_in_a_minute; + select @text_to_return = CONCAT(@text_to_return, ' ', @completed_minutes, ' minute(s)') + select @seconds = @seconds - (@seconds_in_a_minute * @completed_minutes) + end + + return LTRIM(RTRIM(@text_to_return)); + END"; migrationBuilder.Sql(rawFunction); } From 6c28273e7c8793fc28ab63847af588a95a490cc7 Mon Sep 17 00:00:00 2001 From: Diego Galante Date: Wed, 18 Aug 2021 12:17:56 -0300 Subject: [PATCH 02/11] Updating --- .../AzureDevOpsStateTracker.Functions.csproj | 11 +- .../WorkItemFunctions.cs | 21 +-- .../AzureDevopsStateTracker.csproj | 2 +- .../DTOs/Create/CreateWorkItemDTO.cs | 4 + AzureDevopsStateTracker/DTOs/Fields.cs | 20 ++- .../DTOs/Update/UpdateWorkItemDTO.cs | 23 ++-- .../Data/DataBaseConfig.cs | 11 +- AzureDevopsStateTracker/Data/Repository.cs | 29 ++--- .../Data/WorkItemRepository.cs | 33 ++--- AzureDevopsStateTracker/Entities/WorkItem.cs | 3 +- .../Entities/WorkItemChange.cs | 121 ++++++++++++++++-- .../Extensions/HelperExtenions.cs | 8 +- .../IAzureDevopsStateTrackerService.cs | 7 +- .../Interfaces/Internals/IRepository.cs | 11 +- .../Internals/IWorkItemRepository.cs | 7 +- .../AzureDevopsStateTrackerService.cs | 43 +++++-- 16 files changed, 258 insertions(+), 96 deletions(-) diff --git a/AzureDevOpsStateTracker.Functions/AzureDevOpsStateTracker.Functions.csproj b/AzureDevOpsStateTracker.Functions/AzureDevOpsStateTracker.Functions.csproj index f83a1ab..af9f886 100644 --- a/AzureDevOpsStateTracker.Functions/AzureDevOpsStateTracker.Functions.csproj +++ b/AzureDevOpsStateTracker.Functions/AzureDevOpsStateTracker.Functions.csproj @@ -3,18 +3,11 @@ netcoreapp3.1 v3 035287d5-0b94-46fd-b3a9-b927fdb7b8ed + true - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - + diff --git a/AzureDevOpsStateTracker.Functions/WorkItemFunctions.cs b/AzureDevOpsStateTracker.Functions/WorkItemFunctions.cs index a1aae65..289302c 100644 --- a/AzureDevOpsStateTracker.Functions/WorkItemFunctions.cs +++ b/AzureDevOpsStateTracker.Functions/WorkItemFunctions.cs @@ -1,15 +1,16 @@ +using AzureDevopsStateTracker.DTOs.Create; +using AzureDevopsStateTracker.DTOs.Update; +using AzureDevopsStateTracker.Services; +using AzureDevOpsStateTracker.Functions.Extensions; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.WebJobs; using Microsoft.Azure.WebJobs.Extensions.Http; -using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; -using AzureDevopsStateTracker.Services; -using AzureDevOpsStateTracker.Functions.Extensions; using Newtonsoft.Json; -using AzureDevopsStateTracker.DTOs.Create; -using AzureDevopsStateTracker.DTOs.Update; -using System.Net; using System; +using System.Net; +using System.Threading.Tasks; namespace AzureDevOpsStateTracker.Functions { @@ -24,7 +25,7 @@ public WorkItemFunctions( } [FunctionName("workitem")] - public IActionResult Create( + public async Task Create( [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req, ILogger log) { @@ -32,7 +33,7 @@ public IActionResult Create( try { var workItemDTO = JsonConvert.DeserializeObject(req.GetBody()); - _azureDevopsStateTrackerService.Create(workItemDTO); + await _azureDevopsStateTrackerService.Create(workItemDTO); } catch (Exception ex) { @@ -43,14 +44,14 @@ public IActionResult Create( } [FunctionName("workitem-update")] - public IActionResult Update( + public async Task Update( [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req, ILogger log) { try { var workItemDTO = JsonConvert.DeserializeObject(req.GetBody()); - _azureDevopsStateTrackerService.Update(workItemDTO); + await _azureDevopsStateTrackerService.Update(workItemDTO); } catch (Exception ex) { diff --git a/AzureDevopsStateTracker/AzureDevopsStateTracker.csproj b/AzureDevopsStateTracker/AzureDevopsStateTracker.csproj index 647ec7b..1f1d5ca 100644 --- a/AzureDevopsStateTracker/AzureDevopsStateTracker.csproj +++ b/AzureDevopsStateTracker/AzureDevopsStateTracker.csproj @@ -6,8 +6,8 @@ + - \ No newline at end of file diff --git a/AzureDevopsStateTracker/DTOs/Create/CreateWorkItemDTO.cs b/AzureDevopsStateTracker/DTOs/Create/CreateWorkItemDTO.cs index e6282cd..d2cb228 100644 --- a/AzureDevopsStateTracker/DTOs/Create/CreateWorkItemDTO.cs +++ b/AzureDevopsStateTracker/DTOs/Create/CreateWorkItemDTO.cs @@ -1,18 +1,22 @@ using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace AzureDevopsStateTracker.DTOs.Create { public class CreateWorkItemDTO { + [JsonPropertyName("resource")] [JsonProperty("resource")] public Resource Resource { get; set; } } public class Resource { + [JsonPropertyName("id")] [JsonProperty("id")] public string Id { get; set; } + [JsonPropertyName("fields")] [JsonProperty("fields")] public Fields Fields { get; set; } } diff --git a/AzureDevopsStateTracker/DTOs/Fields.cs b/AzureDevopsStateTracker/DTOs/Fields.cs index 1351315..711bfbf 100644 --- a/AzureDevopsStateTracker/DTOs/Fields.cs +++ b/AzureDevopsStateTracker/DTOs/Fields.cs @@ -1,58 +1,76 @@ using Newtonsoft.Json; using System; +using System.Text.Json.Serialization; namespace AzureDevopsStateTracker.DTOs { public class Fields { + [JsonPropertyName("System.AreaPath")] [JsonProperty("System.AreaPath")] public string AreaPath { get; set; } + [JsonPropertyName("System.TeamProject")] [JsonProperty("System.TeamProject")] public string TeamProject { get; set; } + [JsonPropertyName("System.IterationPath")] [JsonProperty("System.IterationPath")] public string IterationPath { get; set; } + [JsonPropertyName("System.AssignedTo")] [JsonProperty("System.AssignedTo")] public string AssignedTo { get; set; } + [JsonPropertyName("System.WorkItemType")] [JsonProperty("System.WorkItemType")] public string Type { get; set; } + [JsonPropertyName("System.CreatedDate")] [JsonProperty("System.CreatedDate")] public DateTime CreatedDate { get; set; } + [JsonPropertyName("System.CreatedBy")] [JsonProperty("System.CreatedBy")] public string CreatedBy { get; set; } + [JsonPropertyName("System.ChangedBy")] [JsonProperty("System.ChangedBy")] public string ChangedBy { get; set; } + [JsonPropertyName("System.State")] [JsonProperty("System.State")] public string State { get; set; } + [JsonPropertyName("System.Title")] [JsonProperty("System.Title")] public string Title { get; set; } + [JsonPropertyName("System.Tags")] [JsonProperty("System.Tags")] public string Tags { get; set; } + [JsonPropertyName("System.Parent")] [JsonProperty("System.Parent")] - public string Parent { get; set; } + public string Parent { get; set; } + [JsonPropertyName("Microsoft.VSTS.Scheduling.StoryPoints")] [JsonProperty("Microsoft.VSTS.Scheduling.StoryPoints")] public string StoryPoints { get; set; } + [JsonPropertyName("Microsoft.VSTS.Scheduling.OriginalEstimate")] [JsonProperty("Microsoft.VSTS.Scheduling.OriginalEstimate")] public string OriginalEstimate { get; set; } + [JsonPropertyName("Microsoft.VSTS.Scheduling.RemainingWork")] [JsonProperty("Microsoft.VSTS.Scheduling.RemainingWork")] public string RemainingWork { get; set; } + [JsonPropertyName("Microsoft.VSTS.Scheduling.Effort")] [JsonProperty("Microsoft.VSTS.Scheduling.Effort")] public string Effort { get; set; } + [JsonPropertyName("Microsoft.VSTS.Common.Activity")] [JsonProperty("Microsoft.VSTS.Common.Activity")] public string Activity { get; set; } } diff --git a/AzureDevopsStateTracker/DTOs/Update/UpdateWorkItemDTO.cs b/AzureDevopsStateTracker/DTOs/Update/UpdateWorkItemDTO.cs index d0ba441..90b0d41 100644 --- a/AzureDevopsStateTracker/DTOs/Update/UpdateWorkItemDTO.cs +++ b/AzureDevopsStateTracker/DTOs/Update/UpdateWorkItemDTO.cs @@ -1,68 +1,73 @@ using Newtonsoft.Json; using System; +using System.Text.Json.Serialization; namespace AzureDevopsStateTracker.DTOs.Update { public class UpdatedWorkItemDTO { + [JsonPropertyName("resource")] [JsonProperty("resource")] public Resource Resource { get; set; } } public class Resource { + [JsonPropertyName("workItemId")] [JsonProperty("workItemId")] public string WorkItemId { get; set; } + [JsonPropertyName("fields")] [JsonProperty("fields")] public ResourceFields Fields { get; set; } + [JsonPropertyName("revision")] [JsonProperty("revision")] public Revision Revision { get; set; } } public class Revision { + [JsonPropertyName("fields")] [JsonProperty("fields")] public Fields Fields { get; set; } } public class ResourceFields { + [JsonPropertyName("System.State")] [JsonProperty("System.State")] public OldNewValues State { get; set; } + [JsonPropertyName("Microsoft.VSTS.Common.StateChangeDate")] [JsonProperty("Microsoft.VSTS.Common.StateChangeDate")] public DateTimeOldNewValues StateChangeDate { get; set; } + [JsonPropertyName("System.ChangedBy")] [JsonProperty("System.ChangedBy")] - public ChangedByOldNewValues ChangedBy { get; set; } + public OldNewValues ChangedBy { get; set; } } public class OldNewValues { + [JsonPropertyName("oldValue")] [JsonProperty("oldValue")] public string OldValue { get; set; } + [JsonPropertyName("newValue")] [JsonProperty("newValue")] public string NewValue { get; set; } } public class DateTimeOldNewValues { + [JsonPropertyName("oldValue")] [JsonProperty("oldValue")] public DateTime OldValue { get; set; } + [JsonPropertyName("newValue")] [JsonProperty("newValue")] public DateTime NewValue { get; set; } } - public class ChangedByOldNewValues - { - [JsonProperty("oldValue")] - public string OldValue { get; set; } - - [JsonProperty("newValue")] - public string NewValue { get; set; } - } } \ No newline at end of file diff --git a/AzureDevopsStateTracker/Data/DataBaseConfig.cs b/AzureDevopsStateTracker/Data/DataBaseConfig.cs index fbf1079..7cd63b1 100644 --- a/AzureDevopsStateTracker/Data/DataBaseConfig.cs +++ b/AzureDevopsStateTracker/Data/DataBaseConfig.cs @@ -1,20 +1,29 @@ using AzureDevopsStateTracker.Extensions; using System; +using System.Runtime.InteropServices; namespace AzureDevopsStateTracker.Data { public class DataBaseConfig { - public DataBaseConfig(string connectionsString, string schemaName = "dbo") + public DataBaseConfig(string connectionsString, string schemaName = "dbo", TimeZoneInfo timeZoneInfo = null) { if (connectionsString.IsNullOrEmpty()) throw new ArgumentException("The ConnectionsString is required"); + if (timeZoneInfo == null) + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("E. South America Standard Time"); + else + timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Brazil/East"); + ConnectionsString = connectionsString; SchemaName = schemaName; + TimeZoneInfo = timeZoneInfo; } public static string ConnectionsString { get; private set; } public static string SchemaName { get; private set; } + public static TimeZoneInfo TimeZoneInfo { get; private set; } } } \ No newline at end of file diff --git a/AzureDevopsStateTracker/Data/Repository.cs b/AzureDevopsStateTracker/Data/Repository.cs index 23d4673..74f7289 100644 --- a/AzureDevopsStateTracker/Data/Repository.cs +++ b/AzureDevopsStateTracker/Data/Repository.cs @@ -4,7 +4,7 @@ using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; -using System.Linq; +using System.Threading.Tasks; namespace AzureDevopsStateTracker.Data { @@ -19,14 +19,14 @@ public Repository(AzureDevopsStateTrackerContext db) DbSet = db.Set(); } - public virtual void Add(TEntity entity) + public virtual async Task Add(TEntity entity) { - DbSet.Add(entity); + await DbSet.AddAsync(entity); } - public virtual void Add(IEnumerable entities) + public virtual async Task Add(IEnumerable entities) { - DbSet.AddRange(entities); + await DbSet.AddRangeAsync(entities); } public virtual void Update(TEntity entity) @@ -44,22 +44,21 @@ public virtual void Delete(TEntity entity) DbSet.Remove(entity); } - public virtual TEntity GetById(string id) + public virtual async Task GetById(string id) { - return DbSet - .Where(x => x.Id == id) - .FirstOrDefault(); + return await DbSet + .FirstOrDefaultAsync(x => x.Id == id); } - public bool Exist(string id) + public async Task Exist(string id) { - return DbSet - .Any(x => x.Id == id); + return await DbSet + .AnyAsync(x => x.Id == id); } - - public void SaveChanges() + + public async Task SaveChangesAsync() { - Db.SaveChanges(); + await Db.SaveChangesAsync(); } public void Dispose() diff --git a/AzureDevopsStateTracker/Data/WorkItemRepository.cs b/AzureDevopsStateTracker/Data/WorkItemRepository.cs index 853f884..036d5e3 100644 --- a/AzureDevopsStateTracker/Data/WorkItemRepository.cs +++ b/AzureDevopsStateTracker/Data/WorkItemRepository.cs @@ -4,6 +4,7 @@ using Microsoft.EntityFrameworkCore; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; namespace AzureDevopsStateTracker.Data { @@ -11,28 +12,30 @@ internal class WorkItemRepository : Repository, IWorkItemRepository { public WorkItemRepository(AzureDevopsStateTrackerContext context) : base(context) { } - public WorkItem GetByWorkItemId(string workItemId) + public async Task GetByWorkItemId(string workItemId) { - return DbSet - .Include(x => x.WorkItemsChanges) - .Include(x => x.TimeByStates) - .FirstOrDefault(x => x.Id == workItemId); + return await DbSet + .Include(x => x.WorkItemsChanges) + .Include(x => x.TimeByStates) + .FirstOrDefaultAsync(x => x.Id == workItemId); } - public IEnumerable ListByWorkItemId(IEnumerable workItemsId) + public async Task> ListByWorkItemId(IEnumerable workItemsId) { - return DbSet - .Include(x => x.WorkItemsChanges) - .Include(x => x.TimeByStates) - .Where(x => workItemsId.Contains(x.Id)); + return await DbSet + .Include(x => x.WorkItemsChanges) + .Include(x => x.TimeByStates) + .Where(x => workItemsId.Contains(x.Id)) + .ToListAsync(); } - public IEnumerable ListByIterationPath(string iterationPath) + public async Task> ListByIterationPath(string iterationPath) { - return DbSet - .Include(x => x.WorkItemsChanges) - .Include(x => x.TimeByStates) - .Where(x => x.IterationPath == iterationPath); + return await DbSet + .Include(x => x.WorkItemsChanges) + .Include(x => x.TimeByStates) + .Where(x => x.IterationPath == iterationPath) + .ToListAsync(); } public void RemoveAllTimeByState(List timeByStates) diff --git a/AzureDevopsStateTracker/Entities/WorkItem.cs b/AzureDevopsStateTracker/Entities/WorkItem.cs index 64aa79c..7bd3362 100644 --- a/AzureDevopsStateTracker/Entities/WorkItem.cs +++ b/AzureDevopsStateTracker/Entities/WorkItem.cs @@ -20,7 +20,6 @@ public class WorkItem : Entity public string StoryPoints { get; private set; } public string WorkItemParentId { get; private set; } public string Activity { get; private set; } - private readonly List _workItemsChanges; public IReadOnlyCollection WorkItemsChanges => _workItemsChanges; @@ -116,7 +115,7 @@ public IEnumerable CalculateTotalTimeByState() foreach (var data in workItemChange) { totalTime += data.CalculateTotalTime(); - totalWorkedTime += data.CalculateTotalWorkedTime(); + totalWorkedTime += TimeSpan.FromSeconds(data.CalculateTotalWorkedTime()); } timesByStateList.Add(new TimeByState(Id, workItemChange.Key, totalTime, totalWorkedTime)); diff --git a/AzureDevopsStateTracker/Entities/WorkItemChange.cs b/AzureDevopsStateTracker/Entities/WorkItemChange.cs index b7baac5..db63a95 100644 --- a/AzureDevopsStateTracker/Entities/WorkItemChange.cs +++ b/AzureDevopsStateTracker/Entities/WorkItemChange.cs @@ -35,25 +35,128 @@ public void Validate() public TimeSpan CalculateTotalTime() { - return OldDate == null ? TimeSpan.Zero : NewDate - OldDate.GetValueOrDefault(); + return OldDate == null ? TimeSpan.Zero : NewDate.ToDateTimeFromTimeZoneInfo() - OldDate.Value.ToDateTimeFromTimeZoneInfo(); } - public TimeSpan CalculateTotalWorkedTime() + public double CalculateTotalWorkedTime() { if (OldDate.GetValueOrDefault() == DateTime.MinValue) - return TimeSpan.Zero; + return 0; - TimeSpan hoursWorked = TimeSpan.Zero; - for (var i = OldDate.GetValueOrDefault(); i <= NewDate; i = i.AddHours(1)) + var oldDate = OldDate.Value.ToDateTimeFromTimeZoneInfo(); + var newDate = NewDate.ToDateTimeFromTimeZoneInfo(); + + var secondsWorked = 0D; + var majorDateBeforeLunch = DateTime.MinValue; + var minorDateBeforeLunch = DateTime.MinValue; + var majorDateAfterLunch = DateTime.MinValue; + var minorDateAfterLunch = DateTime.MinValue; + + DateTime dataAux = DateTime.MinValue; + int diasCompletos = 0; + + TimeSpan afterLunch; + TimeSpan beforeLunch; + + for (var dateAux = oldDate; dateAux <= newDate; dateAux = dateAux.AddSeconds(1)) { - if (i.DayOfWeek != DayOfWeek.Saturday && i.DayOfWeek != DayOfWeek.Sunday) + if (dateAux.DayOfWeek == DayOfWeek.Saturday || dateAux.DayOfWeek == DayOfWeek.Sunday) + continue; + + if (dateAux.TimeOfDay.Hours >= 12 && dateAux.TimeOfDay.Hours < 14) + continue; + + if (dateAux.TimeOfDay.Hours > 18 && dateAux.TimeOfDay.Hours < 23 || + dateAux.TimeOfDay.Hours >= 0 && dateAux.TimeOfDay.Hours < 8) + continue; + + if (dataAux == DateTime.MinValue) + dataAux = dateAux; + + if (dataAux != DateTime.MinValue && dataAux.Date != dateAux.Date) + { + beforeLunch = SubtractDates(majorDateBeforeLunch, minorDateBeforeLunch); + afterLunch = SubtractDates(majorDateAfterLunch, minorDateAfterLunch); + + if ((beforeLunch + afterLunch).Hours == 8) + diasCompletos++; + else + secondsWorked += (beforeLunch + afterLunch).TotalSeconds; + + majorDateBeforeLunch = DateTime.MinValue; + minorDateBeforeLunch = DateTime.MinValue; + + majorDateAfterLunch = DateTime.MinValue; + minorDateAfterLunch = DateTime.MinValue; + dataAux = dateAux; + } + + if (dateAux.TimeOfDay.Hours >= 8 && dateAux.TimeOfDay.Hours < 12) + { + if (minorDateBeforeLunch == DateTime.MinValue || dateAux < minorDateBeforeLunch) + minorDateBeforeLunch = dateAux; + + if (majorDateBeforeLunch == DateTime.MinValue || dateAux > majorDateBeforeLunch) + majorDateBeforeLunch = dateAux; + + continue; + } + + if (dateAux.TimeOfDay.Hours >= 14 && dateAux.TimeOfDay.Hours < 18) { - if ((i.TimeOfDay.Hours >= 8 && i.TimeOfDay.Hours < 12) || (i.TimeOfDay.Hours >= 14 && i.TimeOfDay.Hours < 18)) - hoursWorked += (NewDate.TimeOfDay - i.TimeOfDay); + if (minorDateAfterLunch == DateTime.MinValue || dateAux < minorDateAfterLunch) + minorDateAfterLunch = dateAux; + + if (majorDateAfterLunch == DateTime.MinValue || dateAux > majorDateAfterLunch) + majorDateAfterLunch = dateAux; + + continue; } + + } + + if (dataAux != DateTime.MinValue && + oldDate.Date == newDate.Date || + (majorDateBeforeLunch != DateTime.MinValue || minorDateBeforeLunch != DateTime.MinValue) || + (majorDateAfterLunch != DateTime.MinValue || minorDateAfterLunch != DateTime.MinValue)) + { + beforeLunch = SubtractDates(majorDateBeforeLunch, minorDateBeforeLunch); + afterLunch = SubtractDates(majorDateAfterLunch, minorDateAfterLunch); + + secondsWorked += (beforeLunch + afterLunch).TotalSeconds; } - return hoursWorked; + if (diasCompletos > 0) + secondsWorked += diasCompletos * 28800; + + return secondsWorked; + } + + private TimeSpan SubtractDates(DateTime biger, DateTime minor) + { + if (biger.Hour == minor.Hour) + { + return biger.Subtract(minor); + } + else if (biger.Hour > 8 && biger.Hour == 11 && biger.Minute == 59) + { + var newMajorDate = new DateTime(biger.Year, biger.Month, biger.Day, 12, 0, 0); + return newMajorDate.Subtract(minor); + } + else if (biger.Hour > 14 && biger.Hour < minor.Hour) + { + var newMinorDate = new DateTime(minor.Year, minor.Month, minor.Day, 14, 0, 0); + return biger.Subtract(newMinorDate); + } + else if (biger.Hour > 14 && biger.Hour == 17 && biger.Minute == 59) + { + var newMajorDate = new DateTime(biger.Year, biger.Month, biger.Day, 18, 0, 0); + return newMajorDate.Subtract(minor); + } + else + { + return biger.Subtract(minor); + } } } } \ No newline at end of file diff --git a/AzureDevopsStateTracker/Extensions/HelperExtenions.cs b/AzureDevopsStateTracker/Extensions/HelperExtenions.cs index 286b592..cf8cb21 100644 --- a/AzureDevopsStateTracker/Extensions/HelperExtenions.cs +++ b/AzureDevopsStateTracker/Extensions/HelperExtenions.cs @@ -1,4 +1,5 @@ -using System; +using AzureDevopsStateTracker.Data; +using System; using System.Linq; namespace AzureDevopsStateTracker.Extensions @@ -37,5 +38,10 @@ public static string ToTextTime(this TimeSpan timeSpan) return "-"; } + + public static DateTime ToDateTimeFromTimeZoneInfo(this DateTime date) + { + return TimeZoneInfo.ConvertTimeFromUtc(date, DataBaseConfig.TimeZoneInfo); + } } } \ No newline at end of file diff --git a/AzureDevopsStateTracker/Interfaces/IAzureDevopsStateTrackerService.cs b/AzureDevopsStateTracker/Interfaces/IAzureDevopsStateTrackerService.cs index a0ef0f9..b5f47a9 100644 --- a/AzureDevopsStateTracker/Interfaces/IAzureDevopsStateTrackerService.cs +++ b/AzureDevopsStateTracker/Interfaces/IAzureDevopsStateTrackerService.cs @@ -1,13 +1,14 @@ using AzureDevopsStateTracker.DTOs; using AzureDevopsStateTracker.DTOs.Create; using AzureDevopsStateTracker.DTOs.Update; +using System.Threading.Tasks; namespace AzureDevopsStateTracker.Interfaces { public interface IAzureDevopsStateTrackerService { - void Create(CreateWorkItemDTO createDto); - void Update(UpdatedWorkItemDTO updateDto); - WorkItemDTO GetByWorkItemId(string workItemId); + Task Create(CreateWorkItemDTO createDto, bool addWorkItemChange = true); + Task Update(UpdatedWorkItemDTO updateDto); + Task GetByWorkItemId(string workItemId); } } \ No newline at end of file diff --git a/AzureDevopsStateTracker/Interfaces/Internals/IRepository.cs b/AzureDevopsStateTracker/Interfaces/Internals/IRepository.cs index adbfb76..a7fbca5 100644 --- a/AzureDevopsStateTracker/Interfaces/Internals/IRepository.cs +++ b/AzureDevopsStateTracker/Interfaces/Internals/IRepository.cs @@ -1,18 +1,19 @@ using AzureDevopsStateTracker.Entities; using System; using System.Collections.Generic; +using System.Threading.Tasks; namespace AzureDevopsStateTracker.Interfaces.Internals { public interface IRepository : IDisposable where TEntity : Entity { - void Add(TEntity entity); - void Add(IEnumerable entities); - TEntity GetById(string id); - bool Exist(string id); + Task Add(TEntity entity); + Task Add(IEnumerable entities); + Task GetById(string id); + Task Exist(string id); void Update(TEntity entity); void Update(IEnumerable entities); void Delete(TEntity entity); - void SaveChanges(); + Task SaveChangesAsync(); } } \ No newline at end of file diff --git a/AzureDevopsStateTracker/Interfaces/Internals/IWorkItemRepository.cs b/AzureDevopsStateTracker/Interfaces/Internals/IWorkItemRepository.cs index 82e93b9..69c031b 100644 --- a/AzureDevopsStateTracker/Interfaces/Internals/IWorkItemRepository.cs +++ b/AzureDevopsStateTracker/Interfaces/Internals/IWorkItemRepository.cs @@ -1,13 +1,14 @@ using AzureDevopsStateTracker.Entities; using System.Collections.Generic; +using System.Threading.Tasks; namespace AzureDevopsStateTracker.Interfaces.Internals { public interface IWorkItemRepository : IRepository { - WorkItem GetByWorkItemId(string workItemId); - IEnumerable ListByWorkItemId(IEnumerable workItemsId); - IEnumerable ListByIterationPath(string iterationPath); + Task GetByWorkItemId(string workItemId); + Task> ListByWorkItemId(IEnumerable workItemsId); + Task> ListByIterationPath(string iterationPath); void RemoveAllTimeByState(List timeByStates); } } \ No newline at end of file diff --git a/AzureDevopsStateTracker/Services/AzureDevopsStateTrackerService.cs b/AzureDevopsStateTracker/Services/AzureDevopsStateTrackerService.cs index f9c1bfb..ad0c49f 100644 --- a/AzureDevopsStateTracker/Services/AzureDevopsStateTrackerService.cs +++ b/AzureDevopsStateTracker/Services/AzureDevopsStateTrackerService.cs @@ -7,6 +7,7 @@ using AzureDevopsStateTracker.Interfaces.Internals; using System; using System.Linq; +using System.Threading.Tasks; namespace AzureDevopsStateTracker.Services { @@ -22,7 +23,7 @@ public AzureDevopsStateTrackerService( _workItemRepository = workItemRepository; } - public void Create(CreateWorkItemDTO create) + public async Task Create(CreateWorkItemDTO create, bool addWorkItemChange = true) { var workItem = new WorkItem(create.Resource.Id); @@ -40,15 +41,33 @@ public void Create(CreateWorkItemDTO create) create.Resource.Fields.OriginalEstimate, create.Resource.Fields.Activity); - AddWorkItemChange(workItem, create); + if (addWorkItemChange) + AddWorkItemChange(workItem, create); - _workItemRepository.Add(workItem); - _workItemRepository.SaveChanges(); + await _workItemRepository.Add(workItem); + await _workItemRepository.SaveChangesAsync(); } - public void Update(UpdatedWorkItemDTO update) + public async Task Create(UpdatedWorkItemDTO updateDto) { - var workItem = _workItemRepository.GetByWorkItemId(update.Resource.WorkItemId); + var createDto = new CreateWorkItemDTO() + { + Resource = new DTOs.Create.Resource() + { + Fields = updateDto.Resource.Revision.Fields, + Id = updateDto.Resource.WorkItemId, + } + }; + + await Create(createDto, false); + } + + public async Task Update(UpdatedWorkItemDTO update) + { + if (!_workItemRepository.Exist(update.Resource.WorkItemId).Result) + await Create(update); + + var workItem = await _workItemRepository.GetByWorkItemId(update.Resource.WorkItemId); if (workItem is null) return; @@ -69,12 +88,12 @@ public void Update(UpdatedWorkItemDTO update) AddWorkItemChange(workItem, update); _workItemRepository.Update(workItem); - _workItemRepository.SaveChanges(); + await _workItemRepository.SaveChangesAsync(); } - public WorkItemDTO GetByWorkItemId(string workItemId) + public async Task GetByWorkItemId(string workItemId) { - var workItem = _workItemRepository.GetByWorkItemId(workItemId); + var workItem = await _workItemRepository.GetByWorkItemId(workItemId); if (workItem is null) return null; @@ -91,7 +110,7 @@ public void AddWorkItemChange(WorkItem workItem, CreateWorkItemDTO create) { var workItemChange = ToWorkItemChange(workItem.Id, create.Resource.Fields.ChangedBy, - create.Resource.Fields.CreatedDate, + create.Resource.Fields.CreatedDate.ToDateTimeFromTimeZoneInfo(), create.Resource.Fields.State); workItem.AddWorkItemChange(workItemChange); @@ -102,10 +121,10 @@ public void AddWorkItemChange(WorkItem workItem, UpdatedWorkItemDTO update) var changedBy = update.Resource.Revision.Fields.ChangedBy ?? update.Resource.Fields.ChangedBy.NewValue; var workItemChange = ToWorkItemChange(workItem.Id, changedBy, - update.Resource.Fields.StateChangeDate.NewValue, + update.Resource.Fields.StateChangeDate.NewValue.ToDateTimeFromTimeZoneInfo(), update.Resource.Fields.State.NewValue, update.Resource.Fields.State.OldValue, - update.Resource.Fields.StateChangeDate.OldValue); + update.Resource.Fields.StateChangeDate.OldValue.ToDateTimeFromTimeZoneInfo()); workItem.AddWorkItemChange(workItemChange); From 80fdcf7c8f01afd2bde1d6ca57f822bf199faad2 Mon Sep 17 00:00:00 2001 From: Diego Galante Date: Mon, 4 Oct 2021 18:57:45 -0300 Subject: [PATCH 03/11] Updating --- .../AzureDevOpsStateTracker.Functions.csproj | 6 +- .../AzureDevOpsStateTracker.Functions.sln | 6 - .../WorkItemFunctions.cs | 18 +- .../Adapters/WorkItemAdapter.cs | 109 ------------ .../AzureDevopsStateTracker.csproj | 13 -- .../AzureDevopsStateTracker.sln | 25 --- .../Configurations/Configuration.cs | 37 ---- .../DTOs/Create/CreateWorkItemDTO.cs | 23 --- AzureDevopsStateTracker/DTOs/Fields.cs | 77 --------- .../DTOs/Update/UpdateWorkItemDTO.cs | 73 -------- AzureDevopsStateTracker/DTOs/WorkItemDTO.cs | 100 ----------- .../Context/AzureDevopsStateTrackerContext.cs | 32 ---- .../Data/DataBaseConfig.cs | 29 ---- AzureDevopsStateTracker/Data/Repository.cs | 69 -------- .../Data/WorkItemRepository.cs | 46 ----- AzureDevopsStateTracker/Entities/Entity.cs | 21 --- .../Entities/TimeByState.cs | 36 ---- AzureDevopsStateTracker/Entities/WorkItem.cs | 127 -------------- .../Entities/WorkItemChange.cs | 162 ------------------ .../Extensions/HelperExtenions.cs | 47 ----- .../IAzureDevopsStateTrackerService.cs | 14 -- .../Interfaces/IWorkItemAdapter.cs | 12 -- .../Interfaces/Internals/IRepository.cs | 19 -- .../Internals/IWorkItemRepository.cs | 14 -- ...AzureDevopsStateTrackerInitial.Designer.cs | 154 ----------------- ...19163846_AzureDevopsStateTrackerInitial.cs | 118 ------------- ...20105645_FunctionToTimeInitial.Designer.cs | 154 ----------------- .../20210720105645_FunctionToTimeInitial.cs | 50 ------ ...eDevopsStateTrackerContextModelSnapshot.cs | 152 ---------------- .../AzureDevopsStateTrackerService.cs | 148 ---------------- 30 files changed, 11 insertions(+), 1880 deletions(-) delete mode 100644 AzureDevopsStateTracker/Adapters/WorkItemAdapter.cs delete mode 100644 AzureDevopsStateTracker/AzureDevopsStateTracker.csproj delete mode 100644 AzureDevopsStateTracker/AzureDevopsStateTracker.sln delete mode 100644 AzureDevopsStateTracker/Configurations/Configuration.cs delete mode 100644 AzureDevopsStateTracker/DTOs/Create/CreateWorkItemDTO.cs delete mode 100644 AzureDevopsStateTracker/DTOs/Fields.cs delete mode 100644 AzureDevopsStateTracker/DTOs/Update/UpdateWorkItemDTO.cs delete mode 100644 AzureDevopsStateTracker/DTOs/WorkItemDTO.cs delete mode 100644 AzureDevopsStateTracker/Data/Context/AzureDevopsStateTrackerContext.cs delete mode 100644 AzureDevopsStateTracker/Data/DataBaseConfig.cs delete mode 100644 AzureDevopsStateTracker/Data/Repository.cs delete mode 100644 AzureDevopsStateTracker/Data/WorkItemRepository.cs delete mode 100644 AzureDevopsStateTracker/Entities/Entity.cs delete mode 100644 AzureDevopsStateTracker/Entities/TimeByState.cs delete mode 100644 AzureDevopsStateTracker/Entities/WorkItem.cs delete mode 100644 AzureDevopsStateTracker/Entities/WorkItemChange.cs delete mode 100644 AzureDevopsStateTracker/Extensions/HelperExtenions.cs delete mode 100644 AzureDevopsStateTracker/Interfaces/IAzureDevopsStateTrackerService.cs delete mode 100644 AzureDevopsStateTracker/Interfaces/IWorkItemAdapter.cs delete mode 100644 AzureDevopsStateTracker/Interfaces/Internals/IRepository.cs delete mode 100644 AzureDevopsStateTracker/Interfaces/Internals/IWorkItemRepository.cs delete mode 100644 AzureDevopsStateTracker/Migrations/20210719163846_AzureDevopsStateTrackerInitial.Designer.cs delete mode 100644 AzureDevopsStateTracker/Migrations/20210719163846_AzureDevopsStateTrackerInitial.cs delete mode 100644 AzureDevopsStateTracker/Migrations/20210720105645_FunctionToTimeInitial.Designer.cs delete mode 100644 AzureDevopsStateTracker/Migrations/20210720105645_FunctionToTimeInitial.cs delete mode 100644 AzureDevopsStateTracker/Migrations/AzureDevopsStateTrackerContextModelSnapshot.cs delete mode 100644 AzureDevopsStateTracker/Services/AzureDevopsStateTrackerService.cs diff --git a/AzureDevOpsStateTracker.Functions/AzureDevOpsStateTracker.Functions.csproj b/AzureDevOpsStateTracker.Functions/AzureDevOpsStateTracker.Functions.csproj index af9f886..264a135 100644 --- a/AzureDevOpsStateTracker.Functions/AzureDevOpsStateTracker.Functions.csproj +++ b/AzureDevOpsStateTracker.Functions/AzureDevOpsStateTracker.Functions.csproj @@ -6,13 +6,11 @@ true + - + - - - PreserveNewest diff --git a/AzureDevOpsStateTracker.Functions/AzureDevOpsStateTracker.Functions.sln b/AzureDevOpsStateTracker.Functions/AzureDevOpsStateTracker.Functions.sln index da8e283..ba1c1f3 100644 --- a/AzureDevOpsStateTracker.Functions/AzureDevOpsStateTracker.Functions.sln +++ b/AzureDevOpsStateTracker.Functions/AzureDevOpsStateTracker.Functions.sln @@ -5,8 +5,6 @@ VisualStudioVersion = 16.0.31229.75 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AzureDevOpsStateTracker.Functions", "AzureDevOpsStateTracker.Functions.csproj", "{3C86C085-C8C6-46BB-8315-D4348928034C}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AzureDevopsStateTracker", "..\AzureDevopsStateTracker\AzureDevopsStateTracker.csproj", "{9F58B2EA-6594-41E5-8BAD-DAC7DF9CADA7}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -17,10 +15,6 @@ Global {3C86C085-C8C6-46BB-8315-D4348928034C}.Debug|Any CPU.Build.0 = Debug|Any CPU {3C86C085-C8C6-46BB-8315-D4348928034C}.Release|Any CPU.ActiveCfg = Release|Any CPU {3C86C085-C8C6-46BB-8315-D4348928034C}.Release|Any CPU.Build.0 = Release|Any CPU - {9F58B2EA-6594-41E5-8BAD-DAC7DF9CADA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9F58B2EA-6594-41E5-8BAD-DAC7DF9CADA7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9F58B2EA-6594-41E5-8BAD-DAC7DF9CADA7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9F58B2EA-6594-41E5-8BAD-DAC7DF9CADA7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/AzureDevOpsStateTracker.Functions/WorkItemFunctions.cs b/AzureDevOpsStateTracker.Functions/WorkItemFunctions.cs index 289302c..e55f829 100644 --- a/AzureDevOpsStateTracker.Functions/WorkItemFunctions.cs +++ b/AzureDevOpsStateTracker.Functions/WorkItemFunctions.cs @@ -1,7 +1,7 @@ -using AzureDevopsStateTracker.DTOs.Create; -using AzureDevopsStateTracker.DTOs.Update; -using AzureDevopsStateTracker.Services; using AzureDevOpsStateTracker.Functions.Extensions; +using AzureDevopsTracker.DTOs.Create; +using AzureDevopsTracker.DTOs.Update; +using AzureDevopsTracker.Services; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.WebJobs; @@ -12,16 +12,16 @@ using System.Net; using System.Threading.Tasks; -namespace AzureDevOpsStateTracker.Functions +namespace AzureDevOpsTracker.Functions { public class WorkItemFunctions { - private readonly AzureDevopsStateTrackerService _azureDevopsStateTrackerService; + private readonly AzureDevopsTrackerService _azureDevopsTrackerService; public WorkItemFunctions( - AzureDevopsStateTrackerService azureDevopsStateTrackerService) + AzureDevopsTrackerService azureDevopsTrackerService) { - _azureDevopsStateTrackerService = azureDevopsStateTrackerService; + _azureDevopsTrackerService = azureDevopsTrackerService; } [FunctionName("workitem")] @@ -33,7 +33,7 @@ public async Task Create( try { var workItemDTO = JsonConvert.DeserializeObject(req.GetBody()); - await _azureDevopsStateTrackerService.Create(workItemDTO); + await _azureDevopsTrackerService.Create(workItemDTO); } catch (Exception ex) { @@ -51,7 +51,7 @@ public async Task Update( try { var workItemDTO = JsonConvert.DeserializeObject(req.GetBody()); - await _azureDevopsStateTrackerService.Update(workItemDTO); + await _azureDevopsTrackerService.Update(workItemDTO); } catch (Exception ex) { diff --git a/AzureDevopsStateTracker/Adapters/WorkItemAdapter.cs b/AzureDevopsStateTracker/Adapters/WorkItemAdapter.cs deleted file mode 100644 index 904f362..0000000 --- a/AzureDevopsStateTracker/Adapters/WorkItemAdapter.cs +++ /dev/null @@ -1,109 +0,0 @@ -using AzureDevopsStateTracker.DTOs; -using AzureDevopsStateTracker.Entities; -using AzureDevopsStateTracker.Interfaces; -using System.Collections.Generic; -using System.Linq; - -namespace AzureDevopsStateTracker.Adapters -{ - internal class WorkItemAdapter : IWorkItemAdapter - { - public WorkItemDTO ToWorkItemDTO(WorkItem workItem) - { - if (workItem == null) return null; - - return new WorkItemDTO() - { - Id = workItem.Id, - CreatedAt = workItem.CreatedAt, - AssignedTo = workItem.AssignedTo, - CreatedBy = workItem.CreatedBy, - CurrentStatus = workItem.CurrentStatus, - TeamProject = workItem.TeamProject, - AreaPath = workItem.AreaPath, - IterationPath = workItem.IterationPath, - Title = workItem.Title, - Type = workItem.Type, - Effort = workItem.Effort, - StoryPoints = workItem.StoryPoints, - OriginalEstimate = workItem.OriginalEstimate, - WorkItemParentId = workItem.WorkItemParentId, - Activity = workItem.Activity, - Tags = workItem.Tags == null ? new List() : workItem.Tags.Split(';').ToList(), - WorkItemsChangesDTO = ToWorkItemsChangeDTO(workItem.WorkItemsChanges.OrderBy(x => x.CreatedAt).ToList()), - TimesByStateDTO = ToTimeByStatesDTO(workItem.CalculateTotalTimeByState().ToList()), - }; - } - - public List ToWorkItemsDTO(List workItems) - { - var workItemsDTO = new List(); - - if (workItems == null) return workItemsDTO; - - workItems.ForEach( - workItem => - workItemsDTO.Add(ToWorkItemDTO(workItem))); - - return workItemsDTO - .ToList(); - } - - public WorkItemChangeDTO ToWorkItemChangeDTO(WorkItemChange workIteChange) - { - if (workIteChange == null) return null; - - return new WorkItemChangeDTO() - { - NewDate = workIteChange.NewDate, - NewState = workIteChange.NewState, - OldState = workIteChange.OldState, - OldDate = workIteChange.OldDate, - ChangedBy = workIteChange.ChangedBy - }; - } - - public List ToWorkItemsChangeDTO(List workItemsChanges) - { - var workItemsChangeDTO = new List(); - - if (workItemsChanges == null) return workItemsChangeDTO; - - workItemsChanges.ForEach( - workItemsChange => - workItemsChangeDTO.Add(ToWorkItemChangeDTO(workItemsChange))); - - return workItemsChangeDTO - .Where(w => w != null) - .ToList(); - } - - public TimeByStateDTO ToTimeByStateDTO(TimeByState workItemStatusTime) - { - if (workItemStatusTime == null) return null; - - return new TimeByStateDTO() - { - CreatedAt = workItemStatusTime.CreatedAt, - State = workItemStatusTime.State, - //TotalTime = workItemStatusTime.TotalTimeText, - //TotalWorkedTime = workItemStatusTime.TotalWorkedTimeText - }; - } - - public List ToTimeByStatesDTO(List workItemStatusTimes) - { - var workItemStatusTimeDTO = new List(); - - if (workItemStatusTimes == null) return workItemStatusTimeDTO; - - workItemStatusTimes.ForEach( - workItemStatusTime => - workItemStatusTimeDTO.Add(ToTimeByStateDTO(workItemStatusTime))); - - return workItemStatusTimeDTO - .Where(w => w != null) - .ToList(); - } - } -} \ No newline at end of file diff --git a/AzureDevopsStateTracker/AzureDevopsStateTracker.csproj b/AzureDevopsStateTracker/AzureDevopsStateTracker.csproj deleted file mode 100644 index 1f1d5ca..0000000 --- a/AzureDevopsStateTracker/AzureDevopsStateTracker.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - netcoreapp3.1 - false - - - - - - - - \ No newline at end of file diff --git a/AzureDevopsStateTracker/AzureDevopsStateTracker.sln b/AzureDevopsStateTracker/AzureDevopsStateTracker.sln deleted file mode 100644 index 1a63535..0000000 --- a/AzureDevopsStateTracker/AzureDevopsStateTracker.sln +++ /dev/null @@ -1,25 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.31402.337 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AzureDevopsStateTracker", "AzureDevopsStateTracker.csproj", "{E00DFF81-08B1-4A71-82C4-7CED951299BE}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {E00DFF81-08B1-4A71-82C4-7CED951299BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E00DFF81-08B1-4A71-82C4-7CED951299BE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E00DFF81-08B1-4A71-82C4-7CED951299BE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E00DFF81-08B1-4A71-82C4-7CED951299BE}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {53133A2B-5357-47B5-A1C4-30953F789623} - EndGlobalSection -EndGlobal diff --git a/AzureDevopsStateTracker/Configurations/Configuration.cs b/AzureDevopsStateTracker/Configurations/Configuration.cs deleted file mode 100644 index a20ca36..0000000 --- a/AzureDevopsStateTracker/Configurations/Configuration.cs +++ /dev/null @@ -1,37 +0,0 @@ -using AzureDevopsStateTracker.Adapters; -using AzureDevopsStateTracker.Data; -using AzureDevopsStateTracker.Data.Context; -using AzureDevopsStateTracker.Interfaces; -using AzureDevopsStateTracker.Interfaces.Internals; -using AzureDevopsStateTracker.Services; -using Microsoft.AspNetCore.Builder; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; -using System; - -namespace AzureDevopsStateTracker.Configurations -{ - public static class Configuration - { - public static IServiceCollection AddAzureDevopsStateTracker(this IServiceCollection services, DataBaseConfig configurations) - { - services.AddDbContext(options => - options.UseSqlServer(DataBaseConfig.ConnectionsString)); - - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - - return services; - } - - public static IApplicationBuilder UseAzureDevopsStateTracker(this IApplicationBuilder app, IServiceProvider serviceProvider) - { - var context = serviceProvider.GetService(); - context.Database.Migrate(); - - return app; - } - } -} \ No newline at end of file diff --git a/AzureDevopsStateTracker/DTOs/Create/CreateWorkItemDTO.cs b/AzureDevopsStateTracker/DTOs/Create/CreateWorkItemDTO.cs deleted file mode 100644 index d2cb228..0000000 --- a/AzureDevopsStateTracker/DTOs/Create/CreateWorkItemDTO.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Newtonsoft.Json; -using System.Text.Json.Serialization; - -namespace AzureDevopsStateTracker.DTOs.Create -{ - public class CreateWorkItemDTO - { - [JsonPropertyName("resource")] - [JsonProperty("resource")] - public Resource Resource { get; set; } - } - - public class Resource - { - [JsonPropertyName("id")] - [JsonProperty("id")] - public string Id { get; set; } - - [JsonPropertyName("fields")] - [JsonProperty("fields")] - public Fields Fields { get; set; } - } -} \ No newline at end of file diff --git a/AzureDevopsStateTracker/DTOs/Fields.cs b/AzureDevopsStateTracker/DTOs/Fields.cs deleted file mode 100644 index 711bfbf..0000000 --- a/AzureDevopsStateTracker/DTOs/Fields.cs +++ /dev/null @@ -1,77 +0,0 @@ -using Newtonsoft.Json; -using System; -using System.Text.Json.Serialization; - -namespace AzureDevopsStateTracker.DTOs -{ - public class Fields - { - [JsonPropertyName("System.AreaPath")] - [JsonProperty("System.AreaPath")] - public string AreaPath { get; set; } - - [JsonPropertyName("System.TeamProject")] - [JsonProperty("System.TeamProject")] - public string TeamProject { get; set; } - - [JsonPropertyName("System.IterationPath")] - [JsonProperty("System.IterationPath")] - public string IterationPath { get; set; } - - [JsonPropertyName("System.AssignedTo")] - [JsonProperty("System.AssignedTo")] - public string AssignedTo { get; set; } - - [JsonPropertyName("System.WorkItemType")] - [JsonProperty("System.WorkItemType")] - public string Type { get; set; } - - [JsonPropertyName("System.CreatedDate")] - [JsonProperty("System.CreatedDate")] - public DateTime CreatedDate { get; set; } - - [JsonPropertyName("System.CreatedBy")] - [JsonProperty("System.CreatedBy")] - public string CreatedBy { get; set; } - - [JsonPropertyName("System.ChangedBy")] - [JsonProperty("System.ChangedBy")] - public string ChangedBy { get; set; } - - [JsonPropertyName("System.State")] - [JsonProperty("System.State")] - public string State { get; set; } - - [JsonPropertyName("System.Title")] - [JsonProperty("System.Title")] - public string Title { get; set; } - - [JsonPropertyName("System.Tags")] - [JsonProperty("System.Tags")] - public string Tags { get; set; } - - [JsonPropertyName("System.Parent")] - [JsonProperty("System.Parent")] - public string Parent { get; set; } - - [JsonPropertyName("Microsoft.VSTS.Scheduling.StoryPoints")] - [JsonProperty("Microsoft.VSTS.Scheduling.StoryPoints")] - public string StoryPoints { get; set; } - - [JsonPropertyName("Microsoft.VSTS.Scheduling.OriginalEstimate")] - [JsonProperty("Microsoft.VSTS.Scheduling.OriginalEstimate")] - public string OriginalEstimate { get; set; } - - [JsonPropertyName("Microsoft.VSTS.Scheduling.RemainingWork")] - [JsonProperty("Microsoft.VSTS.Scheduling.RemainingWork")] - public string RemainingWork { get; set; } - - [JsonPropertyName("Microsoft.VSTS.Scheduling.Effort")] - [JsonProperty("Microsoft.VSTS.Scheduling.Effort")] - public string Effort { get; set; } - - [JsonPropertyName("Microsoft.VSTS.Common.Activity")] - [JsonProperty("Microsoft.VSTS.Common.Activity")] - public string Activity { get; set; } - } -} \ No newline at end of file diff --git a/AzureDevopsStateTracker/DTOs/Update/UpdateWorkItemDTO.cs b/AzureDevopsStateTracker/DTOs/Update/UpdateWorkItemDTO.cs deleted file mode 100644 index 90b0d41..0000000 --- a/AzureDevopsStateTracker/DTOs/Update/UpdateWorkItemDTO.cs +++ /dev/null @@ -1,73 +0,0 @@ -using Newtonsoft.Json; -using System; -using System.Text.Json.Serialization; - -namespace AzureDevopsStateTracker.DTOs.Update -{ - public class UpdatedWorkItemDTO - { - [JsonPropertyName("resource")] - [JsonProperty("resource")] - public Resource Resource { get; set; } - } - - public class Resource - { - [JsonPropertyName("workItemId")] - [JsonProperty("workItemId")] - public string WorkItemId { get; set; } - - [JsonPropertyName("fields")] - [JsonProperty("fields")] - public ResourceFields Fields { get; set; } - - [JsonPropertyName("revision")] - [JsonProperty("revision")] - public Revision Revision { get; set; } - } - - public class Revision - { - [JsonPropertyName("fields")] - [JsonProperty("fields")] - public Fields Fields { get; set; } - } - - public class ResourceFields - { - [JsonPropertyName("System.State")] - [JsonProperty("System.State")] - public OldNewValues State { get; set; } - - [JsonPropertyName("Microsoft.VSTS.Common.StateChangeDate")] - [JsonProperty("Microsoft.VSTS.Common.StateChangeDate")] - public DateTimeOldNewValues StateChangeDate { get; set; } - - [JsonPropertyName("System.ChangedBy")] - [JsonProperty("System.ChangedBy")] - public OldNewValues ChangedBy { get; set; } - } - - public class OldNewValues - { - [JsonPropertyName("oldValue")] - [JsonProperty("oldValue")] - public string OldValue { get; set; } - - [JsonPropertyName("newValue")] - [JsonProperty("newValue")] - public string NewValue { get; set; } - } - - public class DateTimeOldNewValues - { - [JsonPropertyName("oldValue")] - [JsonProperty("oldValue")] - public DateTime OldValue { get; set; } - - [JsonPropertyName("newValue")] - [JsonProperty("newValue")] - public DateTime NewValue { get; set; } - } - -} \ No newline at end of file diff --git a/AzureDevopsStateTracker/DTOs/WorkItemDTO.cs b/AzureDevopsStateTracker/DTOs/WorkItemDTO.cs deleted file mode 100644 index d9990a4..0000000 --- a/AzureDevopsStateTracker/DTOs/WorkItemDTO.cs +++ /dev/null @@ -1,100 +0,0 @@ -using Newtonsoft.Json; -using System; -using System.Collections.Generic; - -namespace AzureDevopsStateTracker.DTOs -{ - public class WorkItemDTO - { - [JsonProperty("id")] - public string Id { get; set; } - - [JsonProperty("created_at")] - public DateTime CreatedAt { get; set; } - - [JsonProperty("assigned_to")] - public string AssignedTo { get; set; } - - [JsonProperty("type")] - public string Type { get; set; } - - [JsonProperty("effort")] - public string Effort { get; set; } - - [JsonProperty("story_points")] - public string StoryPoints { get; set; } - - [JsonProperty("original_estimate")] - public string OriginalEstimate { get; set; } - - [JsonProperty("created_by")] - public string CreatedBy { get; set; } - - [JsonProperty("title")] - public string Title { get; set; } - - [JsonProperty("team_project")] - public string TeamProject { get; set; } - - [JsonProperty("iteration_path")] - public string IterationPath { get; set; } - - [JsonProperty("area_path")] - public string AreaPath { get; set; } - - [JsonProperty("current_status")] - public string CurrentStatus { get; set; } - - [JsonProperty("work_item_parent_id")] - public string WorkItemParentId { get; set; } - - [JsonProperty("activity")] - public string Activity { get; set; } - - [JsonProperty("tags")] - public IEnumerable Tags { get; set; } - - [JsonProperty("workItems_changes")] - public List WorkItemsChangesDTO { get; set; } - - [JsonProperty("times_by_state")] - public List TimesByStateDTO { get; set; } - } - - public class WorkItemChangeDTO - { - [JsonProperty("new_date")] - public DateTime NewDate { get; set; } - - [JsonProperty("new_state")] - public string NewState { get; set; } - - [JsonProperty("old_state")] - public string OldState { get; set; } - - [JsonProperty("old_date")] - public DateTime? OldDate { get; set; } - - [JsonProperty("changed_by")] - public string ChangedBy { get; set; } - } - - - public class TimeByStateDTO - { - [JsonProperty("created_at")] - public DateTime CreatedAt { get; set; } - - [JsonProperty("updated_at")] - public DateTime UpdatedAt { get; set; } - - [JsonProperty("state")] - public string State { get; set; } - - [JsonProperty("total_time")] - public string TotalTime { get; set; } - - [JsonProperty("total_worked_time")] - public string TotalWorkedTime { get; set; } - } -} diff --git a/AzureDevopsStateTracker/Data/Context/AzureDevopsStateTrackerContext.cs b/AzureDevopsStateTracker/Data/Context/AzureDevopsStateTrackerContext.cs deleted file mode 100644 index 18113a6..0000000 --- a/AzureDevopsStateTracker/Data/Context/AzureDevopsStateTrackerContext.cs +++ /dev/null @@ -1,32 +0,0 @@ -using AzureDevopsStateTracker.Entities; -using Microsoft.EntityFrameworkCore; -using System; -using System.Linq; - -namespace AzureDevopsStateTracker.Data.Context -{ - public class AzureDevopsStateTrackerContext : DbContext, IDisposable - { - public AzureDevopsStateTrackerContext(DbContextOptions options) : base(options) - { } - - public DbSet WorkItems { get; set; } - public DbSet WorkItemsChange { get; set; } - public DbSet TimeByStates { get; set; } - - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - foreach (var property in modelBuilder.Model.GetEntityTypes().SelectMany( - e => e.GetProperties().Where(p => p.ClrType == typeof(string)))) - property.SetColumnType("varchar(200)"); - - modelBuilder.HasDefaultSchema(DataBaseConfig.SchemaName); - } - - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - { - if (!optionsBuilder.IsConfigured) - optionsBuilder.UseSqlServer(DataBaseConfig.ConnectionsString); - } - } -} \ No newline at end of file diff --git a/AzureDevopsStateTracker/Data/DataBaseConfig.cs b/AzureDevopsStateTracker/Data/DataBaseConfig.cs deleted file mode 100644 index 7cd63b1..0000000 --- a/AzureDevopsStateTracker/Data/DataBaseConfig.cs +++ /dev/null @@ -1,29 +0,0 @@ -using AzureDevopsStateTracker.Extensions; -using System; -using System.Runtime.InteropServices; - -namespace AzureDevopsStateTracker.Data -{ - public class DataBaseConfig - { - public DataBaseConfig(string connectionsString, string schemaName = "dbo", TimeZoneInfo timeZoneInfo = null) - { - if (connectionsString.IsNullOrEmpty()) - throw new ArgumentException("The ConnectionsString is required"); - - if (timeZoneInfo == null) - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("E. South America Standard Time"); - else - timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Brazil/East"); - - ConnectionsString = connectionsString; - SchemaName = schemaName; - TimeZoneInfo = timeZoneInfo; - } - - public static string ConnectionsString { get; private set; } - public static string SchemaName { get; private set; } - public static TimeZoneInfo TimeZoneInfo { get; private set; } - } -} \ No newline at end of file diff --git a/AzureDevopsStateTracker/Data/Repository.cs b/AzureDevopsStateTracker/Data/Repository.cs deleted file mode 100644 index 74f7289..0000000 --- a/AzureDevopsStateTracker/Data/Repository.cs +++ /dev/null @@ -1,69 +0,0 @@ -using AzureDevopsStateTracker.Data.Context; -using AzureDevopsStateTracker.Entities; -using AzureDevopsStateTracker.Interfaces.Internals; -using Microsoft.EntityFrameworkCore; -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace AzureDevopsStateTracker.Data -{ - internal abstract class Repository : IRepository where TEntity : Entity - { - protected readonly AzureDevopsStateTrackerContext Db; - protected readonly DbSet DbSet; - - public Repository(AzureDevopsStateTrackerContext db) - { - Db = db; - DbSet = db.Set(); - } - - public virtual async Task Add(TEntity entity) - { - await DbSet.AddAsync(entity); - } - - public virtual async Task Add(IEnumerable entities) - { - await DbSet.AddRangeAsync(entities); - } - - public virtual void Update(TEntity entity) - { - DbSet.Update(entity); - } - - public virtual void Update(IEnumerable entities) - { - DbSet.UpdateRange(entities); - } - - public virtual void Delete(TEntity entity) - { - DbSet.Remove(entity); - } - - public virtual async Task GetById(string id) - { - return await DbSet - .FirstOrDefaultAsync(x => x.Id == id); - } - - public async Task Exist(string id) - { - return await DbSet - .AnyAsync(x => x.Id == id); - } - - public async Task SaveChangesAsync() - { - await Db.SaveChangesAsync(); - } - - public void Dispose() - { - GC.SuppressFinalize(this); - } - } -} \ No newline at end of file diff --git a/AzureDevopsStateTracker/Data/WorkItemRepository.cs b/AzureDevopsStateTracker/Data/WorkItemRepository.cs deleted file mode 100644 index 036d5e3..0000000 --- a/AzureDevopsStateTracker/Data/WorkItemRepository.cs +++ /dev/null @@ -1,46 +0,0 @@ -using AzureDevopsStateTracker.Data.Context; -using AzureDevopsStateTracker.Entities; -using AzureDevopsStateTracker.Interfaces.Internals; -using Microsoft.EntityFrameworkCore; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace AzureDevopsStateTracker.Data -{ - internal class WorkItemRepository : Repository, IWorkItemRepository - { - public WorkItemRepository(AzureDevopsStateTrackerContext context) : base(context) { } - - public async Task GetByWorkItemId(string workItemId) - { - return await DbSet - .Include(x => x.WorkItemsChanges) - .Include(x => x.TimeByStates) - .FirstOrDefaultAsync(x => x.Id == workItemId); - } - - public async Task> ListByWorkItemId(IEnumerable workItemsId) - { - return await DbSet - .Include(x => x.WorkItemsChanges) - .Include(x => x.TimeByStates) - .Where(x => workItemsId.Contains(x.Id)) - .ToListAsync(); - } - - public async Task> ListByIterationPath(string iterationPath) - { - return await DbSet - .Include(x => x.WorkItemsChanges) - .Include(x => x.TimeByStates) - .Where(x => x.IterationPath == iterationPath) - .ToListAsync(); - } - - public void RemoveAllTimeByState(List timeByStates) - { - Db.TimeByStates.RemoveRange(timeByStates); - } - } -} \ No newline at end of file diff --git a/AzureDevopsStateTracker/Entities/Entity.cs b/AzureDevopsStateTracker/Entities/Entity.cs deleted file mode 100644 index 4f50888..0000000 --- a/AzureDevopsStateTracker/Entities/Entity.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; - -namespace AzureDevopsStateTracker.Entities -{ - public abstract class Entity - { - public string Id { get; protected set; } - public DateTime CreatedAt { get; private set; } - public Entity(string id) - { - Id = id; - CreatedAt = DateTime.UtcNow; - } - - public Entity() - { - Id = Guid.NewGuid().ToString(); - CreatedAt = DateTime.UtcNow; - } - } -} \ No newline at end of file diff --git a/AzureDevopsStateTracker/Entities/TimeByState.cs b/AzureDevopsStateTracker/Entities/TimeByState.cs deleted file mode 100644 index 4145ebb..0000000 --- a/AzureDevopsStateTracker/Entities/TimeByState.cs +++ /dev/null @@ -1,36 +0,0 @@ -using AzureDevopsStateTracker.Extensions; -using System; - -namespace AzureDevopsStateTracker.Entities -{ - public class TimeByState : Entity - { - public string WorkItemId { get; private set; } - public string State { get; private set; } - public double TotalTime { get; private set; } - public double TotalWorkedTime { get; private set; } - - public WorkItem WorkItem { get; private set; } - - private TimeByState() { } - - public TimeByState(string workItemId, string state, TimeSpan totalTime, TimeSpan totalWorkedTime) - { - WorkItemId = workItemId; - State = state; - TotalTime = totalTime.TotalSeconds; - TotalWorkedTime = totalWorkedTime.TotalSeconds; - - Validate(); - } - - public void Validate() - { - if (WorkItemId.IsNullOrEmpty() || Convert.ToInt64(WorkItemId) <= 0) - throw new Exception("WorkItemId is required"); - - if (State.IsNullOrEmpty()) - throw new Exception("State is required"); - } - } -} \ No newline at end of file diff --git a/AzureDevopsStateTracker/Entities/WorkItem.cs b/AzureDevopsStateTracker/Entities/WorkItem.cs deleted file mode 100644 index 7bd3362..0000000 --- a/AzureDevopsStateTracker/Entities/WorkItem.cs +++ /dev/null @@ -1,127 +0,0 @@ -using AzureDevopsStateTracker.Extensions; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace AzureDevopsStateTracker.Entities -{ - public class WorkItem : Entity - { - public string AreaPath { get; private set; } - public string TeamProject { get; private set; } - public string IterationPath { get; private set; } - public string AssignedTo { get; private set; } - public string Type { get; private set; } - public string CreatedBy { get; private set; } - public string Title { get; private set; } - public string Tags { get; private set; } - public string Effort { get; private set; } - public string OriginalEstimate { get; private set; } - public string StoryPoints { get; private set; } - public string WorkItemParentId { get; private set; } - public string Activity { get; private set; } - private readonly List _workItemsChanges; - public IReadOnlyCollection WorkItemsChanges => _workItemsChanges; - - private readonly List _timeByState; - public IReadOnlyCollection TimeByStates => _timeByState; - public string CurrentStatus => _workItemsChanges?.OrderBy(x => x.CreatedAt)?.LastOrDefault()?.NewState; - - private WorkItem() - { - _workItemsChanges = new List(); - _timeByState = new List(); - } - - public WorkItem(string workItemId) : base(workItemId) - { - _workItemsChanges = new List(); - _timeByState = new List(); - Validate(); - } - - public void Update(string title, - string teamProject, string areaPath, - string iterationPath, string type, - string createdBy, string assignedTo, - string tags, - string workItemParentId, - string effort, - string storyPoint, - string originalEstimate, - string activity) - { - TeamProject = teamProject; - AreaPath = areaPath; - IterationPath = iterationPath; - Type = type; - Title = title; - CreatedBy = createdBy; - AssignedTo = assignedTo; - Tags = tags; - WorkItemParentId = workItemParentId; - Effort = effort; - StoryPoints = storyPoint; - OriginalEstimate = originalEstimate; - Activity = activity; - } - - public void Validate() - { - if (Id.IsNullOrEmpty()) - throw new Exception("WorkItemId is required"); - } - - public void AddWorkItemChange(WorkItemChange workItemChange) - { - if (workItemChange == null) - throw new Exception("WorkItemChange is null"); - - _workItemsChanges.Add(workItemChange); - } - - public void AddTimeByState(TimeByState timeByState) - { - if (timeByState == null) - throw new Exception("TimeByState is null"); - - _timeByState.Add(timeByState); - } - - public void AddTimesByState(IEnumerable timesByState) - { - if (!timesByState.Any()) - return; - - foreach (var timeByState in timesByState) - AddTimeByState(timeByState); - } - - public void ClearTimesByState() - { - _timeByState.Clear(); - } - - public IEnumerable CalculateTotalTimeByState() - { - var timesByStateList = new List(); - if (!_workItemsChanges.Any()) - return timesByStateList; - - foreach (var workItemChange in _workItemsChanges.OrderBy(x => x.CreatedAt).GroupBy(x => x.OldState).Where(x => x.Key != null)) - { - var totalTime = TimeSpan.Zero; - var totalWorkedTime = TimeSpan.Zero; - foreach (var data in workItemChange) - { - totalTime += data.CalculateTotalTime(); - totalWorkedTime += TimeSpan.FromSeconds(data.CalculateTotalWorkedTime()); - } - - timesByStateList.Add(new TimeByState(Id, workItemChange.Key, totalTime, totalWorkedTime)); - } - - return timesByStateList; - } - } -} \ No newline at end of file diff --git a/AzureDevopsStateTracker/Entities/WorkItemChange.cs b/AzureDevopsStateTracker/Entities/WorkItemChange.cs deleted file mode 100644 index db63a95..0000000 --- a/AzureDevopsStateTracker/Entities/WorkItemChange.cs +++ /dev/null @@ -1,162 +0,0 @@ -using AzureDevopsStateTracker.Extensions; -using System; - -namespace AzureDevopsStateTracker.Entities -{ - public class WorkItemChange : Entity - { - public string WorkItemId { get; private set; } - public DateTime NewDate { get; private set; } - public DateTime? OldDate { get; private set; } - public string NewState { get; private set; } - public string OldState { get; private set; } - public string ChangedBy { get; private set; } - public WorkItem WorkItem { get; private set; } - - private WorkItemChange() { } - - public WorkItemChange(string workItemId, string changedBy, DateTime newDate, string newState, string oldState, DateTime? oldDate) - { - WorkItemId = workItemId; - NewDate = newDate; - OldDate = oldDate; - NewState = newState; - OldState = oldState; - ChangedBy = changedBy; - - Validate(); - } - - public void Validate() - { - if (WorkItemId.IsNullOrEmpty() || Convert.ToInt64(WorkItemId) <= 0) - throw new Exception("WorkItemId is required"); - } - - public TimeSpan CalculateTotalTime() - { - return OldDate == null ? TimeSpan.Zero : NewDate.ToDateTimeFromTimeZoneInfo() - OldDate.Value.ToDateTimeFromTimeZoneInfo(); - } - - public double CalculateTotalWorkedTime() - { - if (OldDate.GetValueOrDefault() == DateTime.MinValue) - return 0; - - var oldDate = OldDate.Value.ToDateTimeFromTimeZoneInfo(); - var newDate = NewDate.ToDateTimeFromTimeZoneInfo(); - - var secondsWorked = 0D; - var majorDateBeforeLunch = DateTime.MinValue; - var minorDateBeforeLunch = DateTime.MinValue; - var majorDateAfterLunch = DateTime.MinValue; - var minorDateAfterLunch = DateTime.MinValue; - - DateTime dataAux = DateTime.MinValue; - int diasCompletos = 0; - - TimeSpan afterLunch; - TimeSpan beforeLunch; - - for (var dateAux = oldDate; dateAux <= newDate; dateAux = dateAux.AddSeconds(1)) - { - if (dateAux.DayOfWeek == DayOfWeek.Saturday || dateAux.DayOfWeek == DayOfWeek.Sunday) - continue; - - if (dateAux.TimeOfDay.Hours >= 12 && dateAux.TimeOfDay.Hours < 14) - continue; - - if (dateAux.TimeOfDay.Hours > 18 && dateAux.TimeOfDay.Hours < 23 || - dateAux.TimeOfDay.Hours >= 0 && dateAux.TimeOfDay.Hours < 8) - continue; - - if (dataAux == DateTime.MinValue) - dataAux = dateAux; - - if (dataAux != DateTime.MinValue && dataAux.Date != dateAux.Date) - { - beforeLunch = SubtractDates(majorDateBeforeLunch, minorDateBeforeLunch); - afterLunch = SubtractDates(majorDateAfterLunch, minorDateAfterLunch); - - if ((beforeLunch + afterLunch).Hours == 8) - diasCompletos++; - else - secondsWorked += (beforeLunch + afterLunch).TotalSeconds; - - majorDateBeforeLunch = DateTime.MinValue; - minorDateBeforeLunch = DateTime.MinValue; - - majorDateAfterLunch = DateTime.MinValue; - minorDateAfterLunch = DateTime.MinValue; - dataAux = dateAux; - } - - if (dateAux.TimeOfDay.Hours >= 8 && dateAux.TimeOfDay.Hours < 12) - { - if (minorDateBeforeLunch == DateTime.MinValue || dateAux < minorDateBeforeLunch) - minorDateBeforeLunch = dateAux; - - if (majorDateBeforeLunch == DateTime.MinValue || dateAux > majorDateBeforeLunch) - majorDateBeforeLunch = dateAux; - - continue; - } - - if (dateAux.TimeOfDay.Hours >= 14 && dateAux.TimeOfDay.Hours < 18) - { - if (minorDateAfterLunch == DateTime.MinValue || dateAux < minorDateAfterLunch) - minorDateAfterLunch = dateAux; - - if (majorDateAfterLunch == DateTime.MinValue || dateAux > majorDateAfterLunch) - majorDateAfterLunch = dateAux; - - continue; - } - - } - - if (dataAux != DateTime.MinValue && - oldDate.Date == newDate.Date || - (majorDateBeforeLunch != DateTime.MinValue || minorDateBeforeLunch != DateTime.MinValue) || - (majorDateAfterLunch != DateTime.MinValue || minorDateAfterLunch != DateTime.MinValue)) - { - beforeLunch = SubtractDates(majorDateBeforeLunch, minorDateBeforeLunch); - afterLunch = SubtractDates(majorDateAfterLunch, minorDateAfterLunch); - - secondsWorked += (beforeLunch + afterLunch).TotalSeconds; - } - - if (diasCompletos > 0) - secondsWorked += diasCompletos * 28800; - - return secondsWorked; - } - - private TimeSpan SubtractDates(DateTime biger, DateTime minor) - { - if (biger.Hour == minor.Hour) - { - return biger.Subtract(minor); - } - else if (biger.Hour > 8 && biger.Hour == 11 && biger.Minute == 59) - { - var newMajorDate = new DateTime(biger.Year, biger.Month, biger.Day, 12, 0, 0); - return newMajorDate.Subtract(minor); - } - else if (biger.Hour > 14 && biger.Hour < minor.Hour) - { - var newMinorDate = new DateTime(minor.Year, minor.Month, minor.Day, 14, 0, 0); - return biger.Subtract(newMinorDate); - } - else if (biger.Hour > 14 && biger.Hour == 17 && biger.Minute == 59) - { - var newMajorDate = new DateTime(biger.Year, biger.Month, biger.Day, 18, 0, 0); - return newMajorDate.Subtract(minor); - } - else - { - return biger.Subtract(minor); - } - } - } -} \ No newline at end of file diff --git a/AzureDevopsStateTracker/Extensions/HelperExtenions.cs b/AzureDevopsStateTracker/Extensions/HelperExtenions.cs deleted file mode 100644 index cf8cb21..0000000 --- a/AzureDevopsStateTracker/Extensions/HelperExtenions.cs +++ /dev/null @@ -1,47 +0,0 @@ -using AzureDevopsStateTracker.Data; -using System; -using System.Linq; - -namespace AzureDevopsStateTracker.Extensions -{ - public static class HelperExtenions - { - public static bool IsNullOrEmpty(this string text) - { - return string.IsNullOrEmpty(text?.Trim()); - } - - public static string ExtractEmail(this string user) - { - if (user is null) - return user; - - if (!user.Contains(" <") && !user.TrimEnd().Contains(">")) - return user; - - return user.Split("<").LastOrDefault().Split(">").FirstOrDefault(); - } - - public static string ToTextTime(this TimeSpan timeSpan) - { - if (timeSpan.Days > 0) - return $@"{timeSpan:%d} Dia(s) {timeSpan:%h} h e {timeSpan:%m} min e {timeSpan:%s} s"; - - if (timeSpan.Hours > 0) - return $@"{timeSpan:%h} h e {timeSpan:%m} min e {timeSpan:%s} s"; - - if (timeSpan.Minutes > 0) - return $@"{timeSpan:%m} min e {timeSpan:%s} s"; - - if (timeSpan.Seconds > 0) - return $@"{timeSpan:%s} s"; - - return "-"; - } - - public static DateTime ToDateTimeFromTimeZoneInfo(this DateTime date) - { - return TimeZoneInfo.ConvertTimeFromUtc(date, DataBaseConfig.TimeZoneInfo); - } - } -} \ No newline at end of file diff --git a/AzureDevopsStateTracker/Interfaces/IAzureDevopsStateTrackerService.cs b/AzureDevopsStateTracker/Interfaces/IAzureDevopsStateTrackerService.cs deleted file mode 100644 index b5f47a9..0000000 --- a/AzureDevopsStateTracker/Interfaces/IAzureDevopsStateTrackerService.cs +++ /dev/null @@ -1,14 +0,0 @@ -using AzureDevopsStateTracker.DTOs; -using AzureDevopsStateTracker.DTOs.Create; -using AzureDevopsStateTracker.DTOs.Update; -using System.Threading.Tasks; - -namespace AzureDevopsStateTracker.Interfaces -{ - public interface IAzureDevopsStateTrackerService - { - Task Create(CreateWorkItemDTO createDto, bool addWorkItemChange = true); - Task Update(UpdatedWorkItemDTO updateDto); - Task GetByWorkItemId(string workItemId); - } -} \ No newline at end of file diff --git a/AzureDevopsStateTracker/Interfaces/IWorkItemAdapter.cs b/AzureDevopsStateTracker/Interfaces/IWorkItemAdapter.cs deleted file mode 100644 index 5fb5db8..0000000 --- a/AzureDevopsStateTracker/Interfaces/IWorkItemAdapter.cs +++ /dev/null @@ -1,12 +0,0 @@ -using AzureDevopsStateTracker.DTOs; -using AzureDevopsStateTracker.Entities; -using System.Collections.Generic; - -namespace AzureDevopsStateTracker.Interfaces -{ - public interface IWorkItemAdapter - { - WorkItemDTO ToWorkItemDTO(WorkItem workItem); - List ToWorkItemsDTO(List workItems); - } -} \ No newline at end of file diff --git a/AzureDevopsStateTracker/Interfaces/Internals/IRepository.cs b/AzureDevopsStateTracker/Interfaces/Internals/IRepository.cs deleted file mode 100644 index a7fbca5..0000000 --- a/AzureDevopsStateTracker/Interfaces/Internals/IRepository.cs +++ /dev/null @@ -1,19 +0,0 @@ -using AzureDevopsStateTracker.Entities; -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace AzureDevopsStateTracker.Interfaces.Internals -{ - public interface IRepository : IDisposable where TEntity : Entity - { - Task Add(TEntity entity); - Task Add(IEnumerable entities); - Task GetById(string id); - Task Exist(string id); - void Update(TEntity entity); - void Update(IEnumerable entities); - void Delete(TEntity entity); - Task SaveChangesAsync(); - } -} \ No newline at end of file diff --git a/AzureDevopsStateTracker/Interfaces/Internals/IWorkItemRepository.cs b/AzureDevopsStateTracker/Interfaces/Internals/IWorkItemRepository.cs deleted file mode 100644 index 69c031b..0000000 --- a/AzureDevopsStateTracker/Interfaces/Internals/IWorkItemRepository.cs +++ /dev/null @@ -1,14 +0,0 @@ -using AzureDevopsStateTracker.Entities; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace AzureDevopsStateTracker.Interfaces.Internals -{ - public interface IWorkItemRepository : IRepository - { - Task GetByWorkItemId(string workItemId); - Task> ListByWorkItemId(IEnumerable workItemsId); - Task> ListByIterationPath(string iterationPath); - void RemoveAllTimeByState(List timeByStates); - } -} \ No newline at end of file diff --git a/AzureDevopsStateTracker/Migrations/20210719163846_AzureDevopsStateTrackerInitial.Designer.cs b/AzureDevopsStateTracker/Migrations/20210719163846_AzureDevopsStateTrackerInitial.Designer.cs deleted file mode 100644 index b7fa1cf..0000000 --- a/AzureDevopsStateTracker/Migrations/20210719163846_AzureDevopsStateTrackerInitial.Designer.cs +++ /dev/null @@ -1,154 +0,0 @@ -// -using System; -using AzureDevopsStateTracker.Data; -using AzureDevopsStateTracker.Data.Context; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -namespace AzureDevopsStateTracker.Migrations -{ - [DbContext(typeof(AzureDevopsStateTrackerContext))] - [Migration("20210719163846_AzureDevopsStateTrackerInitial")] - partial class AzureDevopsStateTrackerInitial - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasDefaultSchema(DataBaseConfig.SchemaName) - .HasAnnotation("ProductVersion", "3.1.16") - .HasAnnotation("Relational:MaxIdentifierLength", 128) - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - - modelBuilder.Entity("AzureDevopsStateTracker.Entities.TimeByState", b => - { - b.Property("Id") - .HasColumnType("varchar(200)"); - - b.Property("CreatedAt") - .HasColumnType("datetime2"); - - b.Property("State") - .HasColumnType("varchar(200)"); - - b.Property("TotalTime") - .HasColumnType("float"); - - b.Property("TotalWorkedTime") - .HasColumnType("float"); - - b.Property("WorkItemId") - .HasColumnType("varchar(200)"); - - b.HasKey("Id"); - - b.HasIndex("WorkItemId"); - - b.ToTable("TimeByStates"); - }); - - modelBuilder.Entity("AzureDevopsStateTracker.Entities.WorkItem", b => - { - b.Property("Id") - .HasColumnType("varchar(200)"); - - b.Property("Activity") - .HasColumnType("varchar(200)"); - - b.Property("AreaPath") - .HasColumnType("varchar(200)"); - - b.Property("AssignedTo") - .HasColumnType("varchar(200)"); - - b.Property("CreatedAt") - .HasColumnType("datetime2"); - - b.Property("CreatedBy") - .HasColumnType("varchar(200)"); - - b.Property("Effort") - .HasColumnType("varchar(200)"); - - b.Property("IterationPath") - .HasColumnType("varchar(200)"); - - b.Property("OriginalEstimate") - .HasColumnType("varchar(200)"); - - b.Property("StoryPoints") - .HasColumnType("varchar(200)"); - - b.Property("Tags") - .HasColumnType("varchar(200)"); - - b.Property("TeamProject") - .HasColumnType("varchar(200)"); - - b.Property("Title") - .HasColumnType("varchar(200)"); - - b.Property("Type") - .HasColumnType("varchar(200)"); - - b.Property("WorkItemParentId") - .HasColumnType("varchar(200)"); - - b.HasKey("Id"); - - b.ToTable("WorkItems"); - }); - - modelBuilder.Entity("AzureDevopsStateTracker.Entities.WorkItemChange", b => - { - b.Property("Id") - .HasColumnType("varchar(200)"); - - b.Property("ChangedBy") - .HasColumnType("varchar(200)"); - - b.Property("CreatedAt") - .HasColumnType("datetime2"); - - b.Property("NewDate") - .HasColumnType("datetime2"); - - b.Property("NewState") - .HasColumnType("varchar(200)"); - - b.Property("OldDate") - .HasColumnType("datetime2"); - - b.Property("OldState") - .HasColumnType("varchar(200)"); - - b.Property("WorkItemId") - .HasColumnType("varchar(200)"); - - b.HasKey("Id"); - - b.HasIndex("WorkItemId"); - - b.ToTable("WorkItemsChange"); - }); - - modelBuilder.Entity("AzureDevopsStateTracker.Entities.TimeByState", b => - { - b.HasOne("AzureDevopsStateTracker.Entities.WorkItem", "WorkItem") - .WithMany("TimeByStates") - .HasForeignKey("WorkItemId"); - }); - - modelBuilder.Entity("AzureDevopsStateTracker.Entities.WorkItemChange", b => - { - b.HasOne("AzureDevopsStateTracker.Entities.WorkItem", "WorkItem") - .WithMany("WorkItemsChanges") - .HasForeignKey("WorkItemId"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/AzureDevopsStateTracker/Migrations/20210719163846_AzureDevopsStateTrackerInitial.cs b/AzureDevopsStateTracker/Migrations/20210719163846_AzureDevopsStateTrackerInitial.cs deleted file mode 100644 index de24b1a..0000000 --- a/AzureDevopsStateTracker/Migrations/20210719163846_AzureDevopsStateTrackerInitial.cs +++ /dev/null @@ -1,118 +0,0 @@ -using System; -using AzureDevopsStateTracker.Data; -using Microsoft.EntityFrameworkCore.Migrations; - -namespace AzureDevopsStateTracker.Migrations -{ - public partial class AzureDevopsStateTrackerInitial : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.EnsureSchema( - name: DataBaseConfig.SchemaName); - - migrationBuilder.CreateTable( - name: "WorkItems", - schema: DataBaseConfig.SchemaName, - columns: table => new - { - Id = table.Column(type: "varchar(200)", nullable: false), - CreatedAt = table.Column(nullable: false), - AreaPath = table.Column(type: "varchar(200)", nullable: true), - TeamProject = table.Column(type: "varchar(200)", nullable: true), - IterationPath = table.Column(type: "varchar(200)", nullable: true), - AssignedTo = table.Column(type: "varchar(200)", nullable: true), - Type = table.Column(type: "varchar(200)", nullable: true), - CreatedBy = table.Column(type: "varchar(200)", nullable: true), - Title = table.Column(type: "varchar(200)", nullable: true), - Tags = table.Column(type: "varchar(200)", nullable: true), - Effort = table.Column(type: "varchar(200)", nullable: true), - OriginalEstimate = table.Column(type: "varchar(200)", nullable: true), - StoryPoints = table.Column(type: "varchar(200)", nullable: true), - WorkItemParentId = table.Column(type: "varchar(200)", nullable: true), - Activity = table.Column(type: "varchar(200)", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_WorkItems", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "TimeByStates", - schema: DataBaseConfig.SchemaName, - columns: table => new - { - Id = table.Column(type: "varchar(200)", nullable: false), - CreatedAt = table.Column(nullable: false), - WorkItemId = table.Column(type: "varchar(200)", nullable: true), - State = table.Column(type: "varchar(200)", nullable: true), - TotalTime = table.Column(nullable: false), - TotalWorkedTime = table.Column(nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_TimeByStates", x => x.Id); - table.ForeignKey( - name: "FK_TimeByStates_WorkItems_WorkItemId", - column: x => x.WorkItemId, - principalSchema: DataBaseConfig.SchemaName, - principalTable: "WorkItems", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - }); - - migrationBuilder.CreateTable( - name: "WorkItemsChange", - schema: DataBaseConfig.SchemaName, - columns: table => new - { - Id = table.Column(type: "varchar(200)", nullable: false), - CreatedAt = table.Column(nullable: false), - WorkItemId = table.Column(type: "varchar(200)", nullable: true), - NewDate = table.Column(nullable: false), - OldDate = table.Column(nullable: true), - NewState = table.Column(type: "varchar(200)", nullable: true), - OldState = table.Column(type: "varchar(200)", nullable: true), - ChangedBy = table.Column(type: "varchar(200)", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_WorkItemsChange", x => x.Id); - table.ForeignKey( - name: "FK_WorkItemsChange_WorkItems_WorkItemId", - column: x => x.WorkItemId, - principalSchema: DataBaseConfig.SchemaName, - principalTable: "WorkItems", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - }); - - migrationBuilder.CreateIndex( - name: "IX_TimeByStates_WorkItemId", - schema: DataBaseConfig.SchemaName, - table: "TimeByStates", - column: "WorkItemId"); - - migrationBuilder.CreateIndex( - name: "IX_WorkItemsChange_WorkItemId", - schema: DataBaseConfig.SchemaName, - table: "WorkItemsChange", - column: "WorkItemId"); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "TimeByStates", - schema: DataBaseConfig.SchemaName); - - migrationBuilder.DropTable( - name: "WorkItemsChange", - schema: DataBaseConfig.SchemaName); - - migrationBuilder.DropTable( - name: "WorkItems", - schema: DataBaseConfig.SchemaName); - } - } -} diff --git a/AzureDevopsStateTracker/Migrations/20210720105645_FunctionToTimeInitial.Designer.cs b/AzureDevopsStateTracker/Migrations/20210720105645_FunctionToTimeInitial.Designer.cs deleted file mode 100644 index 9a8b8ed..0000000 --- a/AzureDevopsStateTracker/Migrations/20210720105645_FunctionToTimeInitial.Designer.cs +++ /dev/null @@ -1,154 +0,0 @@ -// -using System; -using AzureDevopsStateTracker.Data; -using AzureDevopsStateTracker.Data.Context; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -namespace AzureDevopsStateTracker.Migrations -{ - [DbContext(typeof(AzureDevopsStateTrackerContext))] - [Migration("20210720105645_FunctionToTimeInitial")] - partial class FunctionToTimeInitial - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasDefaultSchema(DataBaseConfig.SchemaName) - .HasAnnotation("ProductVersion", "3.1.16") - .HasAnnotation("Relational:MaxIdentifierLength", 128) - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - - modelBuilder.Entity("AzureDevopsStateTracker.Entities.TimeByState", b => - { - b.Property("Id") - .HasColumnType("varchar(200)"); - - b.Property("CreatedAt") - .HasColumnType("datetime2"); - - b.Property("State") - .HasColumnType("varchar(200)"); - - b.Property("TotalTime") - .HasColumnType("float"); - - b.Property("TotalWorkedTime") - .HasColumnType("float"); - - b.Property("WorkItemId") - .HasColumnType("varchar(200)"); - - b.HasKey("Id"); - - b.HasIndex("WorkItemId"); - - b.ToTable("TimeByStates"); - }); - - modelBuilder.Entity("AzureDevopsStateTracker.Entities.WorkItem", b => - { - b.Property("Id") - .HasColumnType("varchar(200)"); - - b.Property("Activity") - .HasColumnType("varchar(200)"); - - b.Property("AreaPath") - .HasColumnType("varchar(200)"); - - b.Property("AssignedTo") - .HasColumnType("varchar(200)"); - - b.Property("CreatedAt") - .HasColumnType("datetime2"); - - b.Property("CreatedBy") - .HasColumnType("varchar(200)"); - - b.Property("Effort") - .HasColumnType("varchar(200)"); - - b.Property("IterationPath") - .HasColumnType("varchar(200)"); - - b.Property("OriginalEstimate") - .HasColumnType("varchar(200)"); - - b.Property("StoryPoints") - .HasColumnType("varchar(200)"); - - b.Property("Tags") - .HasColumnType("varchar(200)"); - - b.Property("TeamProject") - .HasColumnType("varchar(200)"); - - b.Property("Title") - .HasColumnType("varchar(200)"); - - b.Property("Type") - .HasColumnType("varchar(200)"); - - b.Property("WorkItemParentId") - .HasColumnType("varchar(200)"); - - b.HasKey("Id"); - - b.ToTable("WorkItems"); - }); - - modelBuilder.Entity("AzureDevopsStateTracker.Entities.WorkItemChange", b => - { - b.Property("Id") - .HasColumnType("varchar(200)"); - - b.Property("ChangedBy") - .HasColumnType("varchar(200)"); - - b.Property("CreatedAt") - .HasColumnType("datetime2"); - - b.Property("NewDate") - .HasColumnType("datetime2"); - - b.Property("NewState") - .HasColumnType("varchar(200)"); - - b.Property("OldDate") - .HasColumnType("datetime2"); - - b.Property("OldState") - .HasColumnType("varchar(200)"); - - b.Property("WorkItemId") - .HasColumnType("varchar(200)"); - - b.HasKey("Id"); - - b.HasIndex("WorkItemId"); - - b.ToTable("WorkItemsChange"); - }); - - modelBuilder.Entity("AzureDevopsStateTracker.Entities.TimeByState", b => - { - b.HasOne("AzureDevopsStateTracker.Entities.WorkItem", "WorkItem") - .WithMany("TimeByStates") - .HasForeignKey("WorkItemId"); - }); - - modelBuilder.Entity("AzureDevopsStateTracker.Entities.WorkItemChange", b => - { - b.HasOne("AzureDevopsStateTracker.Entities.WorkItem", "WorkItem") - .WithMany("WorkItemsChanges") - .HasForeignKey("WorkItemId"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/AzureDevopsStateTracker/Migrations/20210720105645_FunctionToTimeInitial.cs b/AzureDevopsStateTracker/Migrations/20210720105645_FunctionToTimeInitial.cs deleted file mode 100644 index d7f9ca3..0000000 --- a/AzureDevopsStateTracker/Migrations/20210720105645_FunctionToTimeInitial.cs +++ /dev/null @@ -1,50 +0,0 @@ -using AzureDevopsStateTracker.Data; -using Microsoft.EntityFrameworkCore.Migrations; - -namespace AzureDevopsStateTracker.Migrations -{ - public partial class FunctionToTimeInitial : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - var rawFunction = @"CREATE OR ALTER FUNCTION ToTime (@seconds int) - RETURNS varchar(50) - AS BEGIN - declare @seconds_in_a_day int = 86400; - declare @seconds_in_an_hour int = 3600; - declare @seconds_in_a_minute int = 60; - - declare @text_to_return varchar(50) = ''; - if(@seconds >= @seconds_in_a_day) - begin - declare @completed_days int = @seconds/@seconds_in_a_day; - select @text_to_return = CONCAT(@text_to_return, @completed_days, ' day(s)') - select @seconds = @seconds - (@seconds_in_a_day * @completed_days) - end - - if(@seconds >= @seconds_in_an_hour) - begin - declare @completed_hours int = @seconds/@seconds_in_an_hour; - select @text_to_return = CONCAT(@text_to_return, ' ', @completed_hours, ' hour(s)') - select @seconds = @seconds - (@seconds_in_an_hour * @completed_hours) - end - - if(@seconds >= @seconds_in_a_minute) - begin - declare @completed_minutes int = @seconds/@seconds_in_a_minute; - select @text_to_return = CONCAT(@text_to_return, ' ', @completed_minutes, ' minute(s)') - select @seconds = @seconds - (@seconds_in_a_minute * @completed_minutes) - end - - return LTRIM(RTRIM(@text_to_return)); - END"; - migrationBuilder.Sql(rawFunction); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - var dropFunction = @$"DROP FUNCTION IF EXISTS dbo.ToTime"; - migrationBuilder.Sql(dropFunction); - } - } -} diff --git a/AzureDevopsStateTracker/Migrations/AzureDevopsStateTrackerContextModelSnapshot.cs b/AzureDevopsStateTracker/Migrations/AzureDevopsStateTrackerContextModelSnapshot.cs deleted file mode 100644 index 7baa9b1..0000000 --- a/AzureDevopsStateTracker/Migrations/AzureDevopsStateTrackerContextModelSnapshot.cs +++ /dev/null @@ -1,152 +0,0 @@ -// -using System; -using AzureDevopsStateTracker.Data; -using AzureDevopsStateTracker.Data.Context; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -namespace AzureDevopsStateTracker.Migrations -{ - [DbContext(typeof(AzureDevopsStateTrackerContext))] - partial class AzureDevopsStateTrackerContextModelSnapshot : ModelSnapshot - { - protected override void BuildModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasDefaultSchema(DataBaseConfig.SchemaName) - .HasAnnotation("ProductVersion", "3.1.16") - .HasAnnotation("Relational:MaxIdentifierLength", 128) - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - - modelBuilder.Entity("AzureDevopsStateTracker.Entities.TimeByState", b => - { - b.Property("Id") - .HasColumnType("varchar(200)"); - - b.Property("CreatedAt") - .HasColumnType("datetime2"); - - b.Property("State") - .HasColumnType("varchar(200)"); - - b.Property("TotalTime") - .HasColumnType("float"); - - b.Property("TotalWorkedTime") - .HasColumnType("float"); - - b.Property("WorkItemId") - .HasColumnType("varchar(200)"); - - b.HasKey("Id"); - - b.HasIndex("WorkItemId"); - - b.ToTable("TimeByStates"); - }); - - modelBuilder.Entity("AzureDevopsStateTracker.Entities.WorkItem", b => - { - b.Property("Id") - .HasColumnType("varchar(200)"); - - b.Property("Activity") - .HasColumnType("varchar(200)"); - - b.Property("AreaPath") - .HasColumnType("varchar(200)"); - - b.Property("AssignedTo") - .HasColumnType("varchar(200)"); - - b.Property("CreatedAt") - .HasColumnType("datetime2"); - - b.Property("CreatedBy") - .HasColumnType("varchar(200)"); - - b.Property("Effort") - .HasColumnType("varchar(200)"); - - b.Property("IterationPath") - .HasColumnType("varchar(200)"); - - b.Property("OriginalEstimate") - .HasColumnType("varchar(200)"); - - b.Property("StoryPoints") - .HasColumnType("varchar(200)"); - - b.Property("Tags") - .HasColumnType("varchar(200)"); - - b.Property("TeamProject") - .HasColumnType("varchar(200)"); - - b.Property("Title") - .HasColumnType("varchar(200)"); - - b.Property("Type") - .HasColumnType("varchar(200)"); - - b.Property("WorkItemParentId") - .HasColumnType("varchar(200)"); - - b.HasKey("Id"); - - b.ToTable("WorkItems"); - }); - - modelBuilder.Entity("AzureDevopsStateTracker.Entities.WorkItemChange", b => - { - b.Property("Id") - .HasColumnType("varchar(200)"); - - b.Property("ChangedBy") - .HasColumnType("varchar(200)"); - - b.Property("CreatedAt") - .HasColumnType("datetime2"); - - b.Property("NewDate") - .HasColumnType("datetime2"); - - b.Property("NewState") - .HasColumnType("varchar(200)"); - - b.Property("OldDate") - .HasColumnType("datetime2"); - - b.Property("OldState") - .HasColumnType("varchar(200)"); - - b.Property("WorkItemId") - .HasColumnType("varchar(200)"); - - b.HasKey("Id"); - - b.HasIndex("WorkItemId"); - - b.ToTable("WorkItemsChange"); - }); - - modelBuilder.Entity("AzureDevopsStateTracker.Entities.TimeByState", b => - { - b.HasOne("AzureDevopsStateTracker.Entities.WorkItem", "WorkItem") - .WithMany("TimeByStates") - .HasForeignKey("WorkItemId"); - }); - - modelBuilder.Entity("AzureDevopsStateTracker.Entities.WorkItemChange", b => - { - b.HasOne("AzureDevopsStateTracker.Entities.WorkItem", "WorkItem") - .WithMany("WorkItemsChanges") - .HasForeignKey("WorkItemId"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/AzureDevopsStateTracker/Services/AzureDevopsStateTrackerService.cs b/AzureDevopsStateTracker/Services/AzureDevopsStateTrackerService.cs deleted file mode 100644 index ad0c49f..0000000 --- a/AzureDevopsStateTracker/Services/AzureDevopsStateTrackerService.cs +++ /dev/null @@ -1,148 +0,0 @@ -using AzureDevopsStateTracker.DTOs; -using AzureDevopsStateTracker.DTOs.Create; -using AzureDevopsStateTracker.DTOs.Update; -using AzureDevopsStateTracker.Entities; -using AzureDevopsStateTracker.Extensions; -using AzureDevopsStateTracker.Interfaces; -using AzureDevopsStateTracker.Interfaces.Internals; -using System; -using System.Linq; -using System.Threading.Tasks; - -namespace AzureDevopsStateTracker.Services -{ - public class AzureDevopsStateTrackerService : IAzureDevopsStateTrackerService - { - public readonly IWorkItemRepository _workItemRepository; - public readonly IWorkItemAdapter _workItemAdapter; - - public AzureDevopsStateTrackerService( - IWorkItemAdapter workItemAdapter, IWorkItemRepository workItemRepository) - { - _workItemAdapter = workItemAdapter; - _workItemRepository = workItemRepository; - } - - public async Task Create(CreateWorkItemDTO create, bool addWorkItemChange = true) - { - var workItem = new WorkItem(create.Resource.Id); - - workItem.Update(create.Resource.Fields.Title, - create.Resource.Fields.TeamProject, - create.Resource.Fields.AreaPath, - create.Resource.Fields.IterationPath, - create.Resource.Fields.Type, - create.Resource.Fields.CreatedBy.ExtractEmail(), - create.Resource.Fields.AssignedTo.ExtractEmail(), - create.Resource.Fields.Tags, - create.Resource.Fields.Parent, - create.Resource.Fields.Effort, - create.Resource.Fields.StoryPoints, - create.Resource.Fields.OriginalEstimate, - create.Resource.Fields.Activity); - - if (addWorkItemChange) - AddWorkItemChange(workItem, create); - - await _workItemRepository.Add(workItem); - await _workItemRepository.SaveChangesAsync(); - } - - public async Task Create(UpdatedWorkItemDTO updateDto) - { - var createDto = new CreateWorkItemDTO() - { - Resource = new DTOs.Create.Resource() - { - Fields = updateDto.Resource.Revision.Fields, - Id = updateDto.Resource.WorkItemId, - } - }; - - await Create(createDto, false); - } - - public async Task Update(UpdatedWorkItemDTO update) - { - if (!_workItemRepository.Exist(update.Resource.WorkItemId).Result) - await Create(update); - - var workItem = await _workItemRepository.GetByWorkItemId(update.Resource.WorkItemId); - if (workItem is null) - return; - - workItem.Update(update.Resource.Revision.Fields.Title, - update.Resource.Revision.Fields.TeamProject, - update.Resource.Revision.Fields.AreaPath, - update.Resource.Revision.Fields.IterationPath, - update.Resource.Revision.Fields.Type, - update.Resource.Revision.Fields.CreatedBy.ExtractEmail(), - update.Resource.Revision.Fields.AssignedTo.ExtractEmail(), - update.Resource.Revision.Fields.Tags, - update.Resource.Revision.Fields.Parent, - update.Resource.Revision.Fields.Effort, - update.Resource.Revision.Fields.StoryPoints, - update.Resource.Revision.Fields.OriginalEstimate, - update.Resource.Revision.Fields.Activity); - - AddWorkItemChange(workItem, update); - - _workItemRepository.Update(workItem); - await _workItemRepository.SaveChangesAsync(); - } - - public async Task GetByWorkItemId(string workItemId) - { - var workItem = await _workItemRepository.GetByWorkItemId(workItemId); - if (workItem is null) - return null; - - return _workItemAdapter.ToWorkItemDTO(workItem); - } - - #region Support Methods - public WorkItemChange ToWorkItemChange(string workItemId, string changedBy, DateTime newDate, string newState, string oldState = null, DateTime? oldDate = null) - { - return new WorkItemChange(workItemId, changedBy.ExtractEmail(), newDate, newState, oldState, oldDate); - } - - public void AddWorkItemChange(WorkItem workItem, CreateWorkItemDTO create) - { - var workItemChange = ToWorkItemChange(workItem.Id, - create.Resource.Fields.ChangedBy, - create.Resource.Fields.CreatedDate.ToDateTimeFromTimeZoneInfo(), - create.Resource.Fields.State); - - workItem.AddWorkItemChange(workItemChange); - } - - public void AddWorkItemChange(WorkItem workItem, UpdatedWorkItemDTO update) - { - var changedBy = update.Resource.Revision.Fields.ChangedBy ?? update.Resource.Fields.ChangedBy.NewValue; - var workItemChange = ToWorkItemChange(workItem.Id, - changedBy, - update.Resource.Fields.StateChangeDate.NewValue.ToDateTimeFromTimeZoneInfo(), - update.Resource.Fields.State.NewValue, - update.Resource.Fields.State.OldValue, - update.Resource.Fields.StateChangeDate.OldValue.ToDateTimeFromTimeZoneInfo()); - - workItem.AddWorkItemChange(workItemChange); - - UpdateTimeByStates(workItem); - } - - public void UpdateTimeByStates(WorkItem workItem) - { - RemoveTimeByStateFromDataBase(workItem); - - workItem.ClearTimesByState(); - workItem.AddTimesByState(workItem.CalculateTotalTimeByState()); - } - - public void RemoveTimeByStateFromDataBase(WorkItem workItem) - { - _workItemRepository.RemoveAllTimeByState(workItem.TimeByStates.ToList()); - } - #endregion - } -} \ No newline at end of file From 5418917403744d99561a9d2450aca78219df45bc Mon Sep 17 00:00:00 2001 From: Elvis Souza Date: Mon, 4 Oct 2021 19:08:27 -0300 Subject: [PATCH 04/11] Update azure-pipelines.yml for Azure Pipelines --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index b12d3a5..e76f932 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -8,7 +8,7 @@ trigger: variables: # Azure Resource Manager connection created during pipeline creation - azureSubscription: '061440c6-b8b2-41ab-98dc-8863642471ff' + azureSubscription: '53eedeb9-cc9a-428e-aee0-e19b1501f238' # Function app name functionAppName: 'func-azure-devops-state-tracker' From a1cbe2173b4dfe7bd72ad496b4ebe4e6164be917 Mon Sep 17 00:00:00 2001 From: Diego Galante Date: Mon, 4 Oct 2021 19:12:23 -0300 Subject: [PATCH 05/11] Updating --- AzureDevOpsStateTracker.Functions/Startup.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/AzureDevOpsStateTracker.Functions/Startup.cs b/AzureDevOpsStateTracker.Functions/Startup.cs index e222af3..0753806 100644 --- a/AzureDevOpsStateTracker.Functions/Startup.cs +++ b/AzureDevOpsStateTracker.Functions/Startup.cs @@ -1,13 +1,14 @@ -using AzureDevopsStateTracker.Configurations; -using AzureDevopsStateTracker.Data; -using AzureDevopsStateTracker.Services; -using AzureDevOpsStateTracker.Functions; +using AzureDevOpsStateTracker.Functions; +using AzureDevopsTracker.Configurations; +using AzureDevopsTracker.Data; +using AzureDevopsTracker.Services; +using AzureDevOpsTracker.Functions; using Microsoft.Azure.Functions.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection; [assembly: FunctionsStartup(typeof(Startup))] -namespace AzureDevOpsStateTracker.Functions +namespace AzureDevOpsTracker.Functions { public class Startup : FunctionsStartup { @@ -16,9 +17,9 @@ public override void Configure(IFunctionsHostBuilder builder) var configuration = builder.GetContext().Configuration; builder.Services.AddScoped(); - builder.Services.AddScoped(); + builder.Services.AddScoped(); - builder.Services.AddAzureDevopsStateTracker(new DataBaseConfig(configuration["ConnectionStrings:DefaultConnection"], "StateTracker")); + builder.Services.AddAzureDevopsTracker(new DataBaseConfig(configuration["ConnectionStrings:DefaultConnection"], "Tracker")); } } } \ No newline at end of file From 50124ec4416ac98ed66c1fb93fddefabdee77df7 Mon Sep 17 00:00:00 2001 From: Elvis Souza Date: Mon, 4 Oct 2021 19:14:20 -0300 Subject: [PATCH 06/11] remove yaml (1) --- azure-pipelines-1.yml | 76 ------------------------------------------- 1 file changed, 76 deletions(-) delete mode 100644 azure-pipelines-1.yml diff --git a/azure-pipelines-1.yml b/azure-pipelines-1.yml deleted file mode 100644 index bee5a86..0000000 --- a/azure-pipelines-1.yml +++ /dev/null @@ -1,76 +0,0 @@ -# .NET Core Function App to Windows on Azure -# Build a .NET Core function app and deploy it to Azure as a Windows function App. -# Add steps that analyze code, save build artifacts, deploy, and more: -# https://docs.microsoft.com/en-us/azure/devops/pipelines/languages/dotnet-core - -trigger: -- main - -variables: - # Azure Resource Manager connection created during pipeline creation - azureSubscription: 'dbd9bc02-3bce-4286-ad67-7aeff32534bf' - - # Function app name - functionAppName: 'func-azure-devops-state-tracker' - - # Agent VM image name - vmImageName: 'vs2017-win2016' - - # Working Directory - workingDirectory: '$(System.DefaultWorkingDirectory)/AzureDevOpsStateTracker.Functions' - -stages: -- stage: Build - displayName: Build stage - - jobs: - - job: Build - displayName: Build - pool: - vmImage: $(vmImageName) - - steps: - - task: DotNetCoreCLI@2 - displayName: Build - inputs: - command: 'build' - projects: | - $(workingDirectory)/*.csproj - arguments: --output $(System.DefaultWorkingDirectory)/publish_output --configuration Release - - - task: ArchiveFiles@2 - displayName: 'Archive files' - inputs: - rootFolderOrFile: '$(System.DefaultWorkingDirectory)/publish_output' - includeRootFolder: false - archiveType: zip - archiveFile: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip - replaceExistingArchive: true - - - publish: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip - artifact: drop - -- stage: Deploy - displayName: Deploy stage - dependsOn: Build - condition: succeeded() - - jobs: - - deployment: Deploy - displayName: Deploy - environment: 'development' - pool: - vmImage: $(vmImageName) - - strategy: - runOnce: - deploy: - - steps: - - task: AzureFunctionApp@1 - displayName: 'Azure functions app deploy' - inputs: - azureSubscription: '$(azureSubscription)' - appType: functionApp - appName: $(functionAppName) - package: '$(Pipeline.Workspace)/drop/$(Build.BuildId).zip' \ No newline at end of file From e5e1e49e05cf02aa48840b6f19ed7f6b0d8f5ae8 Mon Sep 17 00:00:00 2001 From: Diego Galante Date: Mon, 4 Oct 2021 20:28:30 -0300 Subject: [PATCH 07/11] Update Startup.cs --- AzureDevOpsStateTracker.Functions/Startup.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AzureDevOpsStateTracker.Functions/Startup.cs b/AzureDevOpsStateTracker.Functions/Startup.cs index 0753806..622c266 100644 --- a/AzureDevOpsStateTracker.Functions/Startup.cs +++ b/AzureDevOpsStateTracker.Functions/Startup.cs @@ -19,7 +19,7 @@ public override void Configure(IFunctionsHostBuilder builder) builder.Services.AddScoped(); builder.Services.AddScoped(); - builder.Services.AddAzureDevopsTracker(new DataBaseConfig(configuration["ConnectionStrings:DefaultConnection"], "Tracker")); + builder.Services.AddAzureDevopsTracker(new DataBaseConfig(configuration["ConnectionStrings:DefaultConnection"])); } } -} \ No newline at end of file +} From 9ec5c3d2930ee97deef2a901e09afe66af9d4d97 Mon Sep 17 00:00:00 2001 From: Diego Galante Date: Thu, 7 Oct 2021 19:34:16 -0300 Subject: [PATCH 08/11] Update README.md --- README.md | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 104 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b69c26c..a15f5e1 100644 --- a/README.md +++ b/README.md @@ -1 +1,104 @@ -# azure-devops-state-tracker-function \ No newline at end of file +# Azure DevOps Tracker Function + +Nesse repositório temos uma Azure Function que utiliza o [![Nuget](https://img.shields.io/badge/Azure%20DevOps%20Tracker-nuget-blue)](https://www.nuget.org/packages/AzureDevOpsTracker/) que também pode ser encontrado no [![Azure DevOps Tracker](https://img.shields.io/badge/Azure%20DevOps%20Tracker-github-0099cc)](https://github.com/typinghard/azure-devops-tracker) para mostrar um exemplo prático de utilização do mesmo. + +O objetivo é demonstrar a utilização do ADT através de uma Azure Function e, além disso, mostrar os passos necessários para a criação dessa Azure Function no Portal Azure. +Para mais informações mais detalhadas e específicas sobre o Azure DevOps Tracker, consulte a nossa [Wiki](https://github.com/typinghard/azure-devops-tracker/wiki). + +## Etapa 1 + +### Configuração da Azure Function + +Diferente de uma startup de um projeto MVC ou API, requer que a startup herde de uma FunctionsStartup. + +```c# + public class Startup : FunctionsStartup + { + public override void Configure(IFunctionsHostBuilder builder) + { + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddAzureDevopsTracker(new DataBaseConfig("[YOUR_CONNECTION_STRING]")); + } + } +``` + +Novamente, diferente de um projeto MVC ou API, dentro da controller ao invés de injetar a interface será injetado a classe concreta. + +```c# + public class WorkItemFunctionsController + { + private readonly AzureDevopsTrackerService _azureDevopsTrackerService; + + public WorkItemFunctionsController( + AzureDevopsTrackerService azureDevopsTrackerService) + { + _azureDevopsTrackerService = azureDevopsTrackerService; + } + + [FunctionName("workitem")] + public async Task Create( + [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req, + ILogger log) + { + + try + { + var workItemDTO = JsonConvert.DeserializeObject(req.GetBody()); + await _azureDevopsTrackerService.Create(workItemDTO); + } + catch (Exception ex) + { + return new OkObjectResult(ex.Message); + } + + return new OkObjectResult(HttpStatusCode.OK); + } + + [FunctionName("workitem-update")] + public async Task Update( + [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req, + ILogger log) + { + try + { + var workItemDTO = JsonConvert.DeserializeObject(req.GetBody()); + await _azureDevopsTrackerService.Update(workItemDTO); + } + catch (Exception ex) + { + return new OkObjectResult(ex.Message); + } + + return new OkObjectResult(HttpStatusCode.OK); + } + } +``` + +Como resultado final, os endpoints ficarão da seguinte forma + +![Endpoints Azure Functions](https://drive.google.com/uc?export=view&id=1aKPWYHzqPVsnxcMdvN-dhtodL6l1BT_z) + + +## Etapa 2 +Criação da Azure Function no Portal Azure + +### Passo 1 + +Crie um recurso do tipo Function App com as configurações que desejar. + +![Passo 2](https://drive.google.com/uc?export=view&id=13xJhLb5_-dMzRGQwx-gN7FC7U3Pjz1_w) + +### Passo 2: + +Suba a Azure Function para o DevOps. Você pode ver um exemplo de como fazer isso pelo Azure DevOps em [typinghard.azure-devops-tracker-function](https://dev.azure.com/TypingHard/Typing%20Hard%20Project/_build?definitionId=7) e o exemplo do [yalm](https://github.com/typinghard/azure-devops-tracker-function/blob/main/azure-pipelines.yml). + +### Passo 3: + +Após isso, as Functions poderão ser visualizadas no Azure Portal. No exemplo abaixo, estão as Functions criadas nesse repositório. + +![Passo 3](https://drive.google.com/uc?export=view&id=1MpChtcrI1MI4mvoWR3QXAtz6g2bUbMsX) + +### Passo 4: + +Configurar no Azure DevOps as URLs, procedimento que também pode ser visto na Wiki na seção [Configurando o DevOps](https://github.com/typinghard/azure-devops-tracker/wiki/Portugu%C3%AAs#configurando-o-devops) From 026290b1c48a9b63408a5a33bcd48180d64ecd07 Mon Sep 17 00:00:00 2001 From: Elvis Souza Date: Sat, 11 Dec 2021 17:00:07 -0300 Subject: [PATCH 09/11] Updating ADT Nuget to 1.1.2-alpha version AB#81 --- .../AzureDevOpsStateTracker.Functions.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AzureDevOpsStateTracker.Functions/AzureDevOpsStateTracker.Functions.csproj b/AzureDevOpsStateTracker.Functions/AzureDevOpsStateTracker.Functions.csproj index 264a135..34bc5c2 100644 --- a/AzureDevOpsStateTracker.Functions/AzureDevOpsStateTracker.Functions.csproj +++ b/AzureDevOpsStateTracker.Functions/AzureDevOpsStateTracker.Functions.csproj @@ -6,7 +6,7 @@ true - + From 125cdbb60383f489168d63d1fbd890cbf4767541 Mon Sep 17 00:00:00 2001 From: Diego Galante Date: Tue, 14 Dec 2021 18:16:06 -0300 Subject: [PATCH 10/11] Updating --- .../AzureDevOpsStateTracker.Functions.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AzureDevOpsStateTracker.Functions/AzureDevOpsStateTracker.Functions.csproj b/AzureDevOpsStateTracker.Functions/AzureDevOpsStateTracker.Functions.csproj index 34bc5c2..22e319f 100644 --- a/AzureDevOpsStateTracker.Functions/AzureDevOpsStateTracker.Functions.csproj +++ b/AzureDevOpsStateTracker.Functions/AzureDevOpsStateTracker.Functions.csproj @@ -6,7 +6,7 @@ true - + From 0e2857298cbdfa0f4830cef615d54c87a98cc493 Mon Sep 17 00:00:00 2001 From: Diego Galante Date: Mon, 20 Dec 2021 19:48:11 -0300 Subject: [PATCH 11/11] Updating adt nuget package --- .../AzureDevOpsStateTracker.Functions.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AzureDevOpsStateTracker.Functions/AzureDevOpsStateTracker.Functions.csproj b/AzureDevOpsStateTracker.Functions/AzureDevOpsStateTracker.Functions.csproj index 22e319f..8c01ef8 100644 --- a/AzureDevOpsStateTracker.Functions/AzureDevOpsStateTracker.Functions.csproj +++ b/AzureDevOpsStateTracker.Functions/AzureDevOpsStateTracker.Functions.csproj @@ -6,7 +6,7 @@ true - +