diff --git a/.github/codewoners b/.github/codewoners new file mode 100644 index 0000000..e112dbf --- /dev/null +++ b/.github/codewoners @@ -0,0 +1,7 @@ +*.sln @DiegoGalante @ElvisCSouza +*.csproj @DiegoGalante @ElvisCSouza +*.cs @DiegoGalantee @ElvisCSouza + +*.* @DiegoGalante @ElvisCSouza + +.github/ @DiegoGalante diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..7856522 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,34 @@ +# Description + +> Please include a summary of the change here and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. + +## Type of change + +Please delete options that are not relevant. + + - [ ] Bug fix (non-breaking change which fixes an issue) + - [ ] New feature (non-breaking change which adds functionality) + - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) + - [ ] This change requires a documentation update + +## Fixes +Please delete options that are not relevant. + +\# (issue) + +## How Has This Been Tested + +Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration + + - [ ] Unit Tests + - [ ] Integration Tests + - [ ] Web application using this dll + postman + +## Checklist +- [ ] My code follows the style guidelines of this project +- [ ] I have performed a self-review of my own code +- [ ] I checked the PR checks reports +- [ ] I have commented my code, particularly in hard-to-understand areas +- [ ] I have made corresponding changes to the documentation +- [ ] My changes generate no new warnings +- [ ] I have added tests that prove my fix is effective or that my feature works diff --git a/.gitignore b/.gitignore index dfcfd56..3cab525 100644 --- a/.gitignore +++ b/.gitignore @@ -348,3 +348,9 @@ MigrationBackup/ # Ionide (cross platform F# VS Code tools) working folder .ionide/ + +.sonarqube + +*.bat + +*.xml \ No newline at end of file diff --git a/AzureDevopsTracker.sln b/AzureDevopsTracker.sln new file mode 100644 index 0000000..cf25253 --- /dev/null +++ b/AzureDevopsTracker.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32616.157 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AzureDevopsTracker", "src\AzureDevopsTracker.csproj", "{36601E24-C989-4E11-BD8F-572F2F181ED1}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{816B80C1-D0DA-4925-817C-692A5995BCB2}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{035AD571-2D23-4A55-9FBB-1E99758306C8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureDevopsTracker.Tests", "tests\AzureDevopsTracker.Tests\AzureDevopsTracker.Tests.csproj", "{BA1D5DF9-E25A-4984-8072-8CA3C5FC638D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {36601E24-C989-4E11-BD8F-572F2F181ED1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {36601E24-C989-4E11-BD8F-572F2F181ED1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {36601E24-C989-4E11-BD8F-572F2F181ED1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {36601E24-C989-4E11-BD8F-572F2F181ED1}.Release|Any CPU.Build.0 = Release|Any CPU + {BA1D5DF9-E25A-4984-8072-8CA3C5FC638D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BA1D5DF9-E25A-4984-8072-8CA3C5FC638D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BA1D5DF9-E25A-4984-8072-8CA3C5FC638D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BA1D5DF9-E25A-4984-8072-8CA3C5FC638D}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {36601E24-C989-4E11-BD8F-572F2F181ED1} = {035AD571-2D23-4A55-9FBB-1E99758306C8} + {BA1D5DF9-E25A-4984-8072-8CA3C5FC638D} = {816B80C1-D0DA-4925-817C-692A5995BCB2} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {53133A2B-5357-47B5-A1C4-30953F789623} + EndGlobalSection +EndGlobal diff --git a/AzureDevopsTracker/AzureDevopsTracker.sln b/AzureDevopsTracker/AzureDevopsTracker.sln deleted file mode 100644 index 5610a58..0000000 --- a/AzureDevopsTracker/AzureDevopsTracker.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}") = "AzureDevopsTracker", "AzureDevopsTracker.csproj", "{26FE19B9-7CD6-4418-9112-2E3C363985BF}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {26FE19B9-7CD6-4418-9112-2E3C363985BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {26FE19B9-7CD6-4418-9112-2E3C363985BF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {26FE19B9-7CD6-4418-9112-2E3C363985BF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {26FE19B9-7CD6-4418-9112-2E3C363985BF}.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/AzureDevopsTracker/DTOs/WorkItemDTO.cs b/AzureDevopsTracker/DTOs/WorkItemDTO.cs deleted file mode 100644 index e79e1fd..0000000 --- a/AzureDevopsTracker/DTOs/WorkItemDTO.cs +++ /dev/null @@ -1,100 +0,0 @@ -using Newtonsoft.Json; -using System; -using System.Collections.Generic; - -namespace AzureDevopsTracker.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/AzureDevopsTracker/Helpers/MarkdownHelper.cs b/AzureDevopsTracker/Helpers/MarkdownHelper.cs deleted file mode 100644 index f2b062e..0000000 --- a/AzureDevopsTracker/Helpers/MarkdownHelper.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace AzureDevopsTracker.Helpers -{ - internal static class MarkdownHelper - { - } -} diff --git a/AzureDevopsTracker/Helpers/MicrosoftTeamsHelper.cs b/AzureDevopsTracker/Helpers/MicrosoftTeamsHelper.cs deleted file mode 100644 index e4e7e4c..0000000 --- a/AzureDevopsTracker/Helpers/MicrosoftTeamsHelper.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace AzureDevopsTracker.Helpers -{ - internal static class MicrosoftTeamsHelper - { - } -} diff --git a/AzureDevopsTracker/Integrations/MessageBaseIntegration.cs b/AzureDevopsTracker/Integrations/MessageBaseIntegration.cs deleted file mode 100644 index 6390c21..0000000 --- a/AzureDevopsTracker/Integrations/MessageBaseIntegration.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace AzureDevopsTracker.Integrations -{ - internal abstract class MessageBaseIntegration - { - - } -} diff --git a/AzureDevopsTracker/Interfaces/IAzureDevopsTrackerService.cs b/AzureDevopsTracker/Interfaces/IAzureDevopsTrackerService.cs deleted file mode 100644 index 83dfe78..0000000 --- a/AzureDevopsTracker/Interfaces/IAzureDevopsTrackerService.cs +++ /dev/null @@ -1,18 +0,0 @@ -using AzureDevopsTracker.DTOs; -using AzureDevopsTracker.DTOs.Create; -using AzureDevopsTracker.DTOs.Delete; -using AzureDevopsTracker.DTOs.Restore; -using AzureDevopsTracker.DTOs.Update; -using System.Threading.Tasks; - -namespace AzureDevopsTracker.Interfaces -{ - public interface IAzureDevopsTrackerService - { - Task Create(CreateWorkItemDTO createDto, bool addWorkItemChange = true); - Task Update(UpdatedWorkItemDTO updateDto); - Task Delete(DeleteWorkItemDTO deleteDto); - Task Restore(RestoreWorkItemDTO restoreDto); - Task GetByWorkItemId(string workItemId); - } -} \ No newline at end of file diff --git a/AzureDevopsTracker/LICENSE.md.txt b/LICENSE.md.txt similarity index 100% rename from AzureDevopsTracker/LICENSE.md.txt rename to LICENSE.md.txt diff --git a/AzureDevopsTracker/Adapters/WorkItemAdapter.cs b/src/Adapters/WorkItemAdapter.cs similarity index 66% rename from AzureDevopsTracker/Adapters/WorkItemAdapter.cs rename to src/Adapters/WorkItemAdapter.cs index 8b8492b..b56aa17 100644 --- a/AzureDevopsTracker/Adapters/WorkItemAdapter.cs +++ b/src/Adapters/WorkItemAdapter.cs @@ -1,4 +1,4 @@ -using AzureDevopsTracker.DTOs; +using AzureDevopsTracker.Dtos; using AzureDevopsTracker.Entities; using AzureDevopsTracker.Extensions; using AzureDevopsTracker.Interfaces; @@ -10,11 +10,11 @@ namespace AzureDevopsTracker.Adapters { internal class WorkItemAdapter : IWorkItemAdapter { - public WorkItemDTO ToWorkItemDTO(WorkItem workItem) + public WorkItemDto ToWorkItemDto(WorkItem workItem) { if (workItem is null) return null; - return new WorkItemDTO() + return new WorkItemDto() { Id = workItem.Id, CreatedAt = workItem.CreatedAt, @@ -32,30 +32,30 @@ public WorkItemDTO ToWorkItemDTO(WorkItem workItem) WorkItemParentId = workItem.WorkItemParentId, Activity = workItem.Activity, Tags = workItem.Tags is null ? new List() : workItem.Tags.Split(';').ToList(), - WorkItemsChangesDTO = ToWorkItemsChangeDTO(workItem.WorkItemsChanges.OrderBy(x => x.CreatedAt).ToList()), - TimesByStateDTO = ToTimeByStatesDTO(workItem.CalculateTotalTimeByState().ToList()), + WorkItemsChangesDto = ToWorkItemsChangeDto(workItem.WorkItemsChanges.OrderBy(x => x.CreatedAt).ToList()), + TimesByStateDto = ToTimeByStatesDto(workItem.CalculateTotalTimeByState().ToList()), }; } - public List ToWorkItemsDTO(List workItems) + public List ToWorkItemsDto(List workItems) { - var workItemsDTO = new List(); + var workItemsDto = new List(); - if (workItems is null) return workItemsDTO; + if (workItems is null) return workItemsDto; workItems.ForEach( workItem => - workItemsDTO.Add(ToWorkItemDTO(workItem))); + workItemsDto.Add(ToWorkItemDto(workItem))); - return workItemsDTO + return workItemsDto .ToList(); } - public WorkItemChangeDTO ToWorkItemChangeDTO(WorkItemChange workIteChange) + public static WorkItemChangeDto ToWorkItemChangeDto(WorkItemChange workIteChange) { if (workIteChange is null) return null; - return new WorkItemChangeDTO() + return new WorkItemChangeDto() { NewDate = workIteChange.NewDate, NewState = workIteChange.NewState, @@ -65,26 +65,26 @@ public WorkItemChangeDTO ToWorkItemChangeDTO(WorkItemChange workIteChange) }; } - public List ToWorkItemsChangeDTO(List workItemsChanges) + public static List ToWorkItemsChangeDto(List workItemsChanges) { - var workItemsChangeDTO = new List(); + var workItemsChangeDto = new List(); - if (workItemsChanges is null) return workItemsChangeDTO; + if (workItemsChanges is null) return workItemsChangeDto; workItemsChanges.ForEach( workItemsChange => - workItemsChangeDTO.Add(ToWorkItemChangeDTO(workItemsChange))); + workItemsChangeDto.Add(ToWorkItemChangeDto(workItemsChange))); - return workItemsChangeDTO + return workItemsChangeDto .Where(w => w is not null) .ToList(); } - public TimeByStateDTO ToTimeByStateDTO(TimeByState workItemStatusTime) + public static TimeByStateDto ToTimeByStateDto(TimeByState workItemStatusTime) { if (workItemStatusTime is null) return null; - return new TimeByStateDTO() + return new TimeByStateDto() { CreatedAt = workItemStatusTime.CreatedAt, State = workItemStatusTime.State, @@ -93,17 +93,17 @@ public TimeByStateDTO ToTimeByStateDTO(TimeByState workItemStatusTime) }; } - public List ToTimeByStatesDTO(List workItemStatusTimes) + public static List ToTimeByStatesDto(List workItemStatusTimes) { - var workItemStatusTimeDTO = new List(); + var workItemStatusTimeDto = new List(); - if (workItemStatusTimes is null) return workItemStatusTimeDTO; + if (workItemStatusTimes is null) return workItemStatusTimeDto; workItemStatusTimes.ForEach( workItemStatusTime => - workItemStatusTimeDTO.Add(ToTimeByStateDTO(workItemStatusTime))); + workItemStatusTimeDto.Add(ToTimeByStateDto(workItemStatusTime))); - return workItemStatusTimeDTO + return workItemStatusTimeDto .Where(w => w is not null) .ToList(); } diff --git a/AzureDevopsTracker/AzureDevopsTracker.csproj b/src/AzureDevopsTracker.csproj similarity index 95% rename from AzureDevopsTracker/AzureDevopsTracker.csproj rename to src/AzureDevopsTracker.csproj index d83106b..03454f7 100644 --- a/AzureDevopsTracker/AzureDevopsTracker.csproj +++ b/src/AzureDevopsTracker.csproj @@ -2,7 +2,7 @@ net6.0 - False + True AzureDevOpsTracker Elvis Souza | Diego Galante TypingHard @@ -23,6 +23,13 @@ Add ChangeLog Feature + + + True + + + + @@ -31,13 +38,6 @@ - - - True - - - - True diff --git a/AzureDevopsTracker/Configurations/Configuration.cs b/src/Configurations/Configuration.cs similarity index 77% rename from AzureDevopsTracker/Configurations/Configuration.cs rename to src/Configurations/Configuration.cs index c9adcd0..cafa106 100644 --- a/AzureDevopsTracker/Configurations/Configuration.cs +++ b/src/Configurations/Configuration.cs @@ -10,16 +10,31 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using System; +using System.Linq; namespace AzureDevopsTracker.Configurations { public static class Configuration { - public static IServiceCollection AddAzureDevopsTracker(this IServiceCollection services, DataBaseConfig configurations, MessageConfig messageConfig = null) + public static IServiceCollection AddAzureDevopsTracker(this IServiceCollection services, + DataBaseConfig configurations, + MessageConfig messageConfig = null) { services.AddDbContext(options => options.UseSqlServer(DataBaseConfig.ConnectionsString)); + try + { + using var serviceScope = services.BuildServiceProvider().CreateScope(); + var dbContext = serviceScope.ServiceProvider.GetRequiredService(); + + var pendingMigrations = dbContext.Database.GetPendingMigrations(); + if (pendingMigrations.Any()) + dbContext.Database.Migrate(); + } + catch + { } + services.AddMessageIntegrations(); services.AddSingleton(); diff --git a/AzureDevopsTracker/DTOs/Create/CreateWorkItemDTO.cs b/src/DTOs/Create/CreateWorkItemDTO.cs similarity index 55% rename from AzureDevopsTracker/DTOs/Create/CreateWorkItemDTO.cs rename to src/DTOs/Create/CreateWorkItemDTO.cs index e19f527..12897a6 100644 --- a/AzureDevopsTracker/DTOs/Create/CreateWorkItemDTO.cs +++ b/src/DTOs/Create/CreateWorkItemDTO.cs @@ -1,12 +1,12 @@ using Newtonsoft.Json; using System.Text.Json.Serialization; -namespace AzureDevopsTracker.DTOs.Create +namespace AzureDevopsTracker.Dtos.Create { - public class CreateWorkItemDTO + public record CreateWorkItemDto { [JsonPropertyName("resource")] [JsonProperty("resource")] - public Resource Resource { get; set; } + public Resource Resource { get; init; } } } \ No newline at end of file diff --git a/AzureDevopsTracker/DTOs/Delete/DeleteWorkItemDTO.cs b/src/DTOs/Delete/DeleteWorkItemDTO.cs similarity index 55% rename from AzureDevopsTracker/DTOs/Delete/DeleteWorkItemDTO.cs rename to src/DTOs/Delete/DeleteWorkItemDTO.cs index 6b2e982..ecea0c3 100644 --- a/AzureDevopsTracker/DTOs/Delete/DeleteWorkItemDTO.cs +++ b/src/DTOs/Delete/DeleteWorkItemDTO.cs @@ -1,12 +1,12 @@ using Newtonsoft.Json; using System.Text.Json.Serialization; -namespace AzureDevopsTracker.DTOs.Delete +namespace AzureDevopsTracker.Dtos.Delete { - public class DeleteWorkItemDTO + public record DeleteWorkItemDto { [JsonPropertyName("resource")] [JsonProperty("resource")] - public Resource Resource { get; set; } + public Resource Resource { get; init; } } } diff --git a/AzureDevopsTracker/DTOs/Fields.cs b/src/DTOs/Fields.cs similarity index 67% rename from AzureDevopsTracker/DTOs/Fields.cs rename to src/DTOs/Fields.cs index aef4bd1..f1a0a2f 100644 --- a/AzureDevopsTracker/DTOs/Fields.cs +++ b/src/DTOs/Fields.cs @@ -2,79 +2,79 @@ using System; using System.Text.Json.Serialization; -namespace AzureDevopsTracker.DTOs +namespace AzureDevopsTracker.Dtos { - public class Fields + public record Fields { [JsonPropertyName("System.AreaPath")] [JsonProperty("System.AreaPath")] - public string AreaPath { get; set; } + public string AreaPath { get; init; } [JsonPropertyName("System.TeamProject")] [JsonProperty("System.TeamProject")] - public string TeamProject { get; set; } + public string TeamProject { get; init; } [JsonPropertyName("System.IterationPath")] [JsonProperty("System.IterationPath")] - public string IterationPath { get; set; } + public string IterationPath { get; init; } [JsonPropertyName("System.AssignedTo")] [JsonProperty("System.AssignedTo")] - public string AssignedTo { get; set; } + public string AssignedTo { get; init; } [JsonPropertyName("System.WorkItemType")] [JsonProperty("System.WorkItemType")] - public string Type { get; set; } + public string Type { get; init; } [JsonPropertyName("System.CreatedDate")] [JsonProperty("System.CreatedDate")] - public DateTime CreatedDate { get; set; } + public DateTime CreatedDate { get; init; } [JsonPropertyName("System.CreatedBy")] [JsonProperty("System.CreatedBy")] - public string CreatedBy { get; set; } + public string CreatedBy { get; init; } [JsonPropertyName("System.ChangedBy")] [JsonProperty("System.ChangedBy")] - public string ChangedBy { get; set; } + public string ChangedBy { get; init; } [JsonPropertyName("System.State")] [JsonProperty("System.State")] - public string State { get; set; } + public string State { get; init; } [JsonPropertyName("System.Title")] [JsonProperty("System.Title")] - public string Title { get; set; } + public string Title { get; init; } [JsonPropertyName("System.Tags")] [JsonProperty("System.Tags")] - public string Tags { get; set; } + public string Tags { get; init; } [JsonPropertyName("System.Parent")] [JsonProperty("System.Parent")] - public string Parent { get; set; } + public string Parent { get; init; } [JsonPropertyName("Microsoft.VSTS.Scheduling.StoryPoints")] [JsonProperty("Microsoft.VSTS.Scheduling.StoryPoints")] - public string StoryPoints { get; set; } + public string StoryPoints { get; init; } [JsonPropertyName("Microsoft.VSTS.Scheduling.OriginalEstimate")] [JsonProperty("Microsoft.VSTS.Scheduling.OriginalEstimate")] - public string OriginalEstimate { get; set; } + public string OriginalEstimate { get; init; } [JsonPropertyName("Microsoft.VSTS.Scheduling.RemainingWork")] [JsonProperty("Microsoft.VSTS.Scheduling.RemainingWork")] - public string RemainingWork { get; set; } + public string RemainingWork { get; init; } [JsonPropertyName("Microsoft.VSTS.Scheduling.Effort")] [JsonProperty("Microsoft.VSTS.Scheduling.Effort")] - public string Effort { get; set; } + public string Effort { get; init; } [JsonPropertyName("Microsoft.VSTS.Common.Activity")] [JsonProperty("Microsoft.VSTS.Common.Activity")] - public string Activity { get; set; } + public string Activity { get; init; } [JsonProperty("Custom.ChangeLogDescription")] - public string ChangeLogDescription { get; set; } + public string ChangeLogDescription { get; init; } } } \ No newline at end of file diff --git a/AzureDevopsTracker/DTOs/Resource.cs b/src/DTOs/Resource.cs similarity index 59% rename from AzureDevopsTracker/DTOs/Resource.cs rename to src/DTOs/Resource.cs index 7127dd6..2a4624b 100644 --- a/AzureDevopsTracker/DTOs/Resource.cs +++ b/src/DTOs/Resource.cs @@ -1,16 +1,16 @@ using Newtonsoft.Json; using System.Text.Json.Serialization; -namespace AzureDevopsTracker.DTOs +namespace AzureDevopsTracker.Dtos { - public class Resource + public record Resource { [JsonPropertyName("id")] [JsonProperty("id")] - public string Id { get; set; } + public string Id { get; init; } [JsonPropertyName("fields")] [JsonProperty("fields")] - public Fields Fields { get; set; } + public Fields Fields { get; init; } } } diff --git a/AzureDevopsTracker/DTOs/Restore/RestoreWorkItemDTO.cs b/src/DTOs/Restore/RestoreWorkItemDTO.cs similarity index 54% rename from AzureDevopsTracker/DTOs/Restore/RestoreWorkItemDTO.cs rename to src/DTOs/Restore/RestoreWorkItemDTO.cs index c5d2890..82c1695 100644 --- a/AzureDevopsTracker/DTOs/Restore/RestoreWorkItemDTO.cs +++ b/src/DTOs/Restore/RestoreWorkItemDTO.cs @@ -1,12 +1,12 @@ using Newtonsoft.Json; using System.Text.Json.Serialization; -namespace AzureDevopsTracker.DTOs.Restore +namespace AzureDevopsTracker.Dtos.Restore { - public class RestoreWorkItemDTO + public record RestoreWorkItemDto { [JsonPropertyName("resource")] [JsonProperty("resource")] - public Resource Resource { get; set; } + public Resource Resource { get; init; } } } diff --git a/AzureDevopsTracker/DTOs/Update/UpdateWorkItemDTO.cs b/src/DTOs/Update/UpdateWorkItemDTO.cs similarity index 57% rename from AzureDevopsTracker/DTOs/Update/UpdateWorkItemDTO.cs rename to src/DTOs/Update/UpdateWorkItemDTO.cs index 8907979..3f59018 100644 --- a/AzureDevopsTracker/DTOs/Update/UpdateWorkItemDTO.cs +++ b/src/DTOs/Update/UpdateWorkItemDTO.cs @@ -2,72 +2,72 @@ using System; using System.Text.Json.Serialization; -namespace AzureDevopsTracker.DTOs.Update +namespace AzureDevopsTracker.Dtos.Update { - public class UpdatedWorkItemDTO + public record UpdatedWorkItemDto { [JsonPropertyName("resource")] [JsonProperty("resource")] - public Resource Resource { get; set; } + public Resource Resource { get; init; } } - public class Resource + public record Resource { [JsonPropertyName("workItemId")] [JsonProperty("workItemId")] - public string WorkItemId { get; set; } + public string WorkItemId { get; init; } [JsonPropertyName("fields")] [JsonProperty("fields")] - public ResourceFields Fields { get; set; } + public ResourceFields Fields { get; init; } [JsonPropertyName("revision")] [JsonProperty("revision")] - public Revision Revision { get; set; } + public Revision Revision { get; init; } } - public class Revision + public record Revision { [JsonPropertyName("fields")] [JsonProperty("fields")] - public Fields Fields { get; set; } + public Fields Fields { get; init; } } - public class ResourceFields + public record ResourceFields { [JsonPropertyName("System.State")] [JsonProperty("System.State")] - public OldNewValues State { get; set; } + public OldNewValues State { get; init; } [JsonPropertyName("Microsoft.VSTS.Common.StateChangeDate")] [JsonProperty("Microsoft.VSTS.Common.StateChangeDate")] - public DateTimeOldNewValues StateChangeDate { get; set; } + public DateTimeOldNewValues StateChangeDate { get; init; } [JsonPropertyName("System.ChangedBy")] [JsonProperty("System.ChangedBy")] - public OldNewValues ChangedBy { get; set; } + public OldNewValues ChangedBy { get; init; } } - public class OldNewValues + public record OldNewValues { [JsonPropertyName("oldValue")] [JsonProperty("oldValue")] - public string OldValue { get; set; } + public string OldValue { get; init; } [JsonPropertyName("newValue")] [JsonProperty("newValue")] - public string NewValue { get; set; } + public string NewValue { get; init; } } - public class DateTimeOldNewValues + public record DateTimeOldNewValues { [JsonPropertyName("oldValue")] [JsonProperty("oldValue")] - public DateTime OldValue { get; set; } + public DateTime OldValue { get; init; } [JsonPropertyName("newValue")] [JsonProperty("newValue")] - public DateTime NewValue { get; set; } + public DateTime NewValue { get; init; } } } \ No newline at end of file diff --git a/src/DTOs/WorkItemDTO.cs b/src/DTOs/WorkItemDTO.cs new file mode 100644 index 0000000..9553f89 --- /dev/null +++ b/src/DTOs/WorkItemDTO.cs @@ -0,0 +1,100 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; + +namespace AzureDevopsTracker.Dtos +{ + public record WorkItemDto + { + [JsonProperty("id")] + public string Id { get; init; } + + [JsonProperty("created_at")] + public DateTime CreatedAt { get; init; } + + [JsonProperty("assigned_to")] + public string AssignedTo { get; init; } + + [JsonProperty("type")] + public string Type { get; init; } + + [JsonProperty("effort")] + public string Effort { get; init; } + + [JsonProperty("story_points")] + public string StoryPoints { get; init; } + + [JsonProperty("original_estimate")] + public string OriginalEstimate { get; init; } + + [JsonProperty("created_by")] + public string CreatedBy { get; init; } + + [JsonProperty("title")] + public string Title { get; init; } + + [JsonProperty("team_project")] + public string TeamProject { get; init; } + + [JsonProperty("iteration_path")] + public string IterationPath { get; init; } + + [JsonProperty("area_path")] + public string AreaPath { get; init; } + + [JsonProperty("current_status")] + public string CurrentStatus { get; init; } + + [JsonProperty("work_item_parent_id")] + public string WorkItemParentId { get; init; } + + [JsonProperty("activity")] + public string Activity { get; init; } + + [JsonProperty("tags")] + public IEnumerable Tags { get; init; } + + [JsonProperty("workItems_changes")] + public List WorkItemsChangesDto { get; init; } + + [JsonProperty("times_by_state")] + public List TimesByStateDto { get; init; } + } + + public record WorkItemChangeDto + { + [JsonProperty("new_date")] + public DateTime NewDate { get; init; } + + [JsonProperty("new_state")] + public string NewState { get; init; } + + [JsonProperty("old_state")] + public string OldState { get; init; } + + [JsonProperty("old_date")] + public DateTime? OldDate { get; init; } + + [JsonProperty("changed_by")] + public string ChangedBy { get; init; } + } + + + public record TimeByStateDto + { + [JsonProperty("created_at")] + public DateTime CreatedAt { get; init; } + + [JsonProperty("updated_at")] + public DateTime UpdatedAt { get; init; } + + [JsonProperty("state")] + public string State { get; init; } + + [JsonProperty("total_time")] + public string TotalTime { get; init; } + + [JsonProperty("total_worked_time")] + public string TotalWorkedTime { get; init; } + } +} diff --git a/AzureDevopsTracker/Data/ChangeLogItemRepository.cs b/src/Data/ChangeLogItemRepository.cs similarity index 54% rename from AzureDevopsTracker/Data/ChangeLogItemRepository.cs rename to src/Data/ChangeLogItemRepository.cs index b4b0939..02d3746 100644 --- a/AzureDevopsTracker/Data/ChangeLogItemRepository.cs +++ b/src/Data/ChangeLogItemRepository.cs @@ -1,8 +1,10 @@ using AzureDevopsTracker.Data.Context; using AzureDevopsTracker.Entities; using AzureDevopsTracker.Interfaces.Internals; +using Microsoft.EntityFrameworkCore; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; namespace AzureDevopsTracker.Data { @@ -10,14 +12,14 @@ internal class ChangeLogItemRepository : Repository, IChangeLogIt { public ChangeLogItemRepository(AzureDevopsTrackerContext context) : base(context) { } - public int CountItemsForRelease() + public async Task CountItemsForRelease() { - return DbSet.Count(x => string.IsNullOrEmpty(x.ChangeLogId)); + return await DbSet.CountAsync(x => string.IsNullOrEmpty(x.ChangeLogId)); } - public IEnumerable ListWaitingForRelease() + public async Task> ListWaitingForRelease() { - return DbSet.Where(x => string.IsNullOrEmpty(x.ChangeLogId)); + return await DbSet.Where(x => string.IsNullOrEmpty(x.ChangeLogId)).ToListAsync(); } } } \ No newline at end of file diff --git a/AzureDevopsTracker/Data/ChangeLogRepository.cs b/src/Data/ChangeLogRepository.cs similarity index 64% rename from AzureDevopsTracker/Data/ChangeLogRepository.cs rename to src/Data/ChangeLogRepository.cs index 7067039..c12243a 100644 --- a/AzureDevopsTracker/Data/ChangeLogRepository.cs +++ b/src/Data/ChangeLogRepository.cs @@ -1,9 +1,9 @@ using AzureDevopsTracker.Data.Context; using AzureDevopsTracker.Entities; using AzureDevopsTracker.Interfaces.Internals; +using Microsoft.EntityFrameworkCore; using System; -using System.Collections.Generic; -using System.Linq; +using System.Threading.Tasks; namespace AzureDevopsTracker.Data { @@ -11,9 +11,9 @@ internal class ChangeLogRepository : Repository, IChangeLogRepository { public ChangeLogRepository(AzureDevopsTrackerContext context) : base(context) { } - public int CountChangeLogsCreatedToday() + public async Task CountChangeLogsCreatedToday() { - return DbSet.Count(x => x.CreatedAt.Date == DateTime.Now.Date); + return await DbSet.CountAsync(x => x.CreatedAt.Date == DateTime.Now.Date); } } } \ No newline at end of file diff --git a/AzureDevopsTracker/Data/Context/AzureDevopsTrackerContext.cs b/src/Data/Context/AzureDevopsTrackerContext.cs similarity index 100% rename from AzureDevopsTracker/Data/Context/AzureDevopsTrackerContext.cs rename to src/Data/Context/AzureDevopsTrackerContext.cs diff --git a/AzureDevopsTracker/Data/DataBaseConfig.cs b/src/Data/DataBaseConfig.cs similarity index 100% rename from AzureDevopsTracker/Data/DataBaseConfig.cs rename to src/Data/DataBaseConfig.cs diff --git a/AzureDevopsTracker/Data/Mapping/ChangeLogItemMapping.cs b/src/Data/Mapping/ChangeLogItemMapping.cs similarity index 100% rename from AzureDevopsTracker/Data/Mapping/ChangeLogItemMapping.cs rename to src/Data/Mapping/ChangeLogItemMapping.cs diff --git a/AzureDevopsTracker/Data/Mapping/ChangeLogMapping.cs b/src/Data/Mapping/ChangeLogMapping.cs similarity index 100% rename from AzureDevopsTracker/Data/Mapping/ChangeLogMapping.cs rename to src/Data/Mapping/ChangeLogMapping.cs diff --git a/AzureDevopsTracker/Data/Mapping/CustomFieldMapping.cs b/src/Data/Mapping/CustomFieldMapping.cs similarity index 100% rename from AzureDevopsTracker/Data/Mapping/CustomFieldMapping.cs rename to src/Data/Mapping/CustomFieldMapping.cs diff --git a/AzureDevopsTracker/Data/Repository.cs b/src/Data/Repository.cs similarity index 98% rename from AzureDevopsTracker/Data/Repository.cs rename to src/Data/Repository.cs index 3bf46b4..693cac2 100644 --- a/AzureDevopsTracker/Data/Repository.cs +++ b/src/Data/Repository.cs @@ -4,6 +4,7 @@ using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; namespace AzureDevopsTracker.Data diff --git a/AzureDevopsTracker/Data/WorkItemRepository.cs b/src/Data/WorkItemRepository.cs similarity index 100% rename from AzureDevopsTracker/Data/WorkItemRepository.cs rename to src/Data/WorkItemRepository.cs diff --git a/AzureDevopsTracker/Entities/ChangeLog.cs b/src/Entities/ChangeLog.cs similarity index 72% rename from AzureDevopsTracker/Entities/ChangeLog.cs rename to src/Entities/ChangeLog.cs index f8c2109..564eb4a 100644 --- a/AzureDevopsTracker/Entities/ChangeLog.cs +++ b/src/Entities/ChangeLog.cs @@ -9,31 +9,20 @@ public class ChangeLog : Entity public string Response { get; private set; } public string Number { get; private set; } public int Revision { get; private set; } - - private readonly List _changeLogItems = new List(); + private readonly List _changeLogItems = new(); public IReadOnlyCollection ChangeLogItems => _changeLogItems; - private ChangeLog() { } + private ChangeLog() { } + public ChangeLog(string number) => Number = number; public ChangeLog(int newRevision) { Revision = newRevision; - Number = $"{ CreatedAt:yyyyMMdd}.{ Revision }"; - } - - public ChangeLog(string number) - { - Number = number; - } - - public void SetResponse(string response) - { - Response = response; + Number = $"{CreatedAt:yyyyMMdd}.{Revision}"; } - public void ClearResponse() - { - Response = string.Empty; - } + public void SetResponse(string response) => Response = response; + public void ClearResponse() => Response = string.Empty; + private bool CheckChangeLogItem(ChangeLogItem changeLogItem) => _changeLogItems.Any(x => x.WorkItemId == changeLogItem.WorkItemId); public void AddChangeLogItem(ChangeLogItem changeLogItem) { @@ -53,14 +42,7 @@ public void AddChangeLogItems(IEnumerable changeLogItems) throw new Exception("ChangeLogItems is required"); foreach (var changeLogItem in changeLogItems) - { AddChangeLogItem(changeLogItem); - } - } - - private bool CheckChangeLogItem(ChangeLogItem changeLogItem) - { - return _changeLogItems.Any(x => x.WorkItemId == changeLogItem.WorkItemId); } } } \ No newline at end of file diff --git a/AzureDevopsTracker/Entities/ChangeLogItem.cs b/src/Entities/ChangeLogItem.cs similarity index 72% rename from AzureDevopsTracker/Entities/ChangeLogItem.cs rename to src/Entities/ChangeLogItem.cs index 64ac837..29aca95 100644 --- a/AzureDevopsTracker/Entities/ChangeLogItem.cs +++ b/src/Entities/ChangeLogItem.cs @@ -10,13 +10,14 @@ public class ChangeLogItem : Entity public string Description { get; private set; } public string WorkItemType { get; private set; } public string ChangeLogId { get; private set; } - public bool WasReleased => string.IsNullOrEmpty(ChangeLogId?.Trim()); - - /*EF*/ + public bool WasReleased => string.IsNullOrWhiteSpace(ChangeLogId); public ChangeLog ChangeLog { get; private set; } - private ChangeLogItem() { } - public ChangeLogItem(string workItemId, string title, string description, string workItemType) + private ChangeLogItem() { } + public ChangeLogItem(string workItemId, + string title, + string description, + string workItemType) { WorkItemId = workItemId; Title = title; @@ -26,18 +27,17 @@ public ChangeLogItem(string workItemId, string title, string description, string Validate(); } - public void Update(string title, string workItemType, string description) + public void Release(string changeLogId) => ChangeLogId = changeLogId; + + public void Update(string title, + string workItemType, + string description) { Title = title; WorkItemType = workItemType; Description = description; } - public void Release(string changeLogId) - { - ChangeLogId = changeLogId; - } - public void Validate() { if (WorkItemId.IsNullOrEmpty() || Convert.ToInt64(WorkItemId) <= 0) diff --git a/AzureDevopsTracker/Entities/Entity.cs b/src/Entities/Entity.cs similarity index 86% rename from AzureDevopsTracker/Entities/Entity.cs rename to src/Entities/Entity.cs index 46f0a70..88a3328 100644 --- a/AzureDevopsTracker/Entities/Entity.cs +++ b/src/Entities/Entity.cs @@ -6,13 +6,14 @@ public abstract class Entity { public string Id { get; protected set; } public DateTime CreatedAt { get; private set; } - public Entity(string id) + + protected Entity(string id) { Id = id ?? Guid.NewGuid().ToString(); CreatedAt = DateTime.UtcNow; } - public Entity() + protected Entity() { Id = Guid.NewGuid().ToString(); CreatedAt = DateTime.UtcNow; diff --git a/AzureDevopsTracker/Entities/TimeByState.cs b/src/Entities/TimeByState.cs similarity index 83% rename from AzureDevopsTracker/Entities/TimeByState.cs rename to src/Entities/TimeByState.cs index febfbe5..fad334a 100644 --- a/AzureDevopsTracker/Entities/TimeByState.cs +++ b/src/Entities/TimeByState.cs @@ -9,12 +9,13 @@ public class TimeByState : Entity 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) + public TimeByState(string workItemId, + string state, + TimeSpan totalTime, + TimeSpan totalWorkedTime) { WorkItemId = workItemId; State = state; diff --git a/AzureDevopsTracker/Entities/WorkItem.cs b/src/Entities/WorkItem.cs similarity index 91% rename from AzureDevopsTracker/Entities/WorkItem.cs rename to src/Entities/WorkItem.cs index cacdda3..d77090b 100644 --- a/AzureDevopsTracker/Entities/WorkItem.cs +++ b/src/Entities/WorkItem.cs @@ -21,7 +21,6 @@ public class WorkItem : Entity public string WorkItemParentId { get; private set; } public string Activity { get; private set; } public bool Deleted { get; private set; } - public ChangeLogItem ChangeLogItem { get; private set; } private readonly List _workItemsChanges = new(); @@ -36,7 +35,6 @@ public class WorkItem : Entity public string LastStatus => _workItemsChanges?.OrderBy(x => x.CreatedAt)?.ToList()?.Skip(1)?.LastOrDefault()?.OldState; private WorkItem() { } - public WorkItem(string workItemId) : base(workItemId) { Validate(); @@ -68,15 +66,10 @@ public void Update(string title, Activity = activity; } - public void Restore() - { - Deleted = false; - } - - public void Delete() - { - Deleted = true; - } + public void Restore() => Deleted = false; + public void Delete() => Deleted = true; + public void ClearTimesByState() => _timeByState.Clear(); + public void RemoveChangeLogItem() => ChangeLogItem = null; public void Validate() { @@ -102,7 +95,7 @@ public void AddTimeByState(TimeByState timeByState) public void AddTimesByState(IEnumerable timesByState) { - if (timesByState is not null && !timesByState.Any()) + if (timesByState is null || timesByState?.Any() == false) return; foreach (var timeByState in timesByState) @@ -135,16 +128,6 @@ public void UpdateCustomFields(IEnumerable newCustomFields) AddCustomFields(newCustomFields); } - public void ClearTimesByState() - { - _timeByState.Clear(); - } - - public void RemoveChangeLogItem() - { - ChangeLogItem = null; - } - public void VinculateChangeLogItem(ChangeLogItem changeLogItem) { if (changeLogItem is null) @@ -159,7 +142,9 @@ public IEnumerable CalculateTotalTimeByState() if (!_workItemsChanges.Any()) return timesByStateList; - foreach (var workItemChange in _workItemsChanges.OrderBy(x => x.CreatedAt).GroupBy(x => x.OldState).Where(x => x.Key is not null)) + foreach (var workItemChange in _workItemsChanges.OrderBy(x => x.CreatedAt) + .GroupBy(x => x.OldState) + .Where(x => x.Key is not null)) { var totalTime = TimeSpan.Zero; var totalWorkedTime = TimeSpan.Zero; diff --git a/AzureDevopsTracker/Entities/WorkItemChange.cs b/src/Entities/WorkItemChange.cs similarity index 90% rename from AzureDevopsTracker/Entities/WorkItemChange.cs rename to src/Entities/WorkItemChange.cs index 29a276e..5b601ac 100644 --- a/AzureDevopsTracker/Entities/WorkItemChange.cs +++ b/src/Entities/WorkItemChange.cs @@ -13,12 +13,16 @@ public class WorkItemChange : Entity public string ChangedBy { get; private set; } public string IterationPath { get; private set; } public double TotalWorkedTime { get; private set; } - public WorkItem WorkItem { get; private set; } private WorkItemChange() { } - - public WorkItemChange(string workItemId, string changedBy, string iterationPath, DateTime newDate, string newState, string oldState, DateTime? oldDate) + public WorkItemChange(string workItemId, + string changedBy, + string iterationPath, + DateTime newDate, + string newState, + string oldState, + DateTime? oldDate) { WorkItemId = workItemId; NewDate = newDate; @@ -38,10 +42,7 @@ public void Validate() throw new Exception("WorkItemId is required"); } - public TimeSpan CalculateTotalTime() - { - return OldDate is null ? TimeSpan.Zero : NewDate.ToDateTimeFromTimeZoneInfo() - OldDate.Value.ToDateTimeFromTimeZoneInfo(); - } + public TimeSpan CalculateTotalTime() => OldDate is null ? TimeSpan.Zero : NewDate.ToDateTimeFromTimeZoneInfo() - OldDate.Value.ToDateTimeFromTimeZoneInfo(); public double CalculateTotalWorkedTime() { @@ -137,7 +138,8 @@ public double CalculateTotalWorkedTime() return secondsWorked; } - private TimeSpan SubtractDates(DateTime biger, DateTime minor) + #region Private Methods + private static TimeSpan SubtractDates(DateTime biger, DateTime minor) { if (biger.Hour == minor.Hour) { @@ -163,5 +165,6 @@ private TimeSpan SubtractDates(DateTime biger, DateTime minor) return biger.Subtract(minor); } } + #endregion } } \ No newline at end of file diff --git a/AzureDevopsTracker/Entities/WorkItemCustomField.cs b/src/Entities/WorkItemCustomField.cs similarity index 69% rename from AzureDevopsTracker/Entities/WorkItemCustomField.cs rename to src/Entities/WorkItemCustomField.cs index 919a695..2f9b36c 100644 --- a/AzureDevopsTracker/Entities/WorkItemCustomField.cs +++ b/src/Entities/WorkItemCustomField.cs @@ -1,5 +1,4 @@ using AzureDevopsTracker.Extensions; -using System; namespace AzureDevopsTracker.Entities { @@ -8,19 +7,17 @@ public class WorkItemCustomField public string WorkItemId { get; private set; } public string Key { get; private set; } public string Value { get; private set; } - public WorkItem WorkItem { get; private set; } - public WorkItemCustomField(string workItemId, string key, string value) + public WorkItemCustomField(string workItemId, + string key, + string value) { WorkItemId = workItemId; Key = key.Truncate(1000); Value = value.Truncate(); } - public void Update(string value) - { - Value = value; - } + public void Update(string value) => Value = value; } } \ No newline at end of file diff --git a/AzureDevopsTracker/Extensions/HelperExtenions.cs b/src/Extensions/HelperExtenions.cs similarity index 94% rename from AzureDevopsTracker/Extensions/HelperExtenions.cs rename to src/Extensions/HelperExtenions.cs index f4a5859..a233420 100644 --- a/AzureDevopsTracker/Extensions/HelperExtenions.cs +++ b/src/Extensions/HelperExtenions.cs @@ -22,10 +22,10 @@ public static string ExtractEmail(this string user) if (user is null) return user; - if (!user.Contains(" <") && !user.TrimEnd().Contains(">")) + if (!user.Contains(" <") && !user.TrimEnd().Contains('>')) return user; - return user.Split("<").LastOrDefault().Split(">").FirstOrDefault(); + return user.Split('<').LastOrDefault()?.Split('>')?.FirstOrDefault(); } public static string ToTextTime(this TimeSpan timeSpan) diff --git a/src/Helpers/MarkdownHelper.cs b/src/Helpers/MarkdownHelper.cs new file mode 100644 index 0000000..cc6c352 --- /dev/null +++ b/src/Helpers/MarkdownHelper.cs @@ -0,0 +1,4 @@ +namespace AzureDevopsTracker.Helpers +{ + internal static class MarkdownHelper { } +} diff --git a/src/Helpers/MicrosoftTeamsHelper.cs b/src/Helpers/MicrosoftTeamsHelper.cs new file mode 100644 index 0000000..d98c620 --- /dev/null +++ b/src/Helpers/MicrosoftTeamsHelper.cs @@ -0,0 +1,4 @@ +namespace AzureDevopsTracker.Helpers +{ + internal static class MicrosoftTeamsHelper { } +} diff --git a/AzureDevopsTracker/Helpers/RawTextHelper.cs b/src/Helpers/RawTextHelper.cs similarity index 100% rename from AzureDevopsTracker/Helpers/RawTextHelper.cs rename to src/Helpers/RawTextHelper.cs diff --git a/AzureDevopsTracker/Helpers/ReadJsonHelper.cs b/src/Helpers/ReadJsonHelper.cs similarity index 100% rename from AzureDevopsTracker/Helpers/ReadJsonHelper.cs rename to src/Helpers/ReadJsonHelper.cs diff --git a/AzureDevopsTracker/Integrations/DiscordIntegration.cs b/src/Integrations/DiscordIntegration.cs similarity index 94% rename from AzureDevopsTracker/Integrations/DiscordIntegration.cs rename to src/Integrations/DiscordIntegration.cs index 16fe655..f3868f2 100644 --- a/AzureDevopsTracker/Integrations/DiscordIntegration.cs +++ b/src/Integrations/DiscordIntegration.cs @@ -5,12 +5,13 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; namespace AzureDevopsTracker.Integrations { internal class DiscordIntegration : MessageIntegration { - internal override void Send(ChangeLog changeLog) + internal override async Task Send(ChangeLog changeLog) { var embedsDTO = new EmbedsDTO { @@ -26,7 +27,7 @@ internal override void Send(ChangeLog changeLog) }, }; - Notify(embedsDTO); + await Notify(embedsDTO); } public class EmbedsDTO @@ -97,7 +98,7 @@ public class Field public bool IsInline { get; set; } } - private IEnumerable GetText(ChangeLog changeLog) + private static IEnumerable GetText(ChangeLog changeLog) { var changeLogItemsAgrupado = changeLog.ChangeLogItems.GroupBy(d => d.WorkItemType); diff --git a/AzureDevopsTracker/Integrations/FakeIntegration.cs b/src/Integrations/FakeIntegration.cs similarity index 61% rename from AzureDevopsTracker/Integrations/FakeIntegration.cs rename to src/Integrations/FakeIntegration.cs index 420fb38..68d3cfc 100644 --- a/AzureDevopsTracker/Integrations/FakeIntegration.cs +++ b/src/Integrations/FakeIntegration.cs @@ -1,12 +1,10 @@ using AzureDevopsTracker.Entities; +using System.Threading.Tasks; namespace AzureDevopsTracker.Integrations { internal class FakeIntegration : MessageIntegration { - internal override void Send(ChangeLog changeLog) - { - - } + internal override async Task Send(ChangeLog changeLog) { } } } diff --git a/src/Integrations/MessageBaseIntegration.cs b/src/Integrations/MessageBaseIntegration.cs new file mode 100644 index 0000000..ba71b58 --- /dev/null +++ b/src/Integrations/MessageBaseIntegration.cs @@ -0,0 +1,4 @@ +namespace AzureDevopsTracker.Integrations +{ + internal abstract class MessageBaseIntegration { } +} diff --git a/AzureDevopsTracker/Integrations/MessageConfig.cs b/src/Integrations/MessageConfig.cs similarity index 77% rename from AzureDevopsTracker/Integrations/MessageConfig.cs rename to src/Integrations/MessageConfig.cs index e484b9c..3a426ce 100644 --- a/AzureDevopsTracker/Integrations/MessageConfig.cs +++ b/src/Integrations/MessageConfig.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace AzureDevopsTracker.Integrations +namespace AzureDevopsTracker.Integrations { public class MessageConfig { diff --git a/AzureDevopsTracker/Integrations/MessageFacade.cs b/src/Integrations/MessageFacade.cs similarity index 84% rename from AzureDevopsTracker/Integrations/MessageFacade.cs rename to src/Integrations/MessageFacade.cs index b41e5b8..a25f511 100644 --- a/AzureDevopsTracker/Integrations/MessageFacade.cs +++ b/src/Integrations/MessageFacade.cs @@ -1,6 +1,7 @@ using AzureDevopsTracker.Entities; using Microsoft.Extensions.DependencyInjection; using System; +using System.Threading.Tasks; namespace AzureDevopsTracker.Integrations { @@ -14,14 +15,14 @@ public MessageFacade( _serviceScopeFactory = serviceScopeFactory; } - public void Send(ChangeLog changeLog) + public async Task Send(ChangeLog changeLog) { using var scope = _serviceScopeFactory.CreateScope(); var messageIntegration = scope.ServiceProvider.GetService(); if (messageIntegration is null) throw new Exception("Configure the MessageConfig in Startup to send changelog messages"); - messageIntegration.Send(changeLog); + await messageIntegration.Send(changeLog); } } } diff --git a/AzureDevopsTracker/Integrations/MessageIntegration.cs b/src/Integrations/MessageIntegration.cs similarity index 67% rename from AzureDevopsTracker/Integrations/MessageIntegration.cs rename to src/Integrations/MessageIntegration.cs index 56a954f..781cd81 100644 --- a/AzureDevopsTracker/Integrations/MessageIntegration.cs +++ b/src/Integrations/MessageIntegration.cs @@ -2,59 +2,58 @@ using System; using System.Net.Http; using System.Text; +using System.Threading.Tasks; namespace AzureDevopsTracker.Integrations { public abstract class MessageIntegration { - internal abstract void Send(ChangeLog changeLog); + internal abstract Task Send(ChangeLog changeLog); private static readonly string MIMETYPE = "application/json"; private static readonly string CDN_URL = "https://cdn.typinghard.tech/"; private static readonly string MEGAFONE_GIF = "megafone.gif"; private static readonly string LOGO_TYPINGHARD_16X16 = "logo-typinghard-16x16.png"; - protected internal string GetTitle() + protected internal static string GetTitle() { return $"Nova atualização da plataforma"; } - protected internal string GetVersion(ChangeLog changeLog) + protected internal static string GetVersion(ChangeLog changeLog) { return $"Versão: {changeLog.Number}"; } - protected internal string GetAnnouncementImageUrl() + protected internal static string GetAnnouncementImageUrl() { return $"{CDN_URL}{MEGAFONE_GIF}"; } - protected internal string GetLogoTypingHard16x16Url() + protected internal static string GetLogoTypingHard16x16Url() { return $"{CDN_URL}{LOGO_TYPINGHARD_16X16}"; } - protected internal string GetFileVersion() + protected internal static string GetFileVersion() { System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly(); System.Diagnostics.FileVersionInfo fileVersionInfo = System.Diagnostics.FileVersionInfo.GetVersionInfo(assembly.Location); return fileVersionInfo.FileVersion; } - protected internal string GetNugetVersion() + protected internal static string GetNugetVersion() { - return $"Powered by **Typing Hard** • nuget version { GetFileVersion() }"; + return $"Powered by **Typing Hard** • nuget version {GetFileVersion()}"; } - protected internal HttpResponseMessage Notify(object body) + protected internal static async Task Notify(object body) { var json = Newtonsoft.Json.JsonConvert.SerializeObject(body); var content = new StringContent(json, Encoding.UTF8, MIMETYPE); - HttpClient client = new HttpClient(); - return client.PostAsync(new Uri(MessageConfig.URL), - content).Result; - + using HttpClient client = new(); + return await client.PostAsync(new Uri(MessageConfig.URL), content); } } } diff --git a/AzureDevopsTracker/Integrations/MicrosoftTeamsIntegration.cs b/src/Integrations/MicrosoftTeamsIntegration.cs similarity index 82% rename from AzureDevopsTracker/Integrations/MicrosoftTeamsIntegration.cs rename to src/Integrations/MicrosoftTeamsIntegration.cs index ff9fd42..57af2f9 100644 --- a/AzureDevopsTracker/Integrations/MicrosoftTeamsIntegration.cs +++ b/src/Integrations/MicrosoftTeamsIntegration.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Threading.Tasks; namespace AzureDevopsTracker.Integrations { @@ -38,7 +39,7 @@ internal static class MicrosoftTeamsStatics internal static readonly int CLOSING_DIV_SIZE = 6; } - internal override void Send(ChangeLog changeLog) + internal override async Task Send(ChangeLog changeLog) { var values = new MicrosoftTeamsMessage() { @@ -59,10 +60,10 @@ internal override void Send(ChangeLog changeLog) } }; - Notify(values); + await Notify(values); } - private string GetText(ChangeLog changeLog) + private static string GetText(ChangeLog changeLog) { if (changeLog is null || !changeLog.ChangeLogItems.Any()) return string.Empty; @@ -74,12 +75,12 @@ private string GetText(ChangeLog changeLog) return text.ToString(); } - private string GetWorkItemsDescriptionSection(string sectionName, IEnumerable changeLogItems) + private static string GetWorkItemsDescriptionSection(string sectionName, IEnumerable changeLogItems) { StringBuilder text = new(); if (!changeLogItems.Any()) return string.Empty; - text.AppendLine($"\n# **{ sectionName }**\n"); + text.AppendLine($"\n# **{sectionName}**\n"); foreach (var workItem in changeLogItems) text.AppendLine(GetWorkItemDescriptionLine(workItem)); @@ -87,20 +88,20 @@ private string GetWorkItemsDescriptionSection(string sectionName, IEnumerable**{ workItem.WorkItemId }** - { description }
"; + return $"**{workItem.WorkItemId}** - {description}
"; } - private string GetDescription(string description) + private static string GetDescription(string description) { return description.Replace("
", "").Replace("
", "").Replace("
", ""); } - private string GetFooter() + private static string GetFooter() { - return $"
{ GetNugetVersion() }"; + return $"
{GetNugetVersion()}"; } } } diff --git a/src/Interfaces/IAzureDevopsTrackerService.cs b/src/Interfaces/IAzureDevopsTrackerService.cs new file mode 100644 index 0000000..4e1b309 --- /dev/null +++ b/src/Interfaces/IAzureDevopsTrackerService.cs @@ -0,0 +1,18 @@ +using AzureDevopsTracker.Dtos; +using AzureDevopsTracker.Dtos.Create; +using AzureDevopsTracker.Dtos.Delete; +using AzureDevopsTracker.Dtos.Restore; +using AzureDevopsTracker.Dtos.Update; +using System.Threading.Tasks; + +namespace AzureDevopsTracker.Interfaces +{ + public interface IAzureDevopsTrackerService + { + Task Create(CreateWorkItemDto createDto, bool addWorkItemChange = true); + Task Update(UpdatedWorkItemDto updateDto); + Task Delete(DeleteWorkItemDto deleteDto); + Task Restore(RestoreWorkItemDto restoreDto); + Task GetByWorkItemId(string workItemId); + } +} \ No newline at end of file diff --git a/AzureDevopsTracker/Interfaces/IChangeLogService.cs b/src/Interfaces/IChangeLogService.cs similarity index 54% rename from AzureDevopsTracker/Interfaces/IChangeLogService.cs rename to src/Interfaces/IChangeLogService.cs index 6f21bf4..e303353 100644 --- a/AzureDevopsTracker/Interfaces/IChangeLogService.cs +++ b/src/Interfaces/IChangeLogService.cs @@ -5,8 +5,8 @@ namespace AzureDevopsTracker.Interfaces { public interface IChangeLogService { - int CountItemsForRelease(); - ChangeLog Release(); - string SendToMessengers(ChangeLog changeLog); + Task CountItemsForRelease(); + Task Release(); + Task SendToMessengers(ChangeLog changeLog); } } \ No newline at end of file diff --git a/AzureDevopsTracker/Interfaces/IWorkItemAdapter.cs b/src/Interfaces/IWorkItemAdapter.cs similarity index 52% rename from AzureDevopsTracker/Interfaces/IWorkItemAdapter.cs rename to src/Interfaces/IWorkItemAdapter.cs index 79f33b6..dc545e1 100644 --- a/AzureDevopsTracker/Interfaces/IWorkItemAdapter.cs +++ b/src/Interfaces/IWorkItemAdapter.cs @@ -1,4 +1,4 @@ -using AzureDevopsTracker.DTOs; +using AzureDevopsTracker.Dtos; using AzureDevopsTracker.Entities; using System.Collections.Generic; @@ -6,7 +6,7 @@ namespace AzureDevopsTracker.Interfaces { public interface IWorkItemAdapter { - WorkItemDTO ToWorkItemDTO(WorkItem workItem); - List ToWorkItemsDTO(List workItems); + WorkItemDto ToWorkItemDto(WorkItem workItem); + List ToWorkItemsDto(List workItems); } } \ No newline at end of file diff --git a/AzureDevopsTracker/Interfaces/Internals/IChangeLogItemRepository.cs b/src/Interfaces/Internals/IChangeLogItemRepository.cs similarity index 60% rename from AzureDevopsTracker/Interfaces/Internals/IChangeLogItemRepository.cs rename to src/Interfaces/Internals/IChangeLogItemRepository.cs index 0fe8145..eca1cec 100644 --- a/AzureDevopsTracker/Interfaces/Internals/IChangeLogItemRepository.cs +++ b/src/Interfaces/Internals/IChangeLogItemRepository.cs @@ -1,11 +1,12 @@ using AzureDevopsTracker.Entities; using System.Collections.Generic; +using System.Threading.Tasks; namespace AzureDevopsTracker.Interfaces.Internals { public interface IChangeLogItemRepository : IRepository { - int CountItemsForRelease(); - IEnumerable ListWaitingForRelease(); + Task CountItemsForRelease(); + Task> ListWaitingForRelease(); } } \ No newline at end of file diff --git a/AzureDevopsTracker/Interfaces/Internals/IChangeLogRepository.cs b/src/Interfaces/Internals/IChangeLogRepository.cs similarity index 68% rename from AzureDevopsTracker/Interfaces/Internals/IChangeLogRepository.cs rename to src/Interfaces/Internals/IChangeLogRepository.cs index d1d5e87..05b0dae 100644 --- a/AzureDevopsTracker/Interfaces/Internals/IChangeLogRepository.cs +++ b/src/Interfaces/Internals/IChangeLogRepository.cs @@ -1,10 +1,10 @@ using AzureDevopsTracker.Entities; -using System.Collections.Generic; +using System.Threading.Tasks; namespace AzureDevopsTracker.Interfaces.Internals { public interface IChangeLogRepository : IRepository { - int CountChangeLogsCreatedToday(); + Task CountChangeLogsCreatedToday(); } } \ No newline at end of file diff --git a/AzureDevopsTracker/Interfaces/Internals/IRepository.cs b/src/Interfaces/Internals/IRepository.cs similarity index 100% rename from AzureDevopsTracker/Interfaces/Internals/IRepository.cs rename to src/Interfaces/Internals/IRepository.cs diff --git a/AzureDevopsTracker/Interfaces/Internals/IWorkItemRepository.cs b/src/Interfaces/Internals/IWorkItemRepository.cs similarity index 100% rename from AzureDevopsTracker/Interfaces/Internals/IWorkItemRepository.cs rename to src/Interfaces/Internals/IWorkItemRepository.cs diff --git a/AzureDevopsTracker/Migrations/20210719163846_AzureDevopsStateTrackerInitial.Designer.cs b/src/Migrations/20210719163846_AzureDevopsStateTrackerInitial.Designer.cs similarity index 100% rename from AzureDevopsTracker/Migrations/20210719163846_AzureDevopsStateTrackerInitial.Designer.cs rename to src/Migrations/20210719163846_AzureDevopsStateTrackerInitial.Designer.cs diff --git a/AzureDevopsTracker/Migrations/20210719163846_AzureDevopsStateTrackerInitial.cs b/src/Migrations/20210719163846_AzureDevopsStateTrackerInitial.cs similarity index 99% rename from AzureDevopsTracker/Migrations/20210719163846_AzureDevopsStateTrackerInitial.cs rename to src/Migrations/20210719163846_AzureDevopsStateTrackerInitial.cs index 60017e3..704ad44 100644 --- a/AzureDevopsTracker/Migrations/20210719163846_AzureDevopsStateTrackerInitial.cs +++ b/src/Migrations/20210719163846_AzureDevopsStateTrackerInitial.cs @@ -1,6 +1,6 @@ -using System; -using AzureDevopsTracker.Data; +using AzureDevopsTracker.Data; using Microsoft.EntityFrameworkCore.Migrations; +using System; namespace AzureDevopsTracker.Migrations { diff --git a/AzureDevopsTracker/Migrations/20210720105645_FunctionToTimeInitial.Designer.cs b/src/Migrations/20210720105645_FunctionToTimeInitial.Designer.cs similarity index 100% rename from AzureDevopsTracker/Migrations/20210720105645_FunctionToTimeInitial.Designer.cs rename to src/Migrations/20210720105645_FunctionToTimeInitial.Designer.cs diff --git a/AzureDevopsTracker/Migrations/20210720105645_FunctionToTimeInitial.cs b/src/Migrations/20210720105645_FunctionToTimeInitial.cs similarity index 95% rename from AzureDevopsTracker/Migrations/20210720105645_FunctionToTimeInitial.cs rename to src/Migrations/20210720105645_FunctionToTimeInitial.cs index 51dce04..c2c0375 100644 --- a/AzureDevopsTracker/Migrations/20210720105645_FunctionToTimeInitial.cs +++ b/src/Migrations/20210720105645_FunctionToTimeInitial.cs @@ -1,5 +1,4 @@ -using AzureDevopsTracker.Data; -using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Migrations; namespace AzureDevopsTracker.Migrations { diff --git a/AzureDevopsTracker/Migrations/20210831213210_UpdatingColumns.Designer.cs b/src/Migrations/20210831213210_UpdatingColumns.Designer.cs similarity index 100% rename from AzureDevopsTracker/Migrations/20210831213210_UpdatingColumns.Designer.cs rename to src/Migrations/20210831213210_UpdatingColumns.Designer.cs diff --git a/AzureDevopsTracker/Migrations/20210831213210_UpdatingColumns.cs b/src/Migrations/20210831213210_UpdatingColumns.cs similarity index 100% rename from AzureDevopsTracker/Migrations/20210831213210_UpdatingColumns.cs rename to src/Migrations/20210831213210_UpdatingColumns.cs diff --git a/AzureDevopsTracker/Migrations/20210831213948_UpdatingCustomColumn.Designer.cs b/src/Migrations/20210831213948_UpdatingCustomColumn.Designer.cs similarity index 100% rename from AzureDevopsTracker/Migrations/20210831213948_UpdatingCustomColumn.Designer.cs rename to src/Migrations/20210831213948_UpdatingCustomColumn.Designer.cs diff --git a/AzureDevopsTracker/Migrations/20210831213948_UpdatingCustomColumn.cs b/src/Migrations/20210831213948_UpdatingCustomColumn.cs similarity index 100% rename from AzureDevopsTracker/Migrations/20210831213948_UpdatingCustomColumn.cs rename to src/Migrations/20210831213948_UpdatingCustomColumn.cs diff --git a/AzureDevopsTracker/Migrations/20211213213716_Adding_ChangeLog.Designer.cs b/src/Migrations/20211213213716_Adding_ChangeLog.Designer.cs similarity index 100% rename from AzureDevopsTracker/Migrations/20211213213716_Adding_ChangeLog.Designer.cs rename to src/Migrations/20211213213716_Adding_ChangeLog.Designer.cs diff --git a/AzureDevopsTracker/Migrations/20211213213716_Adding_ChangeLog.cs b/src/Migrations/20211213213716_Adding_ChangeLog.cs similarity index 98% rename from AzureDevopsTracker/Migrations/20211213213716_Adding_ChangeLog.cs rename to src/Migrations/20211213213716_Adding_ChangeLog.cs index c099cd9..58dc8bc 100644 --- a/AzureDevopsTracker/Migrations/20211213213716_Adding_ChangeLog.cs +++ b/src/Migrations/20211213213716_Adding_ChangeLog.cs @@ -1,6 +1,6 @@ -using System; -using AzureDevopsTracker.Data; +using AzureDevopsTracker.Data; using Microsoft.EntityFrameworkCore.Migrations; +using System; namespace AzureDevopsTracker.Migrations { diff --git a/AzureDevopsTracker/Migrations/20211220212121_AddField_Number.Designer.cs b/src/Migrations/20211220212121_AddField_Number.Designer.cs similarity index 100% rename from AzureDevopsTracker/Migrations/20211220212121_AddField_Number.Designer.cs rename to src/Migrations/20211220212121_AddField_Number.Designer.cs diff --git a/AzureDevopsTracker/Migrations/20211220212121_AddField_Number.cs b/src/Migrations/20211220212121_AddField_Number.cs similarity index 100% rename from AzureDevopsTracker/Migrations/20211220212121_AddField_Number.cs rename to src/Migrations/20211220212121_AddField_Number.cs diff --git a/AzureDevopsTracker/Migrations/20220607220158_WorkItem_AddDeleted.Designer.cs b/src/Migrations/20220607220158_WorkItem_AddDeleted.Designer.cs similarity index 100% rename from AzureDevopsTracker/Migrations/20220607220158_WorkItem_AddDeleted.Designer.cs rename to src/Migrations/20220607220158_WorkItem_AddDeleted.Designer.cs diff --git a/AzureDevopsTracker/Migrations/20220607220158_WorkItem_AddDeleted.cs b/src/Migrations/20220607220158_WorkItem_AddDeleted.cs similarity index 100% rename from AzureDevopsTracker/Migrations/20220607220158_WorkItem_AddDeleted.cs rename to src/Migrations/20220607220158_WorkItem_AddDeleted.cs diff --git a/AzureDevopsTracker/Migrations/20220621170433_CustomFields.Designer.cs b/src/Migrations/20220621170433_CustomFields.Designer.cs similarity index 100% rename from AzureDevopsTracker/Migrations/20220621170433_CustomFields.Designer.cs rename to src/Migrations/20220621170433_CustomFields.Designer.cs diff --git a/AzureDevopsTracker/Migrations/20220621170433_CustomFields.cs b/src/Migrations/20220621170433_CustomFields.cs similarity index 100% rename from AzureDevopsTracker/Migrations/20220621170433_CustomFields.cs rename to src/Migrations/20220621170433_CustomFields.cs diff --git a/AzureDevopsTracker/Migrations/AzureDevopsStateTrackerContextModelSnapshot.cs b/src/Migrations/AzureDevopsStateTrackerContextModelSnapshot.cs similarity index 100% rename from AzureDevopsTracker/Migrations/AzureDevopsStateTrackerContextModelSnapshot.cs rename to src/Migrations/AzureDevopsStateTrackerContextModelSnapshot.cs diff --git a/AzureDevopsTracker/Services/AzureDevopsTrackerService.cs b/src/Services/AzureDevopsTrackerService.cs similarity index 83% rename from AzureDevopsTracker/Services/AzureDevopsTrackerService.cs rename to src/Services/AzureDevopsTrackerService.cs index ce67781..5f40371 100644 --- a/AzureDevopsTracker/Services/AzureDevopsTrackerService.cs +++ b/src/Services/AzureDevopsTrackerService.cs @@ -1,8 +1,8 @@ -using AzureDevopsTracker.DTOs; -using AzureDevopsTracker.DTOs.Create; -using AzureDevopsTracker.DTOs.Delete; -using AzureDevopsTracker.DTOs.Restore; -using AzureDevopsTracker.DTOs.Update; +using AzureDevopsTracker.Dtos; +using AzureDevopsTracker.Dtos.Create; +using AzureDevopsTracker.Dtos.Delete; +using AzureDevopsTracker.Dtos.Restore; +using AzureDevopsTracker.Dtos.Update; using AzureDevopsTracker.Entities; using AzureDevopsTracker.Extensions; using AzureDevopsTracker.Helpers; @@ -36,7 +36,7 @@ public AzureDevopsTrackerService( _httpContextAccessor = httpContextAccessor; } - public async Task Create(CreateWorkItemDTO create, bool addWorkItemChange = true) + public async Task Create(CreateWorkItemDto create, bool addWorkItemChange = true) { var workItem = new WorkItem(create.Resource.Id); @@ -57,9 +57,9 @@ public async Task Create(CreateWorkItemDTO create, bool addWorkItemChange = true if (addWorkItemChange) AddWorkItemChange(workItem, create); - CheckWorkItemAvailableToChangeLog(workItem, create.Resource.Fields); + await CheckWorkItemAvailableToChangeLog(workItem, create.Resource.Fields); - AddCustomFields(workItem); + await AddCustomFields(workItem); await _workItemRepository.Add(workItem); await _workItemRepository.SaveChangesAsync(); @@ -67,9 +67,9 @@ public async Task Create(CreateWorkItemDTO create, bool addWorkItemChange = true public async Task Create(string workItemId, Fields fields) { - var createDto = new CreateWorkItemDTO() + var createDto = new CreateWorkItemDto() { - Resource = new DTOs.Resource() + Resource = new Dtos.Resource() { Fields = fields, Id = workItemId, @@ -79,9 +79,9 @@ public async Task Create(string workItemId, Fields fields) await Create(createDto, false); } - public async Task Update(UpdatedWorkItemDTO update) + public async Task Update(UpdatedWorkItemDto update) { - if (!_workItemRepository.Exist(update.Resource.WorkItemId).Result) + if (!await _workItemRepository.Exist(update.Resource.WorkItemId)) await Create(update.Resource.WorkItemId, update.Resource.Revision.Fields); var workItem = await _workItemRepository.GetByWorkItemId(update.Resource.WorkItemId); @@ -104,17 +104,17 @@ public async Task Update(UpdatedWorkItemDTO update) AddWorkItemChange(workItem, update); - CheckWorkItemAvailableToChangeLog(workItem, update.Resource.Revision.Fields); + await CheckWorkItemAvailableToChangeLog(workItem, update.Resource.Revision.Fields); - AddCustomFields(workItem); + await AddCustomFields(workItem); _workItemRepository.Update(workItem); await _workItemRepository.SaveChangesAsync(); } - public async Task Delete(DeleteWorkItemDTO delete) + public async Task Delete(DeleteWorkItemDto delete) { - if (!_workItemRepository.Exist(delete.Resource.Id).Result) + if (!await _workItemRepository.Exist(delete.Resource.Id)) await Create(delete.Resource.Id, delete.Resource.Fields); var workItem = await _workItemRepository.GetByWorkItemId(delete.Resource.Id); @@ -137,15 +137,15 @@ public async Task Delete(DeleteWorkItemDTO delete) delete.Resource.Fields.OriginalEstimate, delete.Resource.Fields.Activity); - AddCustomFields(workItem); + await AddCustomFields(workItem); _workItemRepository.Update(workItem); await _workItemRepository.SaveChangesAsync(); } - public async Task Restore(RestoreWorkItemDTO restore) + public async Task Restore(RestoreWorkItemDto restore) { - if (!_workItemRepository.Exist(restore.Resource.Id).Result) + if (!await _workItemRepository.Exist(restore.Resource.Id)) await Create(restore.Resource.Id, restore.Resource.Fields); var workItem = await _workItemRepository.GetByWorkItemId(restore.Resource.Id); @@ -168,27 +168,27 @@ public async Task Restore(RestoreWorkItemDTO restore) restore.Resource.Fields.OriginalEstimate, restore.Resource.Fields.Activity); - AddCustomFields(workItem); + await AddCustomFields(workItem); _workItemRepository.Update(workItem); await _workItemRepository.SaveChangesAsync(); } - public async Task GetByWorkItemId(string workItemId) + public async Task GetByWorkItemId(string workItemId) { var workItem = await _workItemRepository.GetByWorkItemId(workItemId); if (workItem is null) return null; - return _workItemAdapter.ToWorkItemDTO(workItem); + return _workItemAdapter.ToWorkItemDto(workItem); } #region Support Methods - public void AddCustomFields(WorkItem workItem) + public async Task AddCustomFields(WorkItem workItem) { try { - var jsonText = GetRequestBody(); + var jsonText = await GetRequestBody(); if (jsonText.IsNullOrEmpty()) return; @@ -202,7 +202,7 @@ public void AddCustomFields(WorkItem workItem) { } } - public string GetRequestBody() + public async Task GetRequestBody() { string corpo; var request = _httpContextAccessor?.HttpContext?.Request; @@ -212,13 +212,13 @@ public string GetRequestBody() leaveOpen: true)) { request.Body.Position = 0; - corpo = reader.ReadToEndAsync()?.Result; + corpo = await reader.ReadToEndAsync(); } return corpo; } - public WorkItemChange ToWorkItemChange( + public static WorkItemChange ToWorkItemChange( string workItemId, string changedBy, string iterationPath, DateTime newDate, string newState, string oldState = null, DateTime? oldDate = null) @@ -226,7 +226,7 @@ public WorkItemChange ToWorkItemChange( return new WorkItemChange(workItemId, changedBy.ExtractEmail(), iterationPath, newDate, newState, oldState, oldDate); } - public void AddWorkItemChange(WorkItem workItem, CreateWorkItemDTO create) + public static void AddWorkItemChange(WorkItem workItem, CreateWorkItemDto create) { var workItemChange = ToWorkItemChange(workItem.Id, create.Resource.Fields.ChangedBy, @@ -240,7 +240,7 @@ public void AddWorkItemChange(WorkItem workItem, CreateWorkItemDTO create) workItem.AddWorkItemChange(workItemChange); } - public void AddWorkItemChange(WorkItem workItem, UpdatedWorkItemDTO update) + public void AddWorkItemChange(WorkItem workItem, UpdatedWorkItemDto update) { if (update.Resource.Fields.State is null) return; if (update.Resource.Fields.StateChangeDate is null) return; @@ -275,13 +275,13 @@ public void RemoveTimeByStateFromDataBase(WorkItem workItem) _workItemRepository.RemoveAllTimeByState(workItem.TimeByStates.ToList()); } - public void CheckWorkItemAvailableToChangeLog(WorkItem workItem, Fields fields) + public async Task CheckWorkItemAvailableToChangeLog(WorkItem workItem, Fields fields) { if (workItem.CurrentStatus != "Closed" && workItem.LastStatus == "Closed" && workItem.ChangeLogItem is not null && !workItem.ChangeLogItem.WasReleased) - RemoveChangeLogItem(workItem); + await RemoveChangeLogItem(workItem); if (workItem.CurrentStatus != "Closed" || fields.ChangeLogDescription.IsNullOrEmpty()) @@ -293,7 +293,7 @@ workItem.ChangeLogItem is not null && workItem.ChangeLogItem.Update(workItem.Title, workItem.Type, fields.ChangeLogDescription); } - public bool CheckWorkItemChangeExists(WorkItem workItem, WorkItemChange newWorkItemChange) + public static bool CheckWorkItemChangeExists(WorkItem workItem, WorkItemChange newWorkItemChange) { return workItem.WorkItemsChanges.Any(x => x.NewDate == newWorkItemChange.NewDate && x.OldDate == newWorkItemChange.OldDate && @@ -304,18 +304,18 @@ public bool CheckWorkItemChangeExists(WorkItem workItem, WorkItemChange newWorkI x.TotalWorkedTime == newWorkItemChange.TotalWorkedTime); } - public ChangeLogItem ToChangeLogItem(WorkItem workItem, Fields fields) + public static ChangeLogItem ToChangeLogItem(WorkItem workItem, Fields fields) { return new ChangeLogItem(workItem.Id, workItem.Title, fields.ChangeLogDescription, workItem.Type); } - public void RemoveChangeLogItem(WorkItem workItem) + public async Task RemoveChangeLogItem(WorkItem workItem) { - var changeLogItem = _changeLogItemRepository.GetById(workItem.ChangeLogItem?.Id).Result; + var changeLogItem = await _changeLogItemRepository.GetById(workItem.ChangeLogItem?.Id); if (changeLogItem is not null) { _changeLogItemRepository.Delete(changeLogItem); - _changeLogItemRepository.SaveChangesAsync().Wait(); + await _changeLogItemRepository.SaveChangesAsync(); workItem.RemoveChangeLogItem(); } diff --git a/AzureDevopsTracker/Services/ChangeLogService.cs b/src/Services/ChangeLogService.cs similarity index 64% rename from AzureDevopsTracker/Services/ChangeLogService.cs rename to src/Services/ChangeLogService.cs index dce4a73..7e097f5 100644 --- a/AzureDevopsTracker/Services/ChangeLogService.cs +++ b/src/Services/ChangeLogService.cs @@ -5,6 +5,7 @@ using AzureDevopsTracker.Statics; using Microsoft.Extensions.Configuration; using System.Linq; +using System.Threading.Tasks; namespace AzureDevopsTracker.Services { @@ -18,7 +19,7 @@ public class ChangeLogService : IChangeLogService public ChangeLogService( IChangeLogItemRepository changeLogItemRepository, IChangeLogRepository changeLogRepository, - IConfiguration configuration, + IConfiguration configuration, MessageIntegration messageIntegration) { _changeLogItemRepository = changeLogItemRepository; @@ -27,37 +28,37 @@ public ChangeLogService( _messageIntegration = messageIntegration; } - public int CountItemsForRelease() + public async Task CountItemsForRelease() { - return _changeLogItemRepository.CountItemsForRelease(); + return await _changeLogItemRepository.CountItemsForRelease(); } - public ChangeLog Release() + public async Task Release() { - var changeLogItems = _changeLogItemRepository.ListWaitingForRelease(); + var changeLogItems = await _changeLogItemRepository.ListWaitingForRelease(); if (!changeLogItems.Any()) return null; - var changeLog = CreateChangeLog(); + var changeLog = await CreateChangeLog(); changeLog.AddChangeLogItems(changeLogItems); - _changeLogRepository.Add(changeLog).Wait(); - _changeLogRepository.SaveChangesAsync().Wait(); + await _changeLogRepository.Add(changeLog); + await _changeLogRepository.SaveChangesAsync(); return changeLog; } - public string SendToMessengers(ChangeLog changeLog) + public async Task SendToMessengers(ChangeLog changeLog) { - _messageIntegration.Send(changeLog); + await _messageIntegration.Send(changeLog); - return $"The ChangeLog { changeLog.Number } was released."; + return $"The ChangeLog {changeLog.Number} was released."; } - private ChangeLog CreateChangeLog() + private async Task CreateChangeLog() { if (string.IsNullOrEmpty(_configuration[ConfigurationStatics.ADT_CHANGELOG_VERSION])) { - var changeLogsQuantity = _changeLogRepository.CountChangeLogsCreatedToday(); + var changeLogsQuantity = await _changeLogRepository.CountChangeLogsCreatedToday(); return new ChangeLog(changeLogsQuantity + 1); } return new ChangeLog(_configuration[ConfigurationStatics.ADT_CHANGELOG_VERSION]); diff --git a/AzureDevopsTracker/Statics/ConfigurationStatics.cs b/src/Statics/ConfigurationStatics.cs similarity index 57% rename from AzureDevopsTracker/Statics/ConfigurationStatics.cs rename to src/Statics/ConfigurationStatics.cs index a39d50d..92f1a1b 100644 --- a/AzureDevopsTracker/Statics/ConfigurationStatics.cs +++ b/src/Statics/ConfigurationStatics.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace AzureDevopsTracker.Statics +namespace AzureDevopsTracker.Statics { internal class ConfigurationStatics { diff --git a/AzureDevopsTracker/Statics/WorkItemStatics.cs b/src/Statics/WorkItemStatics.cs similarity index 100% rename from AzureDevopsTracker/Statics/WorkItemStatics.cs rename to src/Statics/WorkItemStatics.cs diff --git a/AzureDevopsTracker/adt_icon.png b/src/adt_icon.png similarity index 100% rename from AzureDevopsTracker/adt_icon.png rename to src/adt_icon.png diff --git a/tests/AzureDevopsTracker.Tests/AzureDevopsTracker.Tests.csproj b/tests/AzureDevopsTracker.Tests/AzureDevopsTracker.Tests.csproj new file mode 100644 index 0000000..bb3bd0a --- /dev/null +++ b/tests/AzureDevopsTracker.Tests/AzureDevopsTracker.Tests.csproj @@ -0,0 +1,33 @@ + + + + net6.0 + enable + enable + + false + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/tests/AzureDevopsTracker.Tests/Entities/ChangeLogTests.cs b/tests/AzureDevopsTracker.Tests/Entities/ChangeLogTests.cs new file mode 100644 index 0000000..b8488ae --- /dev/null +++ b/tests/AzureDevopsTracker.Tests/Entities/ChangeLogTests.cs @@ -0,0 +1,105 @@ +namespace AzureDevopsTracker.Tests.Entities +{ + public class ChangeLogTests + { + [Theory(DisplayName = "ChangeLog - New with NewRevision")] + [InlineData(12345)] + [InlineData(65489)] + public void ChangeLog_NewWithRevision(int newRevision) + { + var changeLog = new ChangeLog(newRevision); + + changeLog.Id.Should().NotBeNullOrEmpty(); + changeLog.Revision.Should().Be(newRevision); + changeLog.Number.Should().Be($"{changeLog.CreatedAt:yyyyMMdd}.{newRevision}"); + changeLog.ChangeLogItems.Should().BeEmpty(); + } + + [Theory(DisplayName = "ChangeLog - New with Number")] + [InlineData("12345")] + [InlineData("abcde")] + public void ChangeLog_NewWithNumber(string number) + { + var changeLog = new ChangeLog(number); + + changeLog.Id.Should().NotBeNullOrEmpty(); + changeLog.Number.Should().Be(number); + changeLog.Revision.Should().Be(0); + changeLog.ChangeLogItems.Should().BeEmpty(); + } + + [Fact(DisplayName = "ChangeLog - SetResponse")] + public void ChangeLog_SetResponse() + { + var newResponse = "new response"; + var changeLog = new ChangeLog("abc"); + + changeLog.SetResponse(newResponse); + + changeLog.Response.Should().Be(newResponse); + } + + [Fact(DisplayName = "ChangeLog - ClearResponse")] + public void ChangeLog_ClearResponse() + { + var newResponse = "new response"; + var changeLog = new ChangeLog("abc"); + changeLog.SetResponse(newResponse); + + changeLog.ClearResponse(); + + changeLog.Response.Should().BeEmpty(); + } + + [Theory(DisplayName = "ChangeLog - AddChangeLogItem")] + [InlineData("123", "test", "just a test", "bug", true)] + [InlineData("654", "test", "just a test", "feature", false)] + public void ChangeLog_CheckChangeLogItem(string workItemId, string title, string description, string type, bool exist) + { + var changeLog = new ChangeLog("abc"); + changeLog.AddChangeLogItem(new ChangeLogItem("123", title, description, type)); + + var changeLogItem = new ChangeLogItem(workItemId, title, description, type); + changeLog.AddChangeLogItem(changeLogItem); + + if (exist) + changeLog.ChangeLogItems.Should().NotContain(changeLogItem); + else + changeLog.ChangeLogItems.Should().Contain(changeLogItem); + } + + [Fact(DisplayName = "ChangeLog - AddChangeLogItem should throw exception")] + public void ChangeLog_AddChangeLogItem_ThrowException() + { + var changeLog = new ChangeLog("abc"); + var mensagemEsperada = Assert.Throws(() => changeLog.AddChangeLogItem(null)).Message; + + mensagemEsperada.Should().Be("ChangeLogItem is required"); + } + + [Fact(DisplayName = "ChangeLog - AddChangeLogItems")] + public void ChangeLog_AddChangeLogItems() + { + var changeLog = new ChangeLog("abc"); + var changeLogItems = new List + { + new ChangeLogItem("123", "test", "just a test", "bug"), + new ChangeLogItem("654", "test", "just a test", "feature") + }; + + changeLog.AddChangeLogItems(changeLogItems); + + changeLog.ChangeLogItems.Should().Contain(changeLogItems); + } + + [Fact(DisplayName = "ChangeLog - AddChangeLogItems should throw exception")] + public void ChangeLog_AddChangeLogItems_ThrowException() + { + var changeLog = new ChangeLog("abc"); + + var mensagemEsperada = Assert.Throws(() => changeLog.AddChangeLogItems(null)).Message; + + mensagemEsperada.Should().Be("ChangeLogItems is required"); + } + } +} \ No newline at end of file diff --git a/tests/AzureDevopsTracker.Tests/Entities/TimeByStateTests.cs b/tests/AzureDevopsTracker.Tests/Entities/TimeByStateTests.cs new file mode 100644 index 0000000..6980acd --- /dev/null +++ b/tests/AzureDevopsTracker.Tests/Entities/TimeByStateTests.cs @@ -0,0 +1,36 @@ +namespace AzureDevopsTracker.Tests.Entities +{ + public class TimeByStateTests + { + [Fact(DisplayName = "TimeByState - New")] + public void TimeByState_New() + { + var workItemId = "123"; + var state = "new"; + var totalTime = new TimeSpan(1, 0, 3); + var totalWorkedTime = new TimeSpan(2, 3, 40); + var timeByState = new TimeByState(workItemId, state, totalTime, totalWorkedTime); + + timeByState.Id.Should().NotBeNullOrEmpty(); + timeByState.WorkItemId.Should().Be(workItemId); + timeByState.State.Should().Be(state); + timeByState.TotalTime.Should().Be(totalTime.TotalSeconds); + timeByState.TotalWorkedTime.Should().Be(totalWorkedTime.TotalSeconds); + } + + [Theory(DisplayName = "TimeByState - Validate")] + [InlineData("", "new", "WorkItemId is required")] + [InlineData(null, "", "WorkItemId is required")] + [InlineData("123", "", "State is required")] + [InlineData("123", null, "State is required")] + public void TimeByState_Update(string workItemId, string state, string throwMessage) + { + var totalTime = new TimeSpan(1, 0, 3); + var totalWorkedTime = new TimeSpan(2, 3, 40); + + var mensagemEsperada = Assert.Throws(() => new TimeByState(workItemId, state, totalTime, totalWorkedTime)).Message; + + mensagemEsperada.Should().Be(throwMessage); + } + } +} \ No newline at end of file diff --git a/tests/AzureDevopsTracker.Tests/Entities/WorkItemCustomFieldTests.cs b/tests/AzureDevopsTracker.Tests/Entities/WorkItemCustomFieldTests.cs new file mode 100644 index 0000000..25b2903 --- /dev/null +++ b/tests/AzureDevopsTracker.Tests/Entities/WorkItemCustomFieldTests.cs @@ -0,0 +1,31 @@ +namespace AzureDevopsTracker.Tests.Entities +{ + public class WorkItemCustomFieldTests + { + [Theory(DisplayName = "CustomField - New")] + [InlineData("12345", "key", "value")] + [InlineData("65489", "key1", "value")] + [InlineData("test", "key", "value1")] + public void CustomField_New(string workItemId, string key, string value) + { + var customField = new WorkItemCustomField(workItemId, key, value); + + customField.WorkItemId.Should().Be(workItemId); + customField.Key.Should().Be(key); + customField.Value.Should().Be(value); + } + + [Theory(DisplayName = "CustomField - Update")] + [InlineData("value")] + [InlineData("new_value")] + [InlineData("value1")] + public void CustomField_Update(string value) + { + var customField = new WorkItemCustomField(Guid.NewGuid().ToString(), "key", ""); + + customField.Update(value); + + customField.Value.Should().Be(value); + } + } +} \ No newline at end of file diff --git a/tests/AzureDevopsTracker.Tests/Usings.cs b/tests/AzureDevopsTracker.Tests/Usings.cs new file mode 100644 index 0000000..9d6c592 --- /dev/null +++ b/tests/AzureDevopsTracker.Tests/Usings.cs @@ -0,0 +1,3 @@ +global using AzureDevopsTracker.Entities; +global using FluentAssertions; +global using Xunit;