Skip to content

Commit 0745d24

Browse files
Merge branch 'version-5_add_custom_fields' of https://github.com/typinghard/azure-devops-tracker into feature/43
2 parents 30876ee + 6086baa commit 0745d24

File tree

13 files changed

+215
-37
lines changed

13 files changed

+215
-37
lines changed

AzureDevopsTracker/Adapters/WorkItemAdapter.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ internal class WorkItemAdapter : IWorkItemAdapter
1212
{
1313
public WorkItemDTO ToWorkItemDTO(WorkItem workItem)
1414
{
15-
if (workItem == null) return null;
15+
if (workItem is null) return null;
1616

1717
return new WorkItemDTO()
1818
{
@@ -31,7 +31,7 @@ public WorkItemDTO ToWorkItemDTO(WorkItem workItem)
3131
OriginalEstimate = workItem.OriginalEstimate,
3232
WorkItemParentId = workItem.WorkItemParentId,
3333
Activity = workItem.Activity,
34-
Tags = workItem.Tags == null ? new List<string>() : workItem.Tags.Split(';').ToList(),
34+
Tags = workItem.Tags is null ? new List<string>() : workItem.Tags.Split(';').ToList(),
3535
WorkItemsChangesDTO = ToWorkItemsChangeDTO(workItem.WorkItemsChanges.OrderBy(x => x.CreatedAt).ToList()),
3636
TimesByStateDTO = ToTimeByStatesDTO(workItem.CalculateTotalTimeByState().ToList()),
3737
};
@@ -41,7 +41,7 @@ public List<WorkItemDTO> ToWorkItemsDTO(List<WorkItem> workItems)
4141
{
4242
var workItemsDTO = new List<WorkItemDTO>();
4343

44-
if (workItems == null) return workItemsDTO;
44+
if (workItems is null) return workItemsDTO;
4545

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

5454
public WorkItemChangeDTO ToWorkItemChangeDTO(WorkItemChange workIteChange)
5555
{
56-
if (workIteChange == null) return null;
56+
if (workIteChange is null) return null;
5757

5858
return new WorkItemChangeDTO()
5959
{
@@ -69,20 +69,20 @@ public List<WorkItemChangeDTO> ToWorkItemsChangeDTO(List<WorkItemChange> workIte
6969
{
7070
var workItemsChangeDTO = new List<WorkItemChangeDTO>();
7171

72-
if (workItemsChanges == null) return workItemsChangeDTO;
72+
if (workItemsChanges is null) return workItemsChangeDTO;
7373

7474
workItemsChanges.ForEach(
7575
workItemsChange =>
7676
workItemsChangeDTO.Add(ToWorkItemChangeDTO(workItemsChange)));
7777

7878
return workItemsChangeDTO
79-
.Where(w => w != null)
79+
.Where(w => w is not null)
8080
.ToList();
8181
}
8282

8383
public TimeByStateDTO ToTimeByStateDTO(TimeByState workItemStatusTime)
8484
{
85-
if (workItemStatusTime == null) return null;
85+
if (workItemStatusTime is null) return null;
8686

8787
return new TimeByStateDTO()
8888
{
@@ -97,14 +97,14 @@ public List<TimeByStateDTO> ToTimeByStatesDTO(List<TimeByState> workItemStatusTi
9797
{
9898
var workItemStatusTimeDTO = new List<TimeByStateDTO>();
9999

100-
if (workItemStatusTimes == null) return workItemStatusTimeDTO;
100+
if (workItemStatusTimes is null) return workItemStatusTimeDTO;
101101

102102
workItemStatusTimes.ForEach(
103103
workItemStatusTime =>
104104
workItemStatusTimeDTO.Add(ToTimeByStateDTO(workItemStatusTime)));
105105

106106
return workItemStatusTimeDTO
107-
.Where(w => w != null)
107+
.Where(w => w is not null)
108108
.ToList();
109109
}
110110
}

AzureDevopsTracker/Data/DataBaseConfig.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public DataBaseConfig(string connectionsString, string schemaName = "dbo", TimeZ
1111
if (connectionsString.IsNullOrEmpty())
1212
throw new ArgumentException("The ConnectionsString is required");
1313

14-
if (timeZoneInfo == null)
14+
if (timeZoneInfo is null)
1515
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
1616
timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("E. South America Standard Time");
1717
else

AzureDevopsTracker/Data/WorkItemRepository.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public async Task<WorkItem> GetByWorkItemId(string workItemId)
1818
.Include(x => x.WorkItemsChanges)
1919
.Include(x => x.TimeByStates)
2020
.Include(x => x.ChangeLogItem)
21+
.Include(x => x.CustomFields)
2122
.FirstOrDefaultAsync(x => x.Id == workItemId);
2223
}
2324

@@ -27,6 +28,7 @@ public async Task<IEnumerable<WorkItem>> ListByWorkItemId(IEnumerable<string> wo
2728
.Include(x => x.WorkItemsChanges)
2829
.Include(x => x.TimeByStates)
2930
.Include(x => x.ChangeLogItem)
31+
.Include(x => x.CustomFields)
3032
.Where(x => workItemsId.Contains(x.Id))
3133
.ToListAsync();
3234
}
@@ -37,6 +39,7 @@ public async Task<IEnumerable<WorkItem>> ListByIterationPath(string iterationPat
3739
.Include(x => x.WorkItemsChanges)
3840
.Include(x => x.TimeByStates)
3941
.Include(x => x.ChangeLogItem)
42+
.Include(x => x.CustomFields)
4043
.Where(x => x.IterationPath == iterationPath)
4144
.ToListAsync();
4245
}

AzureDevopsTracker/Entities/ChangeLog.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public void ClearResponse()
3737

3838
public void AddChangeLogItem(ChangeLogItem changeLogItem)
3939
{
40-
if (changeLogItem == null)
40+
if (changeLogItem is null)
4141
throw new Exception("ChangeLogItem is required");
4242

4343
if (CheckChangeLogItem(changeLogItem))
@@ -49,7 +49,7 @@ public void AddChangeLogItem(ChangeLogItem changeLogItem)
4949

5050
public void AddChangeLogItems(IEnumerable<ChangeLogItem> changeLogItems)
5151
{
52-
if (changeLogItems == null)
52+
if (changeLogItems is null)
5353
throw new Exception("ChangeLogItems is required");
5454

5555
foreach (var changeLogItem in changeLogItems)

AzureDevopsTracker/Entities/Entity.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ public abstract class Entity
88
public DateTime CreatedAt { get; private set; }
99
public Entity(string id)
1010
{
11-
Id = id;
11+
Id = id ?? Guid.NewGuid().ToString();
1212
CreatedAt = DateTime.UtcNow;
1313
}
1414

AzureDevopsTracker/Entities/WorkItem.cs

Lines changed: 56 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,24 +25,21 @@ public class WorkItem : Entity
2525

2626
public ChangeLogItem ChangeLogItem { get; private set; }
2727

28-
private readonly List<WorkItemChange> _workItemsChanges;
28+
private readonly List<WorkItemChange> _workItemsChanges = new List<WorkItemChange>();
2929
public IReadOnlyCollection<WorkItemChange> WorkItemsChanges => _workItemsChanges;
3030

31-
private readonly List<TimeByState> _timeByState;
31+
private readonly List<TimeByState> _timeByState = new List<TimeByState>();
3232
public IReadOnlyCollection<TimeByState> TimeByStates => _timeByState;
33+
34+
private readonly List<WorkItemCustomField> _workItemCustomFields = new List<WorkItemCustomField>();
35+
public IReadOnlyCollection<WorkItemCustomField> CustomFields => _workItemCustomFields;
3336
public string CurrentStatus => _workItemsChanges?.OrderBy(x => x.CreatedAt)?.LastOrDefault()?.NewState;
3437
public string LastStatus => _workItemsChanges?.OrderBy(x => x.CreatedAt)?.ToList()?.Skip(1)?.LastOrDefault()?.OldState;
3538

36-
private WorkItem()
37-
{
38-
_workItemsChanges = new List<WorkItemChange>();
39-
_timeByState = new List<TimeByState>();
40-
}
39+
private WorkItem() { }
4140

4241
public WorkItem(string workItemId) : base(workItemId)
4342
{
44-
_workItemsChanges = new List<WorkItemChange>();
45-
_timeByState = new List<TimeByState>();
4643
Validate();
4744
}
4845

@@ -87,34 +84,75 @@ public void Delete()
8784
public void Validate()
8885
{
8986
if (Id.IsNullOrEmpty())
90-
throw new Exception("WorkItemId is required");
87+
throw new ArgumentException("WorkItemId is required");
9188
}
9289

9390
public void AddWorkItemChange(WorkItemChange workItemChange)
9491
{
95-
if (workItemChange == null)
96-
throw new Exception("WorkItemChange is null");
92+
if (workItemChange is null)
93+
throw new ArgumentException("WorkItemChange is null");
9794

9895
_workItemsChanges.Add(workItemChange);
9996
}
10097

10198
public void AddTimeByState(TimeByState timeByState)
10299
{
103-
if (timeByState == null)
104-
throw new Exception("TimeByState is null");
100+
if (timeByState is null)
101+
throw new ArgumentException("TimeByState is null");
105102

106103
_timeByState.Add(timeByState);
107104
}
108105

109106
public void AddTimesByState(IEnumerable<TimeByState> timesByState)
110107
{
111-
if (!timesByState.Any())
108+
if (timesByState is not null && !timesByState.Any())
112109
return;
113110

114111
foreach (var timeByState in timesByState)
115112
AddTimeByState(timeByState);
116113
}
117114

115+
public void AddCustomField(WorkItemCustomField customField)
116+
{
117+
if (customField is null)
118+
throw new ArgumentException("CustomField is null");
119+
120+
if (customField.WorkItemId.IsNullOrEmpty())
121+
customField.LinkWorkItem(Id);
122+
123+
_workItemCustomFields.Add(customField);
124+
}
125+
126+
public void AddCustomFields(IEnumerable<WorkItemCustomField> customFields)
127+
{
128+
if (customFields is not null && !customFields.Any())
129+
return;
130+
131+
foreach (var customField in customFields)
132+
AddCustomField(customField);
133+
}
134+
135+
public void UpdateCustomFields(IEnumerable<WorkItemCustomField> newCustomFields)
136+
{
137+
if (newCustomFields is not null && !newCustomFields.Any())
138+
return;
139+
140+
var customFieldsToAdd = newCustomFields.Where(x => !_workItemCustomFields.Select(x => x.Key).Contains(x.Key));
141+
AddCustomFields(customFieldsToAdd);
142+
143+
var customFieldsToUpdate = newCustomFields.Where(x => _workItemCustomFields.Select(x => x.Key).Contains(x.Key));
144+
foreach (var newCustomField in customFieldsToUpdate)
145+
{
146+
var customField = _workItemCustomFields.FirstOrDefault(x => x.Key == newCustomField.Key);
147+
if (customField is null) continue;
148+
149+
if (customField.WorkItemId.IsNullOrEmpty())
150+
customField.LinkWorkItem(Id);
151+
152+
customField.Update(customField.Value);
153+
}
154+
}
155+
118156
public void ClearTimesByState()
119157
{
120158
_timeByState.Clear();
@@ -127,8 +165,8 @@ public void RemoveChangeLogItem()
127165

128166
public void VinculateChangeLogItem(ChangeLogItem changeLogItem)
129167
{
130-
if (changeLogItem == null)
131-
throw new Exception("ChangeLogItem is null");
168+
if (changeLogItem is null)
169+
throw new ArgumentException("ChangeLogItem is null");
132170

133171
ChangeLogItem = changeLogItem;
134172
}
@@ -139,7 +177,7 @@ public IEnumerable<TimeByState> CalculateTotalTimeByState()
139177
if (!_workItemsChanges.Any())
140178
return timesByStateList;
141179

142-
foreach (var workItemChange in _workItemsChanges.OrderBy(x => x.CreatedAt).GroupBy(x => x.OldState).Where(x => x.Key != null))
180+
foreach (var workItemChange in _workItemsChanges.OrderBy(x => x.CreatedAt).GroupBy(x => x.OldState).Where(x => x.Key is not null))
143181
{
144182
var totalTime = TimeSpan.Zero;
145183
var totalWorkedTime = TimeSpan.Zero;

AzureDevopsTracker/Entities/WorkItemChange.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public void Validate()
4040

4141
public TimeSpan CalculateTotalTime()
4242
{
43-
return OldDate == null ? TimeSpan.Zero : NewDate.ToDateTimeFromTimeZoneInfo() - OldDate.Value.ToDateTimeFromTimeZoneInfo();
43+
return OldDate is null ? TimeSpan.Zero : NewDate.ToDateTimeFromTimeZoneInfo() - OldDate.Value.ToDateTimeFromTimeZoneInfo();
4444
}
4545

4646
public double CalculateTotalWorkedTime()
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using AzureDevopsTracker.Extensions;
2+
using System;
3+
4+
namespace AzureDevopsTracker.Entities
5+
{
6+
public class WorkItemCustomField
7+
{
8+
public string WorkItemId { get; private set; }
9+
public string Key { get; private set; }
10+
public string Value { get; private set; }
11+
12+
public WorkItem WorkItem { get; private set; }
13+
14+
public WorkItemCustomField(string workItemId, string key, string value)
15+
{
16+
WorkItemId = workItemId;
17+
Key = key;
18+
Value = value;
19+
}
20+
21+
public void LinkWorkItem(string workItemId)
22+
{
23+
if (workItemId.IsNullOrEmpty())
24+
throw new ArgumentException("WorkItemId is required");
25+
26+
WorkItemId = workItemId;
27+
}
28+
29+
public void Update(string value)
30+
{
31+
Value = value;
32+
}
33+
}
34+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
using AzureDevopsTracker.Entities;
2+
using Newtonsoft.Json.Linq;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
6+
namespace AzureDevopsTracker.Helpers
7+
{
8+
public static class ReadJsonHelper
9+
{
10+
public static IEnumerable<WorkItemCustomField> ReadJson(string workItemId, string jsonTexto)
11+
{
12+
try
13+
{
14+
var workItemCustomFields = new List<WorkItemCustomField>();
15+
foreach (KeyValuePair<string, JToken> element in JObject.Parse(jsonTexto))
16+
{
17+
if (element.Value is JObject)
18+
ReadJsonObject(workItemId, workItemCustomFields, (JObject)element.Value);
19+
else
20+
GetWorkItemCustomField(workItemCustomFields, workItemId, element.Key, element.Value.ToString());
21+
}
22+
23+
return workItemCustomFields;
24+
}
25+
catch
26+
{
27+
return Enumerable.Empty<WorkItemCustomField>();
28+
}
29+
}
30+
31+
private static void ReadJsonObject(string workItemId, List<WorkItemCustomField> workItemCustomFields, JObject objeto)
32+
{
33+
foreach (KeyValuePair<string, JToken> item in objeto)
34+
if (item.Value is JObject)
35+
ReadJsonObject(workItemId, workItemCustomFields, (JObject)item.Value);
36+
else
37+
GetWorkItemCustomField(workItemCustomFields, workItemId, item.Key, item.Value.ToString());
38+
}
39+
40+
private static void GetWorkItemCustomField(List<WorkItemCustomField> workItemCustomFields, string workItemId, string key, string value)
41+
{
42+
if (key is not null && !key.ToLower().Contains("custom")) return;
43+
workItemCustomFields.Add(new WorkItemCustomField(workItemId, key, value));
44+
}
45+
}
46+
}

AzureDevopsTracker/Integrations/MessageFacade.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public void Send(ChangeLog changeLog)
1919
using var scope = _serviceScopeFactory.CreateScope();
2020

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

2424
messageIntegration.Send(changeLog);
2525
}

0 commit comments

Comments
 (0)