using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Core.WebApi;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Proxy;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi;
using Microsoft.VisualStudio.Services.Common;
using Microsoft.VisualStudio.Services.WebApi;
using Microsoft.VisualStudio.Services.WebApi.Patch;
using Microsoft.VisualStudio.Services.WebApi.Patch.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tango.Core;
namespace Tango.TFS
{
///
/// Represents a VSTS (Visual Studio On-line) client implementation.
///
///
public class TeamFoundationServiceClient : ExtendedObject, ITeamFoundationServiceClient
{
#region Extension Fields Constants
private class ExtensionFields
{
public const String FOUND_IN_BUILD = "Microsoft.VSTS.Build.FoundIn";
public const String SEVERITY = "Microsoft.VSTS.Common.Severity";
public const String PRIORITY = "Microsoft.VSTS.Common.Priority";
public const String STEPS_TO_REP = "Microsoft.VSTS.TCM.ReproSteps";
public const String SYSTEM_INFO = "Microsoft.VSTS.TCM.SystemInfo";
public const String RESOLVED_BY = "Microsoft.VSTS.Common.ResolvedBy";
public const String RESOLVED_DATE = "Microsoft.VSTS.Common.ResolvedDate";
public const String RESOLVED_REASON = "Microsoft.VSTS.Common.ResolvedReason";
public const String EMBEDDED_VERSION = "Custom.EmbeddedVersion";
public const String MACHINE_SN = "Custom.MachineSN";
public const String ENVIRONMENT = "Custom.Environment";
public const String LOGGED_IN_USER = "Custom.LoggedInUser";
public const String MACHINE_TYPE = "Custom.MachineType";
}
#endregion
#region Properties
///
/// Gets the default team collection URL.
///
public String CollectionURL { get; private set; }
///
/// Gets the personal token used to authenticate against the service. https://docs.microsoft.com/en-us/vsts/accounts/use-personal-access-tokens-to-authenticate?view=vsts
///
public String PersonalToken { get; private set; }
///
/// Gets the VSTS user name (optional).
///
public String UserName { get; private set; }
#endregion
#region Constructors
///
/// Initializes a new instance of the class.
///
/// The collection URL.
/// Name of the user.
/// The personal token.
public TeamFoundationServiceClient(String collectionURL, String userName, String personalToken)
{
CollectionURL = collectionURL;
UserName = userName;
PersonalToken = personalToken;
}
#endregion
#region Public Methods
///
/// Gets a team project by the specified name.
///
/// The name.
///
public Task GetProject(string name)
{
return Task.Factory.StartNew(() =>
{
Project p = new Project();
VssConnection connection = CreateConnection();
LogManager.Log("Retrieving project " + name + " details...");
ProjectHttpClient projectClient = connection.GetClient();
TeamProjectReference project = projectClient.GetProjects().Result.FirstOrDefault(x => x.Name == name);
if (project == null)
{
throw LogManager.Log(new ArgumentException(String.Format("Project '{0}' could not be found.", name)));
}
LogManager.Log("Project details successfully retrieved.");
p.Name = project.Name;
p.ID = project.Id;
p.URL = project.Url;
p.Description = project.Description;
TeamHttpClient teamClient = connection.GetClient();
var team = teamClient.GetTeamsAsync(project.Id.ToString()).Result.FirstOrDefault();
IEnumerable teamMembers = teamClient.GetTeamMembersAsync(project.Id.ToString(), team.Id.ToString()).Result;
foreach (var member in teamMembers)
{
TeamMember teamMember = new TeamMember();
teamMember.ID = member.Id;
teamMember.DisplayName = member.DisplayName;
teamMember.ImageURL = member.ImageUrl;
teamMember.UniqueName = member.UniqueName;
teamMember.URL = member.Url;
p.Members.Add(teamMember);
}
TaggingHttpClient taggingClient = connection.GetClient();
WebApiTagDefinitionList tags = taggingClient.GetTagsAsync(project.Id).Result;
foreach (var tag in tags)
{
p.Tags.Add(new Tag()
{
ID = tag.Id,
Name = tag.Name,
});
}
var projCollection = new TfsTeamProjectCollection(new Uri(CollectionURL), connection.Credentials);
var store = projCollection.GetService();
WorkItemCollection queryResults = store.Query("Select [State], [Title] " + "From WorkItems " + "Where [Work Item Type] = 'User Story'");
var userStories = queryResults.OfType().Where(x => x.Project.Name == project.Name).ToList();
foreach (var userStory in userStories)
{
WorkItem story = new WorkItem();
story.Type = WorkItemType.UserStory;
story.Title = userStory.Title;
story.ID = userStory.Id;
story.URL = userStory.Uri.ToString();
story.Description = userStory.Description;
if (userStory.Fields[CoreField.AssignedTo].Value != null)
{
story.AssignedTo = p.Members.SingleOrDefault(x => x.AssignName == userStory.Fields[CoreField.AssignedTo].Value.ToString());
}
story.Area = new Area() { Name = userStory.AreaPath };
story.Iteration = new Iteration() { Name = userStory.IterationPath };
p.UserStories.Add(story);
}
var mainArea = new Area() { Name = project.Name, Path = project.Name };
p.Areas.Add(mainArea);
foreach (var area in store.Projects[project.Name].AreaRootNodes.OfType())
{
Area a = new Area();
FillArea(a, area);
mainArea.SubAreas.Add(a);
}
foreach (var iteration in store.Projects[project.Name].IterationRootNodes.OfType())
{
p.Iterations.Add(new Iteration()
{
Name = iteration.Name,
Path = iteration.Path,
});
}
return p;
});
}
private Area FillArea(Area area, Node node)
{
area.Name = node.Name;
area.Path = node.Path;
foreach (var child in node.ChildNodes.OfType())
{
var subArea = new Area();
FillArea(subArea, child);
area.SubAreas.Add(subArea);
}
return area;
}
///
/// Uploads a work item to the specified team project.
///
/// The project.
/// The work item.
///
public Task UploadWorkItem(Project project, WorkItem workItem)
{
return Task.Factory.StartNew(() =>
{
var connection = CreateConnection();
WorkItemTrackingHttpClient witClient = connection.GetClient();
var patchDocument = new JsonPatchDocument();
patchDocument.Add(new JsonPatchOperation
{
Operation = Operation.Add,
Path = GetFieldNameForWrite(CoreField.Title),
Value = workItem.Title,
});
if (!String.IsNullOrWhiteSpace(workItem.Description))
{
patchDocument.Add(new JsonPatchOperation
{
Operation = Operation.Add,
Path = GetFieldNameForWrite(CoreField.Description),
Value = workItem.Description,
});
}
if (!String.IsNullOrWhiteSpace(workItem.Comment))
{
patchDocument.Add(new JsonPatchOperation
{
Operation = Operation.Add,
Path = GetFieldNameForWrite(CoreField.History),
Value = workItem.Comment,
From = workItem.CreatedBy.AssignName
});
}
if (workItem.Iteration != null)
{
patchDocument.Add(new JsonPatchOperation
{
Operation = Operation.Add,
Path = GetFieldNameForWrite(CoreField.IterationPath),
Value = workItem.Iteration.Path,
});
}
patchDocument.Add(new JsonPatchOperation
{
Operation = Operation.Add,
Path = GetFieldNameForWrite(CoreField.AreaPath),
Value = workItem.Area.Path,
});
patchDocument.Add(new JsonPatchOperation
{
Operation = Operation.Add,
Path = GetFieldNameForWrite(CoreField.AssignedTo),
Value = workItem.AssignedTo.AssignName,
});
patchDocument.Add(new JsonPatchOperation
{
Operation = Operation.Add,
Path = GetFieldNameForWrite(CoreField.CreatedBy),
Value = workItem.CreatedBy.AssignName,
});
patchDocument.Add(new JsonPatchOperation
{
Operation = Operation.Add,
Path = GetFieldNameForWrite(CoreField.ChangedBy),
Value = workItem.ChangedBy.AssignName,
});
patchDocument.Add(new JsonPatchOperation
{
Operation = Operation.Add,
Path = GetFieldNameForWrite(CoreField.AuthorizedAs),
Value = workItem.AuthorizedAs.AssignName,
});
if (workItem.UserStory != null)
{
patchDocument.Add(
new JsonPatchOperation()
{
Operation = Operation.Add,
Path = "/relations/-",
Value = new
{
rel = "System.LinkTypes.Hierarchy-Reverse",
url = workItem.UserStory.URL,
}
}
);
}
foreach (var attachment in workItem.Attachments)
{
Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models.AttachmentReference attachmentReference = witClient.CreateAttachmentAsync(attachment.FilePath).Result;
patchDocument.Add(
new JsonPatchOperation()
{
Operation = Operation.Add,
Path = "/relations/-",
Value = new
{
rel = "AttachedFile",
url = attachmentReference.Url,
attributes = new { comment = attachment.Description, name = attachment.Name }
}
}
);
}
if (workItem.Tags.Count > 0)
{
patchDocument.Add(new JsonPatchOperation
{
Operation = Operation.Add,
Path = GetFieldNameForWrite(CoreField.Tags),
Value = String.Join("; ", workItem.Tags.Select(x => x.Name)),
});
}
if (!String.IsNullOrWhiteSpace(workItem.StepsToReproduce))
{
patchDocument.Add(new JsonPatchOperation
{
Operation = Operation.Add,
Path = GetExtensionFieldNameForWrite(ExtensionFields.STEPS_TO_REP),
Value = workItem.StepsToReproduce,
});
}
if (!String.IsNullOrWhiteSpace(workItem.FoundInBuild))
{
patchDocument.Add(new JsonPatchOperation
{
Operation = Operation.Add,
Path = GetExtensionFieldNameForWrite(ExtensionFields.FOUND_IN_BUILD),
Value = workItem.FoundInBuild,
});
}
patchDocument.Add(new JsonPatchOperation
{
Operation = Operation.Add,
Path = GetFieldNameForWrite(CoreField.State),
Value = workItem.State.ToString(),
});
patchDocument.Add(new JsonPatchOperation
{
Operation = Operation.Add,
Path = GetExtensionFieldNameForWrite(ExtensionFields.SEVERITY),
Value = workItem.Severity.ToDescription(),
});
patchDocument.Add(new JsonPatchOperation
{
Operation = Operation.Add,
Path = GetExtensionFieldNameForWrite(ExtensionFields.PRIORITY),
Value = (int)workItem.Priority,
});
patchDocument.Add(new JsonPatchOperation
{
Operation = Operation.Add,
Path = GetExtensionFieldNameForWrite(ExtensionFields.SYSTEM_INFO),
Value = workItem.SystemInformation,
});
if (workItem.EmbeddedVersion != null)
{
patchDocument.Add(new JsonPatchOperation
{
Operation = Operation.Add,
Path = GetExtensionFieldNameForWrite(ExtensionFields.EMBEDDED_VERSION),
Value = workItem.EmbeddedVersion,
});
}
if (workItem.Environment != null)
{
patchDocument.Add(new JsonPatchOperation
{
Operation = Operation.Add,
Path = GetExtensionFieldNameForWrite(ExtensionFields.ENVIRONMENT),
Value = workItem.Environment,
});
}
if (workItem.MachineSerialNumber != null)
{
patchDocument.Add(new JsonPatchOperation
{
Operation = Operation.Add,
Path = GetExtensionFieldNameForWrite(ExtensionFields.MACHINE_SN),
Value = workItem.MachineSerialNumber,
});
}
if (workItem.LoggedInUser != null)
{
patchDocument.Add(new JsonPatchOperation
{
Operation = Operation.Add,
Path = GetExtensionFieldNameForWrite(ExtensionFields.LOGGED_IN_USER),
Value = workItem.LoggedInUser,
});
}
patchDocument.Add(new JsonPatchOperation
{
Operation = Operation.Add,
Path = GetExtensionFieldNameForWrite(ExtensionFields.MACHINE_TYPE),
Value = workItem.MachineType.ToDescription(),
});
var resultWorkItem = witClient.CreateWorkItemAsync(patchDocument, project.Name, workItem.Type.ToString(), bypassRules: true).Result;
workItem.ID = resultWorkItem.Id.Value;
workItem.URL = resultWorkItem.Url;
return workItem;
});
}
///
/// Gets a work item by the specified team project and work item id.
///
/// The project.
/// The identifier.
///
public Task GetWorkItem(Project project, int id)
{
return Task.Factory.StartNew(() =>
{
var connection = CreateConnection();
WorkItemTrackingHttpClient witClient = connection.GetClient();
var item = witClient.GetWorkItemAsync(id, expand: Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models.WorkItemExpand.All).Result;
return ConvertToWorkItem(project, item);
});
}
///
/// Gets the type of the work items by.
///
/// The project.
/// The type.
///
public Task> GetWorkItemsByType(Project project, WorkItemType type)
{
return Task.Factory.StartNew>(() =>
{
var connection = CreateConnection();
var projCollection = new TfsTeamProjectCollection(new Uri(CollectionURL), connection.Credentials);
var store = projCollection.GetService();
WorkItemCollection queryResults = store.Query(String.Format("Select [Id]" + "From WorkItems " + "Where [Work Item Type] = '{0}'", type.ToString()));
var ids = queryResults.OfType().Where(x => x.Project.Name == project.Name).ToList().Select(x => x.Id).ToList();
if (ids.Count == 0) return new List();
WorkItemTrackingHttpClient witClient = connection.GetClient();
var items = witClient.GetWorkItemsAsync(ids).Result;
return items.Select(x => ConvertToWorkItem(project, x)).ToList();
});
}
///
/// Gets all work items of the specified project.
///
/// The project.
///
public Task> GetAllWorkItems(Project project)
{
return Task.Factory.StartNew>(() =>
{
var connection = CreateConnection();
var projCollection = new TfsTeamProjectCollection(new Uri(CollectionURL), connection.Credentials);
var store = projCollection.GetService();
WorkItemCollection queryResults = store.Query("Select [Id]" + "From WorkItems " + "Where [Work Item Type] = 'Bug' Or [Work Item Type] = 'Task'");
var ids = queryResults.OfType().Where(x => x.Project.Name == project.Name).ToList().Select(x => x.Id).ToList();
if (ids.Count == 0) return new List();
WorkItemTrackingHttpClient witClient = connection.GetClient();
var items = witClient.GetWorkItemsAsync(ids).Result;
return items.Select(x => ConvertToWorkItem(project, x)).ToList();
});
}
///
/// Deletes the specified work item.
///
/// The project.
/// The identifier.
///
public Task DeleteWorkItem(Project project, int id)
{
return Task.Factory.StartNew(() =>
{
var connection = CreateConnection();
WorkItemTrackingHttpClient witClient = connection.GetClient();
var result = witClient.DeleteWorkItemAsync(id, true).Result;
});
}
///
/// Gets all the work items created by the specified team member.
///
/// The project.
/// The member.
///
public Task> GetWorkItemsCreatedBy(Project project, TeamMember member)
{
return Task.Factory.StartNew>(() =>
{
var connection = CreateConnection();
var projCollection = new TfsTeamProjectCollection(new Uri(CollectionURL), connection.Credentials);
var store = projCollection.GetService();
WorkItemCollection queryResults = store.Query(String.Format("Select [Id]" + "From WorkItems " + "Where [Created By] = '{0}' And [Work Item Type] = 'Bug'", member.AssignName));
var ids = queryResults.OfType().Where(x => x.Project.Name == project.Name).ToList().Select(x => x.Id).ToList();
if (ids.Count == 0) return new List();
WorkItemTrackingHttpClient witClient = connection.GetClient();
var idsList = ids.ChunkBy(200);
List items = new List();
foreach (var idsChunk in idsList)
{
var chunkItems = witClient.GetWorkItemsAsync(idsChunk).Result;
items.AddRange(chunkItems);
}
return items.Select(x => ConvertToWorkItem(project, x)).ToList();
});
}
public Task> GetWorkItemAttachements(int id)
{
return Task.Factory.StartNew>(() =>
{
List handlers = new List();
var connection = CreateConnection();
var projCollection = new TfsTeamProjectCollection(new Uri(CollectionURL), connection.Credentials);
projCollection.EnsureAuthenticated();
WorkItemStore wistore = projCollection.GetService();
Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem wi = wistore.GetWorkItem(id);
//WorkItemServer wiserver = projCollection.GetService();
foreach (Microsoft.TeamFoundation.WorkItemTracking.Client.Attachment attachement in wi.Attachments)
{
AttachementHandler handler = new AttachementHandler((targetPath) =>
{
WorkItemTrackingHttpClient witClient = connection.GetClient();
//Method 1. Use for progress...
//Stream st = witClient.GetAttachmentContentAsync(Guid.Parse(attachement.FileGuid)).Result;
//var tempFile = TemporaryManager.CreateFile();
//using (var fileStream = File.Open(tempFile, FileMode.Create))
//{
// byte[] buffer = new byte[2048]; // read in chunks of 2KB
// int bytesRead;
// while ((bytesRead = st.Read(buffer, 0, buffer.Length)) > 0)
// {
// fileStream.Write(buffer, 0, bytesRead);
// }
//}
//File.Copy(tempFile, targetPath, true);
//tempFile.Delete();
//Method 2. More basic...
WorkItemServer wiserver = projCollection.GetService();
string tempPath = wiserver.DownloadFile(attachement.Id);
File.Copy(tempPath, targetPath, true);
try
{
File.Delete(tempPath);
}
catch { }
});
handler.Name = attachement.Name;
handler.Comment = attachement.Comment;
handler.AttachedTimeUtc = attachement.AttachedTimeUtc;
handler.Extension = attachement.Extension;
handler.FileGuid = attachement.FileGuid;
handler.Length = attachement.Length;
handlers.Add(handler);
}
return handlers;
});
}
public Task> GetWorkItemsForMachine(Project project, String serialNumber, DateTime startUtc, DateTime endUtc)
{
return Task.Factory.StartNew>(() =>
{
var connection = CreateConnection();
var projCollection = new TfsTeamProjectCollection(new Uri(CollectionURL), connection.Credentials);
var store = projCollection.GetService();
WorkItemCollection queryResults = store.Query($"Select [Id] From WorkItems Where {ExtensionFields.MACHINE_SN} = '{serialNumber}' And [Work Item Type] = 'Bug' AND [Created Date] >= '{startUtc.ToString("MM/dd/yyyy")}' AND [Created Date] <= '{endUtc.ToString("MM/dd/yyyy")}'");
var ids = queryResults.OfType().Where(x => x.Project.Name == project.Name).ToList().Select(x => x.Id).ToList();
if (ids.Count == 0) return new List();
WorkItemTrackingHttpClient witClient = connection.GetClient();
var items = witClient.GetWorkItemsAsync(ids).Result;
return items.Select(x => ConvertToWorkItem(project, x)).ToList();
});
}
///
/// Sets the state of the work item.
///
/// The project.
/// The item.
/// The state.
///
public Task SetWorkItemState(Project project, WorkItem item, State state)
{
return Task.Factory.StartNew(() =>
{
var connection = CreateConnection();
WorkItemTrackingHttpClient witClient = connection.GetClient();
var patchDocument = new JsonPatchDocument();
patchDocument.Add(new JsonPatchOperation
{
Operation = Operation.Replace,
Path = GetFieldNameForWrite(CoreField.State),
Value = state.ToString(),
});
var updatedItem = witClient.UpdateWorkItemAsync(patchDocument, item.ID).Result;
return ConvertToWorkItem(project, updatedItem);
});
}
public Task UpdateWorkItemSystemInfo(Project project, WorkItem item, String systemInfo)
{
return Task.Factory.StartNew(() =>
{
var connection = CreateConnection();
WorkItemTrackingHttpClient witClient = connection.GetClient();
var patchDocument = new JsonPatchDocument();
patchDocument.Add(new JsonPatchOperation
{
Operation = Operation.Replace,
Path = GetExtensionFieldNameForWrite(ExtensionFields.SYSTEM_INFO),
Value = systemInfo,
});
var updatedItem = witClient.UpdateWorkItemAsync(patchDocument, item.ID).Result;
return ConvertToWorkItem(project, updatedItem);
});
}
///
/// Adds a comment to the work item discussion.
///
/// The project.
/// The item.
/// Team member
/// The comment.
///
public Task AddWorkItemComment(Project project, WorkItem item, TeamMember teamMember, String comment)
{
return Task.Factory.StartNew(() =>
{
var connection = CreateConnection();
WorkItemTrackingHttpClient witClient = connection.GetClient();
var patchDocument = new JsonPatchDocument();
patchDocument.Add(new JsonPatchOperation
{
Operation = Operation.Add,
Path = GetFieldNameForWrite(CoreField.History),
Value = comment,
From = teamMember.AssignName
});
var updatedItem = witClient.UpdateWorkItemAsync(patchDocument, item.ID).Result;
return ConvertToWorkItem(project, updatedItem);
});
}
///
/// Sets the work item assignment.
///
/// The project.
/// The item.
/// The member.
///
public Task SetWorkItemAssignment(Project project, WorkItem item, TeamMember member)
{
return Task.Factory.StartNew(() =>
{
var connection = CreateConnection();
WorkItemTrackingHttpClient witClient = connection.GetClient();
var patchDocument = new JsonPatchDocument();
patchDocument.Add(new JsonPatchOperation
{
Operation = Operation.Replace,
Path = GetFieldNameForWrite(CoreField.AssignedTo),
Value = member.AssignName,
});
var updatedItem = witClient.UpdateWorkItemAsync(patchDocument, item.ID).Result;
return ConvertToWorkItem(project, updatedItem);
});
}
#endregion
#region Private Methods
///
/// Creates connection to VSTS.
///
///
private VssConnection CreateConnection()
{
LogManager.Log("Generating VSTS connection using personal token " + PersonalToken);
VssConnection connection = new VssConnection(new Uri(CollectionURL), new VssBasicCredential(String.Empty, PersonalToken));
connection.Credentials.PromptType = CredentialPromptType.DoNotPrompt;
connection.ConnectAsync(VssConnectMode.User).SyncResult();
LogManager.Log("VSS Connection established...");
LogManager.Log("Authenticated: " + connection.HasAuthenticated);
if (connection.HasAuthenticated)
{
LogManager.Log("Authenticated Identity: " + connection.AuthorizedIdentity.DisplayName);
}
return connection;
}
///
/// Creates a string representation of a VSTS field when reading.
///
/// The field.
///
private String GetFieldNameForRead(CoreField field)
{
return "System." + field.ToString();
}
///
/// Creates a string representation of a VSTS field when writing.
///
/// The field.
///
private String GetFieldNameForWrite(CoreField field)
{
return "/fields/System." + field.ToString();
}
///
/// Creates a string representation of a VSTS extension field when writing.
///
/// The field.
///
private String GetExtensionFieldNameForWrite(String extensionFieldName)
{
return "/fields/" + extensionFieldName;
}
///
/// Returns a value of the specified field key if found. Otherwise return an empty string.
///
/// The fields.
/// The key.
///
private String TryGetField(IDictionary fields, String key)
{
if (fields.ContainsKey(key))
{
return fields[key].ToString();
}
return String.Empty;
}
///
/// Returns the specified enum type value by it's [Description] attribute.
///
///
/// The description.
///
private T ParseEnumByDescription(String description)
{
Dictionary values = new Dictionary();
foreach (var item in Enum.GetValues(typeof(T)))
{
values.Add(((Enum)item).ToDescription(), (T)item);
}
return values[description];
}
private WorkItem ConvertToWorkItem(Project project, Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models.WorkItem item)
{
WorkItem workItem = new WorkItem();
workItem.ID = item.Id.Value;
workItem.Title = item.Fields[GetFieldNameForRead(CoreField.Title)].ToString();
workItem.CreatedDate = DateTime.Parse(item.Fields[GetFieldNameForRead(CoreField.CreatedDate)].ToString());
workItem.Description = TryGetField(item.Fields, GetFieldNameForRead(CoreField.Description));
workItem.Area = new Area()
{
Path = item.Fields[GetFieldNameForRead(CoreField.AreaPath)].ToString(),
Name = Path.GetFileName(item.Fields[GetFieldNameForRead(CoreField.AreaPath)].ToString()),
};
workItem.Iteration = new Iteration()
{
Path = item.Fields[GetFieldNameForRead(CoreField.IterationPath)].ToString(),
Name = Path.GetFileName(item.Fields[GetFieldNameForRead(CoreField.IterationPath)].ToString()),
};
workItem.AssignedTo = project.Members.SingleOrDefault(x => x.AssignName == TryGetField(item.Fields, GetFieldNameForRead(CoreField.AssignedTo)));
workItem.CreatedBy = project.Members.SingleOrDefault(x => x.AssignName == TryGetField(item.Fields, GetFieldNameForRead(CoreField.CreatedBy)));
workItem.ChangedBy = project.Members.SingleOrDefault(x => x.AssignName == TryGetField(item.Fields, GetFieldNameForRead(CoreField.ChangedBy)));
workItem.AuthorizedAs = project.Members.SingleOrDefault(x => x.AssignName == TryGetField(item.Fields, GetFieldNameForRead(CoreField.AuthorizedAs)));
workItem.ResolvedBy = project.Members.SingleOrDefault(x => x.AssignName == TryGetField(item.Fields, ExtensionFields.RESOLVED_BY));
if (item.Fields.ContainsKey(ExtensionFields.RESOLVED_REASON))
{
try
{
workItem.ResolvedReason = ParseEnumByDescription(item.Fields[ExtensionFields.RESOLVED_REASON].ToString());
if (item.Fields.ContainsKey(ExtensionFields.RESOLVED_DATE))
{
workItem.ResolvedDate = DateTime.Parse(item.Fields[ExtensionFields.RESOLVED_DATE].ToString());
}
}
catch (Exception ex)
{
Debug.WriteLine($"Error parsing TFS work item resolved reason.\n{ex.ToString()}");
LogManager.Log(ex, "Error parsing TFS work item resolved reason.");
}
}
workItem.Type = (WorkItemType)Enum.Parse(typeof(WorkItemType), item.Fields[GetFieldNameForRead(CoreField.WorkItemType)].ToString());
workItem.URL = item.Url;
if (item.Fields.ContainsKey(GetFieldNameForRead(CoreField.Tags)))
{
List tags = item.Fields[GetFieldNameForRead(CoreField.Tags)].ToString().Split(';').Select(x => x.Trim()).ToList();
workItem.Tags = tags.Select(x => new Tag() { Name = x }).ToList();
}
workItem.FoundInBuild = TryGetField(item.Fields, ExtensionFields.FOUND_IN_BUILD).ToString();
workItem.State = (State)Enum.Parse(typeof(State), item.Fields[GetFieldNameForRead(CoreField.State)].ToString());
if (item.Fields.ContainsKey(ExtensionFields.SEVERITY))
{
workItem.Severity = ParseEnumByDescription(item.Fields[ExtensionFields.SEVERITY].ToString());
}
workItem.Priority = (Priority)int.Parse(item.Fields[ExtensionFields.PRIORITY].ToString());
if (item.Fields.ContainsKey(ExtensionFields.STEPS_TO_REP))
{
workItem.StepsToReproduce = TryGetField(item.Fields, ExtensionFields.STEPS_TO_REP).ToString();
}
if (item.Fields.ContainsKey(ExtensionFields.SYSTEM_INFO))
{
workItem.SystemInformation = TryGetField(item.Fields, ExtensionFields.SYSTEM_INFO).ToString();
}
if (item.Fields.ContainsKey(ExtensionFields.LOGGED_IN_USER))
{
workItem.LoggedInUser = TryGetField(item.Fields, ExtensionFields.LOGGED_IN_USER).ToString();
}
if (item.Fields.ContainsKey(ExtensionFields.MACHINE_SN))
{
workItem.MachineSerialNumber = TryGetField(item.Fields, ExtensionFields.MACHINE_SN).ToString();
}
if (item.Fields.ContainsKey(ExtensionFields.ENVIRONMENT))
{
workItem.Environment = TryGetField(item.Fields, ExtensionFields.ENVIRONMENT).ToString();
}
if (item.Fields.ContainsKey(ExtensionFields.MACHINE_TYPE))
{
workItem.MachineType = ParseEnumByDescription(item.Fields[ExtensionFields.MACHINE_TYPE].ToString());
}
workItem.Comment = TryGetField(item.Fields, GetFieldNameForRead(CoreField.History)).ToString();
return workItem;
}
#endregion
}
}