Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions AzureDevopsTracker/Adapters/WorkItemAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ internal class WorkItemAdapter : IWorkItemAdapter
{
public WorkItemDTO ToWorkItemDTO(WorkItem workItem)
{
if (workItem == null) return null;
if (workItem is null) return null;

return new WorkItemDTO()
{
Expand All @@ -31,7 +31,7 @@ public WorkItemDTO ToWorkItemDTO(WorkItem workItem)
OriginalEstimate = workItem.OriginalEstimate,
WorkItemParentId = workItem.WorkItemParentId,
Activity = workItem.Activity,
Tags = workItem.Tags == null ? new List<string>() : workItem.Tags.Split(';').ToList(),
Tags = workItem.Tags is null ? new List<string>() : workItem.Tags.Split(';').ToList(),
WorkItemsChangesDTO = ToWorkItemsChangeDTO(workItem.WorkItemsChanges.OrderBy(x => x.CreatedAt).ToList()),
TimesByStateDTO = ToTimeByStatesDTO(workItem.CalculateTotalTimeByState().ToList()),
};
Expand All @@ -41,7 +41,7 @@ public List<WorkItemDTO> ToWorkItemsDTO(List<WorkItem> workItems)
{
var workItemsDTO = new List<WorkItemDTO>();

if (workItems == null) return workItemsDTO;
if (workItems is null) return workItemsDTO;

workItems.ForEach(
workItem =>
Expand All @@ -53,7 +53,7 @@ public List<WorkItemDTO> ToWorkItemsDTO(List<WorkItem> workItems)

public WorkItemChangeDTO ToWorkItemChangeDTO(WorkItemChange workIteChange)
{
if (workIteChange == null) return null;
if (workIteChange is null) return null;

return new WorkItemChangeDTO()
{
Expand All @@ -69,20 +69,20 @@ public List<WorkItemChangeDTO> ToWorkItemsChangeDTO(List<WorkItemChange> workIte
{
var workItemsChangeDTO = new List<WorkItemChangeDTO>();

if (workItemsChanges == null) return workItemsChangeDTO;
if (workItemsChanges is null) return workItemsChangeDTO;

workItemsChanges.ForEach(
workItemsChange =>
workItemsChangeDTO.Add(ToWorkItemChangeDTO(workItemsChange)));

return workItemsChangeDTO
.Where(w => w != null)
.Where(w => w is not null)
.ToList();
}

public TimeByStateDTO ToTimeByStateDTO(TimeByState workItemStatusTime)
{
if (workItemStatusTime == null) return null;
if (workItemStatusTime is null) return null;

return new TimeByStateDTO()
{
Expand All @@ -97,14 +97,14 @@ public List<TimeByStateDTO> ToTimeByStatesDTO(List<TimeByState> workItemStatusTi
{
var workItemStatusTimeDTO = new List<TimeByStateDTO>();

if (workItemStatusTimes == null) return workItemStatusTimeDTO;
if (workItemStatusTimes is null) return workItemStatusTimeDTO;

workItemStatusTimes.ForEach(
workItemStatusTime =>
workItemStatusTimeDTO.Add(ToTimeByStateDTO(workItemStatusTime)));

return workItemStatusTimeDTO
.Where(w => w != null)
.Where(w => w is not null)
.ToList();
}
}
Expand Down
2 changes: 1 addition & 1 deletion AzureDevopsTracker/Data/DataBaseConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public DataBaseConfig(string connectionsString, string schemaName = "dbo", TimeZ
if (connectionsString.IsNullOrEmpty())
throw new ArgumentException("The ConnectionsString is required");

if (timeZoneInfo == null)
if (timeZoneInfo is null)
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("E. South America Standard Time");
else
Expand Down
3 changes: 3 additions & 0 deletions AzureDevopsTracker/Data/WorkItemRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public async Task<WorkItem> GetByWorkItemId(string workItemId)
.Include(x => x.WorkItemsChanges)
.Include(x => x.TimeByStates)
.Include(x => x.ChangeLogItem)
.Include(x => x.CustomFields)
.FirstOrDefaultAsync(x => x.Id == workItemId);
}

Expand All @@ -27,6 +28,7 @@ public async Task<IEnumerable<WorkItem>> ListByWorkItemId(IEnumerable<string> wo
.Include(x => x.WorkItemsChanges)
.Include(x => x.TimeByStates)
.Include(x => x.ChangeLogItem)
.Include(x => x.CustomFields)
.Where(x => workItemsId.Contains(x.Id))
.ToListAsync();
}
Expand All @@ -37,6 +39,7 @@ public async Task<IEnumerable<WorkItem>> ListByIterationPath(string iterationPat
.Include(x => x.WorkItemsChanges)
.Include(x => x.TimeByStates)
.Include(x => x.ChangeLogItem)
.Include(x => x.CustomFields)
.Where(x => x.IterationPath == iterationPath)
.ToListAsync();
}
Expand Down
4 changes: 2 additions & 2 deletions AzureDevopsTracker/Entities/ChangeLog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public void ClearResponse()

public void AddChangeLogItem(ChangeLogItem changeLogItem)
{
if (changeLogItem == null)
if (changeLogItem is null)
throw new Exception("ChangeLogItem is required");

if (CheckChangeLogItem(changeLogItem))
Expand All @@ -49,7 +49,7 @@ public void AddChangeLogItem(ChangeLogItem changeLogItem)

public void AddChangeLogItems(IEnumerable<ChangeLogItem> changeLogItems)
{
if (changeLogItems == null)
if (changeLogItems is null)
throw new Exception("ChangeLogItems is required");

foreach (var changeLogItem in changeLogItems)
Expand Down
2 changes: 1 addition & 1 deletion AzureDevopsTracker/Entities/Entity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public abstract class Entity
public DateTime CreatedAt { get; private set; }
public Entity(string id)
{
Id = id;
Id = id ?? Guid.NewGuid().ToString();
CreatedAt = DateTime.UtcNow;
}

Expand Down
74 changes: 56 additions & 18 deletions AzureDevopsTracker/Entities/WorkItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,21 @@ public class WorkItem : Entity

public ChangeLogItem ChangeLogItem { get; private set; }

private readonly List<WorkItemChange> _workItemsChanges;
private readonly List<WorkItemChange> _workItemsChanges = new List<WorkItemChange>();
public IReadOnlyCollection<WorkItemChange> WorkItemsChanges => _workItemsChanges;

private readonly List<TimeByState> _timeByState;
private readonly List<TimeByState> _timeByState = new List<TimeByState>();
public IReadOnlyCollection<TimeByState> TimeByStates => _timeByState;

private readonly List<WorkItemCustomField> _workItemCustomFields = new List<WorkItemCustomField>();
public IReadOnlyCollection<WorkItemCustomField> CustomFields => _workItemCustomFields;
public string CurrentStatus => _workItemsChanges?.OrderBy(x => x.CreatedAt)?.LastOrDefault()?.NewState;
public string LastStatus => _workItemsChanges?.OrderBy(x => x.CreatedAt)?.ToList()?.Skip(1)?.LastOrDefault()?.OldState;

private WorkItem()
{
_workItemsChanges = new List<WorkItemChange>();
_timeByState = new List<TimeByState>();
}
private WorkItem() { }

public WorkItem(string workItemId) : base(workItemId)
{
_workItemsChanges = new List<WorkItemChange>();
_timeByState = new List<TimeByState>();
Validate();
}

Expand Down Expand Up @@ -87,34 +84,75 @@ public void Delete()
public void Validate()
{
if (Id.IsNullOrEmpty())
throw new Exception("WorkItemId is required");
throw new ArgumentException("WorkItemId is required");
}

public void AddWorkItemChange(WorkItemChange workItemChange)
{
if (workItemChange == null)
throw new Exception("WorkItemChange is null");
if (workItemChange is null)
throw new ArgumentException("WorkItemChange is null");

_workItemsChanges.Add(workItemChange);
}

public void AddTimeByState(TimeByState timeByState)
{
if (timeByState == null)
throw new Exception("TimeByState is null");
if (timeByState is null)
throw new ArgumentException("TimeByState is null");

_timeByState.Add(timeByState);
}

public void AddTimesByState(IEnumerable<TimeByState> timesByState)
{
if (!timesByState.Any())
if (timesByState is not null && !timesByState.Any())
return;

foreach (var timeByState in timesByState)
AddTimeByState(timeByState);
}

public void AddCustomField(WorkItemCustomField customField)
{
if (customField is null)
throw new ArgumentException("CustomField is null");

if (customField.WorkItemId.IsNullOrEmpty())
customField.LinkWorkItem(Id);

_workItemCustomFields.Add(customField);
}

public void AddCustomFields(IEnumerable<WorkItemCustomField> customFields)
{
if (customFields is not null && !customFields.Any())
return;

foreach (var customField in customFields)
AddCustomField(customField);
}

public void UpdateCustomFields(IEnumerable<WorkItemCustomField> newCustomFields)
{
if (newCustomFields is not null && !newCustomFields.Any())
return;

var customFieldsToAdd = newCustomFields.Where(x => !_workItemCustomFields.Select(x => x.Key).Contains(x.Key));
AddCustomFields(customFieldsToAdd);

var customFieldsToUpdate = newCustomFields.Where(x => _workItemCustomFields.Select(x => x.Key).Contains(x.Key));
foreach (var newCustomField in customFieldsToUpdate)
{
var customField = _workItemCustomFields.FirstOrDefault(x => x.Key == newCustomField.Key);
if (customField is null) continue;

if (customField.WorkItemId.IsNullOrEmpty())
customField.LinkWorkItem(Id);

customField.Update(customField.Value);
}
}

public void ClearTimesByState()
{
_timeByState.Clear();
Expand All @@ -127,8 +165,8 @@ public void RemoveChangeLogItem()

public void VinculateChangeLogItem(ChangeLogItem changeLogItem)
{
if (changeLogItem == null)
throw new Exception("ChangeLogItem is null");
if (changeLogItem is null)
throw new ArgumentException("ChangeLogItem is null");

ChangeLogItem = changeLogItem;
}
Expand All @@ -139,7 +177,7 @@ public IEnumerable<TimeByState> CalculateTotalTimeByState()
if (!_workItemsChanges.Any())
return timesByStateList;

foreach (var workItemChange in _workItemsChanges.OrderBy(x => x.CreatedAt).GroupBy(x => x.OldState).Where(x => x.Key != 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;
Expand Down
2 changes: 1 addition & 1 deletion AzureDevopsTracker/Entities/WorkItemChange.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public void Validate()

public TimeSpan CalculateTotalTime()
{
return OldDate == null ? TimeSpan.Zero : NewDate.ToDateTimeFromTimeZoneInfo() - OldDate.Value.ToDateTimeFromTimeZoneInfo();
return OldDate is null ? TimeSpan.Zero : NewDate.ToDateTimeFromTimeZoneInfo() - OldDate.Value.ToDateTimeFromTimeZoneInfo();
}

public double CalculateTotalWorkedTime()
Expand Down
34 changes: 34 additions & 0 deletions AzureDevopsTracker/Entities/WorkItemCustomField.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using AzureDevopsTracker.Extensions;
using System;

namespace AzureDevopsTracker.Entities
{
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)
{
WorkItemId = workItemId;
Key = key;
Value = value;
}

public void LinkWorkItem(string workItemId)
{
if (workItemId.IsNullOrEmpty())
throw new ArgumentException("WorkItemId is required");

WorkItemId = workItemId;
}

public void Update(string value)
{
Value = value;
}
}
}
46 changes: 46 additions & 0 deletions AzureDevopsTracker/Helpers/ReadJsonHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using AzureDevopsTracker.Entities;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Linq;

namespace AzureDevopsTracker.Helpers
{
public static class ReadJsonHelper
{
public static IEnumerable<WorkItemCustomField> ReadJson(string workItemId, string jsonTexto)
{
try
{
var workItemCustomFields = new List<WorkItemCustomField>();
foreach (KeyValuePair<string, JToken> element in JObject.Parse(jsonTexto))
{
if (element.Value is JObject)
ReadJsonObject(workItemId, workItemCustomFields, (JObject)element.Value);
else
GetWorkItemCustomField(workItemCustomFields, workItemId, element.Key, element.Value.ToString());
}

return workItemCustomFields;
}
catch
{
return Enumerable.Empty<WorkItemCustomField>();
}
}

private static void ReadJsonObject(string workItemId, List<WorkItemCustomField> workItemCustomFields, JObject objeto)
{
foreach (KeyValuePair<string, JToken> item in objeto)
if (item.Value is JObject)
ReadJsonObject(workItemId, workItemCustomFields, (JObject)item.Value);
else
GetWorkItemCustomField(workItemCustomFields, workItemId, item.Key, item.Value.ToString());
}

private static void GetWorkItemCustomField(List<WorkItemCustomField> workItemCustomFields, string workItemId, string key, string value)
{
if (key is not null && !key.ToLower().Contains("custom")) return;
workItemCustomFields.Add(new WorkItemCustomField(workItemId, key, value));
}
}
}
2 changes: 1 addition & 1 deletion AzureDevopsTracker/Integrations/MessageFacade.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public void Send(ChangeLog changeLog)
using var scope = _serviceScopeFactory.CreateScope();

var messageIntegration = scope.ServiceProvider.GetService<MessageIntegration>();
if (messageIntegration == null) throw new Exception("Configure the MessageConfig in Startup to send changelog messages");
if (messageIntegration is null) throw new Exception("Configure the MessageConfig in Startup to send changelog messages");

messageIntegration.Send(changeLog);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ internal override void Send(ChangeLog changeLog)

private string GetText(ChangeLog changeLog)
{
if (changeLog == null || !changeLog.ChangeLogItems.Any()) return string.Empty;
if (changeLog is null || !changeLog.ChangeLogItems.Any()) return string.Empty;

StringBuilder text = new();
text.AppendLine(GetWorkItemsDescriptionSection("Features", changeLog.ChangeLogItems.Where(x => x.WorkItemType != WorkItemStatics.WORKITEM_TYPE_BUG)));
Expand Down
3 changes: 3 additions & 0 deletions AzureDevopsTracker/Interfaces/IAzureDevopsTrackerService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,8 @@ public interface IAzureDevopsTrackerService
Task Delete(DeleteWorkItemDTO deleteDto);
Task Restore(RestoreWorkItemDTO restoreDto);
Task<WorkItemDTO> GetByWorkItemId(string workItemId);

Task Create(string jsonText, bool addWorkItemChange = true);
Task Update(string jsonText);
}
}
Loading