Esempio n. 1
0
        private void IssueUpdated(Issue issue, Card card, BoardMapping boardMapping)
        {
            Log.Info("Issue [{0}] updated, comparing to corresponding card...", issue.Id);

            long boardId = boardMapping.Identity.LeanKit;

            // sync and save those items that are different (of title, description, priority)
            bool saveCard = false;

            if (issue.Title != card.Title)
            {
                card.Title = issue.Title;
                saveCard   = true;
            }

            if (issue.Body.SanitizeCardDescription() != card.Description)
            {
                card.Description = issue.Body.SanitizeCardDescription();
                saveCard         = true;
            }

            var priority = issue.LeanKitPriority();

            if (priority != card.Priority)
            {
                card.Priority = priority;
                saveCard      = true;
            }

            if (issue.Labels != null && issue.Labels.Count > 0)
            {
                var tags = string.Join(",", issue.Labels.Select(x => x.Name));
                if (card.Tags != tags)
                {
                    card.Tags = tags;
                    saveCard  = true;
                }
            }
            else if (!string.IsNullOrEmpty(card.Tags))
            {
                card.Tags = "";
                saveCard  = true;
            }

            if (issue.Milestone != null && issue.Milestone.Due_On != null)
            {
                if (CurrentUser != null)
                {
                    var dateFormat    = CurrentUser.DateFormat ?? "MM/dd/yyyy";
                    var dueDateString = issue.Milestone.Due_On.Value.ToString(dateFormat);
                    if (card.DueDate != dueDateString)
                    {
                        card.DueDate = dueDateString;
                        saveCard     = true;
                    }
                }
            }
            else if (!string.IsNullOrEmpty(card.DueDate))
            {
                card.DueDate = "";
                saveCard     = true;
            }

            if ((card.Tags == null || !card.Tags.Contains(ServiceName)) && boardMapping.TagCardsWithTargetSystemName)
            {
                if (string.IsNullOrEmpty(card.Tags))
                {
                    card.Tags = ServiceName;
                }
                else
                {
                    card.Tags += "," + ServiceName;
                }
                saveCard = true;
            }

            var lanes = boardMapping.LanesFromState(issue.State);

            if (lanes.Count > 0 && lanes.All(x => x != card.LaneId))
            {
                card.LaneId = lanes.First();
                saveCard    = true;
            }

            if (saveCard)
            {
                Log.Info("Updating card [{0}]", card.Id);
                LeanKit.UpdateCard(boardId, card);
            }
        }
Esempio n. 2
0
        private void CreateCardFromItem(BoardMapping project, Issue issue)
        {
            if (issue == null)
            {
                return;
            }
            if (!project.CreateCards)
            {
                Log.Debug("CreateCards is disabled, skipping card creation.");
                return;
            }

            var boardId = project.Identity.LeanKit;

            var mappedCardType = issue.LeanKitCardType(project);
            var laneId         = project.LanesFromState(issue.State).First();
            var card           = new Card
            {
                Active             = true,
                Title              = issue.Title,
                Description        = issue.Body.SanitizeCardDescription(),
                Priority           = issue.LeanKitPriority(),
                TypeId             = mappedCardType.Id,
                TypeName           = mappedCardType.Name,
                LaneId             = laneId,
                ExternalCardID     = issue.Id + "|" + issue.Number,
                ExternalSystemName = ServiceName,
                ExternalSystemUrl  = string.Format(_externalUrlTemplate, project.Identity.Target, issue.Number),
                Index              = 9999
            };

            var assignedUserId = issue.LeanKitAssignedUserId(boardId, LeanKit);

            if (assignedUserId != null)
            {
                card.AssignedUserIds = new[] { assignedUserId.Value }
            }
            ;

            if (issue.Milestone != null && issue.Milestone.Due_On != null)
            {
                if (CurrentUser != null)
                {
                    var dateFormat = CurrentUser.DateFormat ?? "MM/dd/yyyy";
                    card.DueDate = issue.Milestone.Due_On.Value.ToString(dateFormat);
                }
            }

            if (issue.Labels != null && issue.Labels.Any())
            {
                card.Tags = string.Join(",", issue.Labels.Select(x => x.Name).ToList());
            }

            if ((card.Tags == null || !card.Tags.Contains(ServiceName)) && project.TagCardsWithTargetSystemName)
            {
                if (string.IsNullOrEmpty(card.Tags))
                {
                    card.Tags = ServiceName;
                }
                else
                {
                    card.Tags += "," + ServiceName;
                }
            }

            Log.Info("Creating a card of type [{0}] for Issue [{1}] on Board [{2}] on Lane [{3}]", mappedCardType.Name, issue.Number, boardId, laneId);

            CardAddResult cardAddResult = null;

            int  tries   = 0;
            bool success = false;

            while (tries < 10 && !success)
            {
                if (tries > 0)
                {
                    Log.Error(string.Format("Attempting to create card for issue [{0}] attempt number [{1}]", issue.Id,
                                            tries));
                    // wait 5 seconds before trying again
                    Thread.Sleep(new TimeSpan(0, 0, 5));
                }

                try {
                    cardAddResult = LeanKit.AddCard(boardId, card, "New Card From GitHub Issue");
                    success       = true;
                } catch (Exception ex) {
                    Log.Error(string.Format("An error occurred: {0} - {1} - {2}", ex.GetType(), ex.Message, ex.StackTrace));
                }
                tries++;
            }
            card.Id = cardAddResult.CardId;

            Log.Info("Created a card [{0}] of type [{1}] for Issue [{2}] on Board [{3}] on Lane [{4}]", card.Id, mappedCardType.Name, issue.Number, boardId, laneId);
        }
        private void CreateCardFromWorkItem(BoardMapping project, WorkItem workItem)
        {
            if (workItem == null) return;

            var boardId = project.Identity.LeanKit;

            var mappedCardType = workItem.LeanKitCardType(project);

            var laneId = project.LanesFromState(workItem.State).First();
            var card = new Card
                {
                    Active = true,
                    Title = workItem.Title,
                    Description = workItem.LeanKitDescription(GetTfsVersion()),
                    Priority = workItem.LeanKitPriority(),
                    TypeId = mappedCardType.Id,
                    TypeName = mappedCardType.Name,
                    LaneId = laneId,
                    ExternalCardID = workItem.Id.ToString(CultureInfo.InvariantCulture),
                    ExternalSystemName = ServiceName
                };

			if (workItem.Fields.Contains("Tags") && workItem.Fields["Tags"] != null && workItem.Fields["Tags"].Value != null)
			{
				card.Tags = workItem.Fields["Tags"].Value.ToString().Replace(";", ",");
			}

            if (project.TagCardsWithTargetSystemName && (card.Tags == null || !card.Tags.Contains(ServiceName))) 
			{
				if (string.IsNullOrEmpty(card.Tags))
					card.Tags = ServiceName;
				else
					card.Tags += "," + ServiceName;
			}

			if (_projectHyperlinkService != null)
			{
				card.ExternalSystemUrl = _projectHyperlinkService.GetWorkItemEditorUrl(workItem.Id).ToString();
			}

	        if (workItem.Fields != null && workItem.Fields.Contains("Assigned To"))
	        {
		        if (workItem.Fields["Assigned To"] != null && workItem.Fields["Assigned To"].Value != null)
		        {
			        var assignedUserId = CalculateAssignedUserId(boardId, workItem.Fields["Assigned To"].Value.ToString());
			        if (assignedUserId != null)
				        card.AssignedUserIds = new[] {assignedUserId.Value};
		        }
	        }

			if (workItem.Fields != null && workItem.Fields.Contains("Due Date"))
			{
				if (workItem.Fields["Due Date"] != null && workItem.Fields["Due Date"].Value != null)
				{
					DateTime tfsDueDate;
					var isDate = DateTime.TryParse(workItem.Fields["Due Date"].Value.ToString(), out tfsDueDate);
					if (isDate)
					{
						if (CurrentUser != null)
						{
							var dateFormat = CurrentUser.DateFormat ?? "MM/dd/yyyy";
							card.DueDate = tfsDueDate.ToString(dateFormat);
						}
					}
				}
			}

			if (workItem.Fields != null && (workItem.Fields.Contains("Original Estimate") || workItem.Fields.Contains("Story Points")))
			{
				if (workItem.Fields.Contains("Original Estimate") && workItem.Fields["Original Estimate"] != null && workItem.Fields["Original Estimate"].Value != null)
				{
					double cardSize;
					var isNumber = Double.TryParse(workItem.Fields["Original Estimate"].Value.ToString(), out cardSize);
					if (isNumber)
						card.Size = (int)cardSize;
				}
				else if (workItem.Fields.Contains("Story Points") && workItem.Fields["Story Points"] != null && workItem.Fields["Story Points"].Value != null)
				{
					double cardSize;
					var isNumber = Double.TryParse(workItem.Fields["Story Points"].Value.ToString(), out cardSize);
					if (isNumber)
						card.Size = (int) cardSize;
				}
			}

	        Log.Info("Creating a card of type [{0}] for work item [{1}] on Board [{2}] on Lane [{3}]", mappedCardType.Name, workItem.Id, boardId, laneId);

	        CardAddResult cardAddResult = null;

	        var tries = 0;
	        var success = false;
	        while (tries < 10 && !success)
	        {
		        if (tries > 0)
		        {
			        Log.Warn(String.Format("Attempting to create card for work item [{0}] attempt number [{1}]", workItem.Id,
			                                 tries));
					// wait 5 seconds before trying again
					Thread.Sleep(new TimeSpan(0, 0, 5));
		        }

		        try
		        {
			        cardAddResult = LeanKit.AddCard(boardId, card, "New Card From TFS Work Item");
			        success = true;
		        }
		        catch (Exception ex)
		        {
					Log.Error(ex, string.Format("An error occurred creating a new card for work item [{0}]", workItem.Id));
		        }
		        tries++;
	        }
	        card.Id = cardAddResult.CardId;

            Log.Info("Created a card [{0}] of type [{1}] for work item [{2}] on Board [{3}] on Lane [{4}]", card.Id, mappedCardType.Name, workItem.Id, boardId, laneId);
        }
        private void WorkItemUpdated(WorkItem workItem, Card card, BoardMapping project)
        {
            Log.Info("WorkItem [{0}] updated, comparing to corresponding card...", workItem.Id);

	        var boardId = project.Identity.LeanKit;

            // sync and save those items that are different (of title, description, priority)
            var saveCard = false;
            if (workItem.Title != card.Title)
            {
                card.Title = workItem.Title;
                saveCard = true;
            }

            var description = workItem.LeanKitDescription(GetTfsVersion());
            if (description != card.Description)
            {
                card.Description = description;
                saveCard = true;
            }

            var priority = workItem.LeanKitPriority();
            if(priority!= card.Priority)
            {
                card.Priority = priority;
                saveCard = true;
            }
            
            if(workItem.Fields!=null && 
				workItem.Fields.Contains("Tags") && 
				workItem.Fields["Tags"] != null && 
				workItem.Fields["Tags"].Value.ToString() != card.Tags)
            {
	            var tfsTags = workItem.Fields["Tags"].Value.ToString();
				// since we cannot set the tags in TFS we cannot blindly overwrite the LK tags 
				// with what is in TFS. Instead we can only add TFS tags to LK
				if (!string.IsNullOrEmpty(tfsTags))
				{
					var tfsTagsArr = tfsTags.Contains(',') ? tfsTags.Split(',') : tfsTags.Split(';');
					foreach (var tag in tfsTagsArr)
					{
						if (card.Tags != null && card.Tags.ToLowerInvariant().Contains(tag.ToLowerInvariant())) continue;
						if (string.IsNullOrEmpty(card.Tags))
							card.Tags = tag;
						else
							card.Tags += "," + tag;
						saveCard = true;
					}
				}
            }

			if (workItem.Fields != null && (workItem.Fields.Contains("Original Estimate") || workItem.Fields.Contains("Story Points"))) 
			{
				if (workItem.Fields.Contains("Original Estimate") && workItem.Fields["Original Estimate"] != null && workItem.Fields["Original Estimate"].Value != null) 
				{
					double cardSize;
					var isNumber = Double.TryParse(workItem.Fields["Original Estimate"].Value.ToString(), out cardSize);
					if (isNumber)
					{
						var size = (int) cardSize;
						if (card.Size != size)
						{
							card.Size = size;
							saveCard = true;
						}
					}
				} 
				else if (workItem.Fields.Contains("Story Points") && workItem.Fields["Story Points"] != null && workItem.Fields["Story Points"].Value != null) 
				{
					double cardSize;
					var isNumber = Double.TryParse(workItem.Fields["Story Points"].Value.ToString(), out cardSize);
					if (isNumber)
					{
						var size = (int)cardSize;
						if (card.Size != size) 
						{
							card.Size = size;
							saveCard = true;
						}
					}
				}
			}

			if ((card.Tags == null || !card.Tags.Contains(ServiceName)) && project.TagCardsWithTargetSystemName) 
			{
				if (string.IsNullOrEmpty(card.Tags))
					card.Tags = ServiceName;
				else
					card.Tags += "," + ServiceName;
				saveCard = true;
			}

            if(saveCard)
            {
                Log.Info("Updating card [{0}]", card.Id);
                LeanKit.UpdateCard(boardId, card);
            }

			// check the state of the work item
			// if we have the state mapped to a lane then check to see if the card is in that lane
			// if it is not in that lane then move it to that lane
	        if (!project.UpdateCardLanes || string.IsNullOrEmpty(workItem.State)) return;

	        // if card is already in archive lane then we do not want to move it to the end lane
	        // because it is effectively the same thing with respect to integrating with TFS
	        if (card.LaneId == project.ArchiveLaneId)
	        {
		        return;
	        }

			var laneIds = project.LanesFromState(workItem.State);

	        if (laneIds.Any())
	        {
		        if (!laneIds.Contains(card.LaneId))
		        {
					// first let's see if any of the lanes are sibling lanes, if so then 
					// we should be using one of them. So we'll limit the results to just siblings
					if (project.ValidLanes != null) {
						var siblingLaneIds = (from siblingLaneId in laneIds
											  let parentLane =
												  project.ValidLanes.FirstOrDefault(x =>
													  x.HasChildLanes &&
													  x.ChildLaneIds.Contains(siblingLaneId) &&
													  x.ChildLaneIds.Contains(card.LaneId))
											  where parentLane != null
											  select siblingLaneId).ToList();
						if (siblingLaneIds.Any())
							laneIds = siblingLaneIds;
					}

			        LeanKit.MoveCard(project.Identity.LeanKit, card.Id, laneIds.First(), 0, "Moved Lane From TFS Work Item");
		        }
	        }
        }
		private void IssueUpdated(Issue issue, Card card, BoardMapping boardMapping)
		{
			Log.Info("Issue [{0}] updated, comparing to corresponding card...", issue.Key);

			long boardId = boardMapping.Identity.LeanKit;

			// sync and save those items that are different (of title, description, priority)
			bool saveCard = false;

			if (issue.Fields != null)
			{
				if (issue.Fields.Summary != null && issue.Fields.Summary != card.Title)
				{
					card.Title = issue.Fields.Summary;
					saveCard = true;
				}

				if (issue.Fields.Description != null &&
				    issue.Fields.Description.SanitizeCardDescription().JiraPlainTextToLeanKitHtml() != card.Description)
				{
					card.Description = issue.Fields.Description.SanitizeCardDescription().JiraPlainTextToLeanKitHtml();
					saveCard = true;
				}

				var priority = issue.LeanKitPriority();
				if (priority != card.Priority)
				{
					card.Priority = priority;
					saveCard = true;
				}

				if (issue.Fields.Labels != null && issue.Fields.Labels.Count > 0)
				{
					var tags = string.Join(",", issue.Fields.Labels.Select(x => x));
					if (card.Tags != tags)
					{
						card.Tags = tags;
						saveCard = true;
					}
				}
				else if (!string.IsNullOrEmpty(card.Tags))
				{
					card.Tags = "";
					saveCard = true;
				}

				if ((card.Tags == null || !card.Tags.Contains(ServiceName)) && boardMapping.TagCardsWithTargetSystemName)
				{
					if (string.IsNullOrEmpty(card.Tags))
						card.Tags = ServiceName;
					else
						card.Tags += "," + ServiceName;
					saveCard = true;
				}

				if (issue.Fields.DueDate != null && CurrentUser != null)
				{
					var dateFormat = CurrentUser.DateFormat ?? "MM/dd/yyyy";
					var dueDateString = issue.Fields.DueDate.Value.ToString(dateFormat, CultureInfo.InvariantCulture);
					if (card.DueDate != dueDateString)
					{
						card.DueDate = dueDateString;
						saveCard = true;
					}
				}
				else if (!string.IsNullOrEmpty(card.DueDate))
				{
					card.DueDate = "";
					saveCard = true;
				}
			}

			if (saveCard)
			{
				Log.Info("Updating card [{0}]", card.Id);
				LeanKit.UpdateCard(boardId, card);
			}

			// check the state of the work item
			// if we have the state mapped to a lane then check to see if the card is in that lane
			// if it is not in that lane then move it to that lane
			if (boardMapping.UpdateCardLanes && issue.Fields != null && issue.Fields.Status != null &&
			    !string.IsNullOrEmpty(issue.Fields.Status.Name))
			{
				var laneIds = boardMapping.LanesFromState(issue.Fields.Status.Name);
				if (laneIds.Any())
				{
					if (!laneIds.Contains(card.LaneId))
					{
						// first let's see if any of the lanes are sibling lanes, if so then
						// we should be using one of them. So we'll limit the results to just siblings
						if (boardMapping.ValidLanes != null)
						{
							var siblingLaneIds = (from siblingLaneId in laneIds
								let parentLane =
									boardMapping.ValidLanes.FirstOrDefault(x =>
										x.HasChildLanes &&
										x.ChildLaneIds.Contains(siblingLaneId) &&
										x.ChildLaneIds.Contains(card.LaneId))
								where parentLane != null
								select siblingLaneId).ToList();
							if (siblingLaneIds.Any())
								laneIds = siblingLaneIds;
						}

						LeanKit.MoveCard(boardMapping.Identity.LeanKit, card.Id, laneIds.First(), 0,
							"Moved Lane From Jira Issue");
					}
				}
			}
		}
		private void CreateCardFromItem(BoardMapping project, Issue issue)
		{
			if (issue == null) return;

			var boardId = project.Identity.LeanKit;

			var mappedCardType = issue.LeanKitCardType(project);

			var validLanes = project.LanesFromState(issue.Fields.Status.Name);
			var laneId = validLanes.Any() ? validLanes.First() : project.DefaultCardCreationLaneId;

			var card = new Card
			{
				Active = true,
				Title = issue.Fields.Summary,
				Description = issue.Fields.Description.SanitizeCardDescription().JiraPlainTextToLeanKitHtml(),
				Priority = issue.LeanKitPriority(),
				TypeId = mappedCardType.Id,
				TypeName = mappedCardType.Name,
				LaneId = laneId,
				ExternalCardID = issue.Key,
				ExternalSystemName = ServiceName,
				ExternalSystemUrl = string.Format(_externalUrlTemplate, issue.Key)
			};

			var assignedUserId = issue.LeanKitAssignedUserId(boardId, LeanKit);
			if (assignedUserId != null)
				card.AssignedUserIds = new[] {assignedUserId.Value};

			if (issue.Fields != null && issue.Fields.DueDate != null && CurrentUser != null)
			{
				var dateFormat = CurrentUser.DateFormat ?? "MM/dd/yyyy";
				card.DueDate = issue.Fields.DueDate.Value.ToString(dateFormat, CultureInfo.InvariantCulture);
			}

			if (issue.Fields != null && issue.Fields.Labels != null && issue.Fields.Labels.Any())
			{
				card.Tags = string.Join(",", issue.Fields.Labels);
			}

			if ((card.Tags == null || !card.Tags.Contains(ServiceName)) && project.TagCardsWithTargetSystemName)
			{
				if (string.IsNullOrEmpty(card.Tags))
					card.Tags = ServiceName;
				else
					card.Tags += "," + ServiceName;
			}

			// TODO: Add size from the custom story points field.

			Log.Info("Creating a card of type [{0}] for issue [{1}] on Board [{2}] on Lane [{3}]", mappedCardType.Name,
				issue.Key, boardId, laneId);

			CardAddResult cardAddResult = null;

			int tries = 0;
			bool success = false;
			while (tries < 10 && !success)
			{
				if (tries > 0)
				{
					Log.Error(string.Format("Attempting to create card for work item [{0}] attempt number [{1}]",
						issue.Key, tries));
					// wait 5 seconds before trying again
					Thread.Sleep(new TimeSpan(0, 0, 5));
				}

				try
				{
					cardAddResult = LeanKit.AddCard(boardId, card, "New Card From Jira Issue");
					success = true;
				}
				catch (Exception ex)
				{
					Log.Error(string.Format("An error occurred: {0} - {1} - {2}", ex.GetType(), ex.Message,
						ex.StackTrace));
				}
				tries++;
			}
			card.Id = cardAddResult.CardId;

			Log.Info("Created a card [{0}] of type [{1}] for work item [{2}] on Board [{3}] on Lane [{4}]", card.Id,
				mappedCardType.Name, issue.Key, boardId, laneId);
		}
Esempio n. 7
0
        private void IssueUpdated(Issue issue, Card card, BoardMapping boardMapping)
        {
            Log.Info("Issue [{0}] updated, comparing to corresponding card...", issue.Key);

            long boardId = boardMapping.Identity.LeanKit;

            // sync and save those items that are different (of title, description, priority)
            bool saveCard = false;

            if (issue.Fields != null)
            {
                if (issue.Fields.Summary != null && issue.Fields.Summary != card.Title)
                {
                    card.Title = issue.Fields.Summary;
                    saveCard   = true;
                }

                if (issue.Fields.Description != null && issue.Fields.Description.SanitizeCardDescription() != card.Description)
                {
                    card.Description = issue.Fields.Description.SanitizeCardDescription();
                    saveCard         = true;
                }

                var priority = issue.LeanKitPriority();
                if (priority != card.Priority)
                {
                    card.Priority = priority;
                    saveCard      = true;
                }

                if (issue.Fields.Labels != null && issue.Fields.Labels.Count > 0)
                {
                    var tags = string.Join(",", issue.Fields.Labels.Select(x => x));
                    if (card.Tags != tags)
                    {
                        card.Tags = tags;
                        saveCard  = true;
                    }
                }
                else if (!string.IsNullOrEmpty(card.Tags))
                {
                    card.Tags = "";
                    saveCard  = true;
                }

                if ((card.Tags == null || !card.Tags.Contains(ServiceName)) && boardMapping.TagCardsWithTargetSystemName)
                {
                    if (string.IsNullOrEmpty(card.Tags))
                    {
                        card.Tags = ServiceName;
                    }
                    else
                    {
                        card.Tags += "," + ServiceName;
                    }
                    saveCard = true;
                }

                if (issue.Fields.DueDate != null && CurrentUser != null)
                {
                    var dateFormat    = CurrentUser.DateFormat ?? "MM/dd/yyyy";
                    var dueDateString = issue.Fields.DueDate.Value.ToString(dateFormat, CultureInfo.InvariantCulture);
                    if (card.DueDate != dueDateString)
                    {
                        card.DueDate = dueDateString;
                        saveCard     = true;
                    }
                }
                else if (!string.IsNullOrEmpty(card.DueDate))
                {
                    card.DueDate = "";
                    saveCard     = true;
                }
            }

            if (saveCard)
            {
                Log.Info("Updating card [{0}]", card.Id);
                LeanKit.UpdateCard(boardId, card);
            }

            // check the state of the work item
            // if we have the state mapped to a lane then check to see if the card is in that lane
            // if it is not in that lane then move it to that lane
            if (boardMapping.UpdateCardLanes && issue.Fields != null && issue.Fields.Status != null && !string.IsNullOrEmpty(issue.Fields.Status.Name))
            {
                // if card is already in archive lane then we do not want to move it to the end lane
                // because it is effectively the same thing with respect to integrating with TFS
                if (card.LaneId == boardMapping.ArchiveLaneId)
                {
                    return;
                }

                var laneIds = boardMapping.LanesFromState(issue.Fields.Status.Name);
                if (laneIds.Any())
                {
                    if (!laneIds.Contains(card.LaneId))
                    {
                        // first let's see if any of the lanes are sibling lanes, if so then
                        // we should be using one of them. So we'll limit the results to just siblings
                        if (boardMapping.ValidLanes != null)
                        {
                            var siblingLaneIds = (from siblingLaneId in laneIds
                                                  let parentLane =
                                                      boardMapping.ValidLanes.FirstOrDefault(x =>
                                                                                             x.HasChildLanes &&
                                                                                             x.ChildLaneIds.Contains(siblingLaneId) &&
                                                                                             x.ChildLaneIds.Contains(card.LaneId))
                                                      where parentLane != null
                                                      select siblingLaneId).ToList();
                            if (siblingLaneIds.Any())
                            {
                                laneIds = siblingLaneIds;
                            }
                        }

                        LeanKit.MoveCard(boardMapping.Identity.LeanKit, card.Id, laneIds.First(), 0, "Moved Lane From Jira Issue");
                    }
                }
            }
        }
Esempio n. 8
0
        private void CreateCardFromItem(BoardMapping project, Issue issue)
        {
            if (issue == null)
            {
                return;
            }

            var boardId = project.Identity.LeanKit;

            var mappedCardType = issue.LeanKitCardType(project);

            var validLanes = project.LanesFromState(issue.Fields.Status.Name);
            var laneId     = validLanes.Any() ? validLanes.First() : project.DefaultCardCreationLaneId;

            var card = new Card
            {
                Active             = true,
                Title              = issue.Fields.Summary,
                Description        = issue.Fields.Description.SanitizeCardDescription(),
                Priority           = issue.LeanKitPriority(),
                TypeId             = mappedCardType.Id,
                TypeName           = mappedCardType.Name,
                LaneId             = laneId,
                ExternalCardID     = issue.Key,
                ExternalSystemName = ServiceName,
                ExternalSystemUrl  = string.Format(_externalUrlTemplate, issue.Key)
            };

            var assignedUserId = issue.LeanKitAssignedUserId(boardId, LeanKit);

            if (assignedUserId != null)
            {
                card.AssignedUserIds = new[] { assignedUserId.Value }
            }
            ;

            if (issue.Fields != null && issue.Fields.DueDate != null && CurrentUser != null)
            {
                var dateFormat = CurrentUser.DateFormat ?? "MM/dd/yyyy";
                card.DueDate = issue.Fields.DueDate.Value.ToString(dateFormat, CultureInfo.InvariantCulture);
            }

            if (issue.Fields != null && issue.Fields.Labels != null && issue.Fields.Labels.Any())
            {
                card.Tags = string.Join(",", issue.Fields.Labels);
            }

            if ((card.Tags == null || !card.Tags.Contains(ServiceName)) && project.TagCardsWithTargetSystemName)
            {
                if (string.IsNullOrEmpty(card.Tags))
                {
                    card.Tags = ServiceName;
                }
                else
                {
                    card.Tags += "," + ServiceName;
                }
            }

            // TODO: Add size from the custom story points field.

            Log.Info("Creating a card of type [{0}] for issue [{1}] on Board [{2}] on Lane [{3}]", mappedCardType.Name, issue.Key, boardId, laneId);

            CardAddResult cardAddResult = null;

            int  tries   = 0;
            bool success = false;

            while (tries < 10 && !success)
            {
                if (tries > 0)
                {
                    Log.Error(string.Format("Attempting to create card for work item [{0}] attempt number [{1}]", issue.Key, tries));
                    // wait 5 seconds before trying again
                    Thread.Sleep(new TimeSpan(0, 0, 5));
                }

                try
                {
                    cardAddResult = LeanKit.AddCard(boardId, card, "New Card From Jira Issue");
                    success       = true;
                }
                catch (Exception ex)
                {
                    Log.Error(string.Format("An error occurred: {0} - {1} - {2}", ex.GetType(), ex.Message, ex.StackTrace));
                }
                tries++;
            }
            card.Id = cardAddResult.CardId;

            Log.Info("Created a card [{0}] of type [{1}] for work item [{2}] on Board [{3}] on Lane [{4}]", card.Id, mappedCardType.Name, issue.Key, boardId, laneId);
        }
		private void IssueUpdated(Issue issue, Card card, BoardMapping boardMapping) 
		{
			Log.Info("Issue [{0}] updated, comparing to corresponding card...", issue.Id);

			long boardId = boardMapping.Identity.LeanKit;

			// sync and save those items that are different (of title, description, priority)
			bool saveCard = false;
			if (issue.Title != card.Title) 
			{
				card.Title = issue.Title;
				saveCard = true;
			}

			if (issue.Body.SanitizeCardDescription() != card.Description) 
			{
				card.Description = issue.Body.SanitizeCardDescription();
				saveCard = true;
			}

			var priority = issue.LeanKitPriority();
			if (priority != card.Priority) 
			{
				card.Priority = priority;
				saveCard = true;
			}

			if (issue.Labels != null && issue.Labels.Count > 0)
			{
				var tags = string.Join(",", issue.Labels.Select(x => x.Name));
				if (card.Tags != tags)
				{
					card.Tags = tags;
					saveCard = true;
				}
			}
			else if (!string.IsNullOrEmpty(card.Tags))
			{
				card.Tags = "";
				saveCard = true;
			}

			if (issue.Milestone != null && issue.Milestone.Due_On != null) 
			{
				if (CurrentUser != null)
				{
					var dateFormat = CurrentUser.DateFormat ?? "MM/dd/yyyy";
					var dueDateString = issue.Milestone.Due_On.Value.ToString(dateFormat);
					if (card.DueDate != dueDateString)
					{
						card.DueDate = dueDateString;
						saveCard = true;
					}
				}
			} 
			else if (!string.IsNullOrEmpty(card.DueDate)) 
			{
				card.DueDate = "";
				saveCard = true;
			}

			if ((card.Tags == null || !card.Tags.Contains(ServiceName)) && boardMapping.TagCardsWithTargetSystemName) 
			{
				if (string.IsNullOrEmpty(card.Tags))
					card.Tags = ServiceName;
				else
					card.Tags += "," + ServiceName;
				saveCard = true;
			}

			var lanes = boardMapping.LanesFromState(issue.State);
			if (lanes.Count > 0 && lanes.All(x => x != card.LaneId))
			{
				card.LaneId = lanes.First();
				saveCard = true;
			}

			if (saveCard) 
			{
				Log.Info("Updating card [{0}]", card.Id);
				LeanKit.UpdateCard(boardId, card);
			}
		}
        private void CreateCardFromItem(BoardMapping project, Issue issue)
        {
			if (issue == null) return;
        
            var boardId = project.Identity.LeanKit;
        
            var mappedCardType = issue.LeanKitCardType(project);
            var laneId = project.LanesFromState(issue.State).First();
            var card = new Card
            {
			    Active = true,
                Title = issue.Title,
				Description = issue.Body.SanitizeCardDescription(),
                Priority = issue.LeanKitPriority(),
                TypeId = mappedCardType.Id,
                TypeName = mappedCardType.Name,
                LaneId = laneId,
                ExternalCardID = issue.Id + "|" + issue.Number,
                ExternalSystemName = ServiceName,
				ExternalSystemUrl = string.Format(_externalUrlTemplate, project.Identity.Target, issue.Number)
            };

			var assignedUserId = issue.LeanKitAssignedUserId(boardId, LeanKit);
			if (assignedUserId != null)
				card.AssignedUserIds = new[] { assignedUserId.Value };

			if (issue.Milestone != null && issue.Milestone.Due_On != null) 
			{
				if (CurrentUser != null) 
				{
					var dateFormat = CurrentUser.DateFormat ?? "MM/dd/yyyy";
					card.DueDate = issue.Milestone.Due_On.Value.ToString(dateFormat);
				}
			}

			if (issue.Labels != null && issue.Labels.Any())
			{
				card.Tags = string.Join(",", issue.Labels.Select(x => x.Name).ToList());
			}

			if ((card.Tags == null || !card.Tags.Contains(ServiceName)) && project.TagCardsWithTargetSystemName) 
			{
				if (string.IsNullOrEmpty(card.Tags))
					card.Tags = ServiceName;
				else
					card.Tags += "," + ServiceName;
			}

            Log.Info("Creating a card of type [{0}] for Issue [{1}] on Board [{2}] on Lane [{3}]", mappedCardType.Name, issue.Number, boardId, laneId);

	        CardAddResult cardAddResult = null;

			int tries = 0;
			bool success = false;
			while (tries < 10 && !success) 
			{
				if (tries > 0) 
				{
					Log.Error(string.Format("Attempting to create card for issue [{0}] attempt number [{1}]", issue.Id,
											 tries));
					// wait 5 seconds before trying again
					Thread.Sleep(new TimeSpan(0, 0, 5));
				}

				try {
					cardAddResult = LeanKit.AddCard(boardId, card, "New Card From GitHub Issue");
					success = true;
				} catch (Exception ex) {
					Log.Error(string.Format("An error occurred: {0} - {1} - {2}", ex.GetType(), ex.Message, ex.StackTrace));
				}
				tries++;
			}
			card.Id = cardAddResult.CardId;
        
            Log.Info("Created a card [{0}] of type [{1}] for Issue [{2}] on Board [{3}] on Lane [{4}]", card.Id, mappedCardType.Name, issue.Number, boardId, laneId);
        }
        private void CreateCardFromItem(BoardMapping project, Pull pull)
        {
			if (pull == null) return;
        
            var boardId = project.Identity.LeanKit;
        
            var mappedCardType = pull.LeanKitCardType(project);
            var laneId = project.LanesFromState(pull.State).First();
            var card = new Card
            {
			    Active = true,
                Title = pull.Title,
				Description = pull.Body.SanitizeCardDescription(),
				Priority = pull.LeanKitPriority(),
                TypeId = mappedCardType.Id,
                TypeName = mappedCardType.Name,
                LaneId = laneId,
                ExternalCardID = pull.Id.ToString() + "|" + pull.Number.ToString(),
                ExternalSystemName = ServiceName, 				
				ExternalSystemUrl = string.Format(_externalUrlTemplate, project.Identity.Target, pull.Number)
            };

			var assignedUserId = pull.LeanKitAssignedUser(boardId, LeanKit);
			if (assignedUserId != null)
				card.AssignedUserIds = new[] { assignedUserId.Value };

			if ((card.Tags == null || !card.Tags.Contains(ServiceName)) && project.TagCardsWithTargetSystemName) 
			{
				if (string.IsNullOrEmpty(card.Tags))
					card.Tags = ServiceName;
				else
					card.Tags += "," + ServiceName;
			}

            Log.Info("Creating a card of type [{0}] for Pull Request [{1}] on Board [{2}] on Lane [{3}]", mappedCardType.Name, pull.Number, boardId, laneId);

	        CardAddResult cardAddResult = null;

			int tries = 0;
			bool success = false;
			while (tries < 10 && !success) 
			{
				if (tries > 0) 
				{
					Log.Error(string.Format("Attempting to create card for Pull Request [{0}] attempt number [{1}]", pull.Id,
											 tries));
					// wait 5 seconds before trying again
					Thread.Sleep(new TimeSpan(0, 0, 5));
				}

				try {
					cardAddResult = LeanKit.AddCard(boardId, card, "New Card From GitHub Pull Request");
					success = true;
				} catch (Exception ex) {
					Log.Error(string.Format("An error occurred: {0} - {1} - {2}", ex.GetType(), ex.Message, ex.StackTrace));
				}
				tries++;
			}
	        if (cardAddResult != null) card.Id = cardAddResult.CardId;

	        Log.Info("Created a card [{0}] of type [{1}] for Pull Request [{2}] on Board [{3}] on Lane [{4}]", card.Id, mappedCardType.Name, pull.Number, boardId, laneId);
        }
        private void CreateCardFromItem(BoardMapping project, Pull pull)
        {
            if (pull == null)
            {
                return;
            }

            var boardId = project.Identity.LeanKit;

            var mappedCardType = pull.LeanKitCardType(project);
            var laneId         = project.LanesFromState(pull.State).First();
            var card           = new Card
            {
                Active             = true,
                Title              = pull.Title,
                Description        = pull.Body.SanitizeCardDescription(),
                Priority           = pull.LeanKitPriority(),
                TypeId             = mappedCardType.Id,
                TypeName           = mappedCardType.Name,
                LaneId             = laneId,
                ExternalCardID     = pull.Id.ToString() + "|" + pull.Number.ToString(),
                ExternalSystemName = ServiceName,
                ExternalSystemUrl  = string.Format(_externalUrlTemplate, project.Identity.Target, pull.Number)
            };

            var assignedUserId = pull.LeanKitAssignedUser(boardId, LeanKit);

            if (assignedUserId != null)
            {
                card.AssignedUserIds = new[] { assignedUserId.Value }
            }
            ;

            if ((card.Tags == null || !card.Tags.Contains(ServiceName)) && project.TagCardsWithTargetSystemName)
            {
                if (string.IsNullOrEmpty(card.Tags))
                {
                    card.Tags = ServiceName;
                }
                else
                {
                    card.Tags += "," + ServiceName;
                }
            }

            Log.Info("Creating a card of type [{0}] for Pull Request [{1}] on Board [{2}] on Lane [{3}]", mappedCardType.Name, pull.Number, boardId, laneId);

            CardAddResult cardAddResult = null;

            int  tries   = 0;
            bool success = false;

            while (tries < 10 && !success)
            {
                if (tries > 0)
                {
                    Log.Error(string.Format("Attempting to create card for Pull Request [{0}] attempt number [{1}]", pull.Id,
                                            tries));
                    // wait 5 seconds before trying again
                    Thread.Sleep(new TimeSpan(0, 0, 5));
                }

                try {
                    cardAddResult = LeanKit.AddCard(boardId, card, "New Card From GitHub Pull Request");
                    success       = true;
                } catch (Exception ex) {
                    Log.Error(string.Format("An error occurred: {0} - {1} - {2}", ex.GetType(), ex.Message, ex.StackTrace));
                }
                tries++;
            }
            if (cardAddResult != null)
            {
                card.Id = cardAddResult.CardId;
            }

            Log.Info("Created a card [{0}] of type [{1}] for Pull Request [{2}] on Board [{3}] on Lane [{4}]", card.Id, mappedCardType.Name, pull.Number, boardId, laneId);
        }
Esempio n. 13
0
        private void CreateCardFromItem(BoardMapping project, Ticket ticket)
        {
            if (ticket == null)
            {
                return;
            }

            var boardId = project.Identity.LeanKit;

            var mappedCardType = ticket.LeanKitCardType(project);

            var laneId = project.LanesFromState(ticket.Status).First();
            var card   = new Card
            {
                Active             = true,
                Title              = ticket.Summary,
                Description        = ticket.Description.SanitizeCardDescription(),
                Priority           = ticket.LeanKitPriority(),
                TypeId             = mappedCardType.Id,
                TypeName           = mappedCardType.Name,
                LaneId             = laneId,
                ExternalCardID     = ticket.Id.ToString(),
                ExternalSystemName = ServiceName,
                ExternalSystemUrl  = string.Format(_externalUrlTemplate, ticket.Id, project.Identity.Target)
            };

            var assignedUserId = CalculateAssignedUserId(boardId, ticket);

            if (assignedUserId != null)
            {
                card.AssignedUserIds = new[] { assignedUserId.Value }
            }
            ;

            if (ticket.Due_On != null)
            {
                if (CurrentUser != null)
                {
                    var dateFormat = CurrentUser.DateFormat ?? "MM/dd/yyyy";
                    card.DueDate = ticket.Due_On.Value.ToString(dateFormat);
                }
            }

            if ((card.Tags == null || !card.Tags.Contains(ServiceName)) && project.TagCardsWithTargetSystemName)
            {
                if (string.IsNullOrEmpty(card.Tags))
                {
                    card.Tags = ServiceName;
                }
                else
                {
                    card.Tags += "," + ServiceName;
                }
            }

            Log.Info("Creating a card of type [{0}] for ticket [{1}] on Board [{2}] on Lane [{3}]", mappedCardType.Name, ticket.Id, boardId, laneId);

            CardAddResult cardAddResult = null;

            int  tries   = 0;
            bool success = false;

            while (tries < 10 && !success)
            {
                if (tries > 0)
                {
                    Log.Error(string.Format("Attempting to create card for ticket [{0}] attempt number [{1}]", ticket.Id, tries));
                    // wait 5 seconds before trying again
                    Thread.Sleep(new TimeSpan(0, 0, 5));
                }

                try
                {
                    cardAddResult = LeanKit.AddCard(boardId, card, "New Card From Unfuddle Ticket");
                    success       = true;
                }
                catch (Exception ex)
                {
                    Log.Error(string.Format("An error occurred: {0} - {1} - {2}", ex.GetType(), ex.Message, ex.StackTrace));
                }
                tries++;
            }
            if (cardAddResult != null)
            {
                card.Id = cardAddResult.CardId;
            }

            Log.Info("Created a card [{0}] of type [{1}] for ticket [{2}] on Board [{3}] on Lane [{4}]", card.Id, mappedCardType.Name, ticket.Id, boardId, laneId);
        }
Esempio n. 14
0
        private void WorkItemUpdated(WorkItem workItem, Card card, BoardMapping project)
        {
            Log.Info("WorkItem [{0}] updated, comparing to corresponding card...", workItem.Id);

            var boardId = project.Identity.LeanKit;

            // sync and save those items that are different (of title, description, priority)
            var saveCard = false;

            if (workItem.Title != card.Title)
            {
                card.Title = workItem.Title;
                saveCard   = true;
            }

            var description = workItem.LeanKitDescription(GetTfsVersion());

            if (description != card.Description)
            {
                card.Description = description;
                saveCard         = true;
            }

            var priority = workItem.LeanKitPriority();

            if (priority != card.Priority)
            {
                card.Priority = priority;
                saveCard      = true;
            }

            if (workItem.Fields != null &&
                workItem.Fields.Contains("Tags") &&
                workItem.Fields["Tags"] != null &&
                workItem.Fields["Tags"].Value.ToString() != card.Tags)
            {
                var tfsTags = workItem.Fields["Tags"].Value.ToString();
                // since we cannot set the tags in TFS we cannot blindly overwrite the LK tags
                // with what is in TFS. Instead we can only add TFS tags to LK
                if (!string.IsNullOrEmpty(tfsTags))
                {
                    var tfsTagsArr = tfsTags.Split(',');
                    foreach (var tag in tfsTagsArr)
                    {
                        if (card.Tags.ToLowerInvariant().Contains(tag.ToLowerInvariant()))
                        {
                            continue;
                        }
                        if (card.Tags == string.Empty)
                        {
                            card.Tags = tag;
                        }
                        else
                        {
                            card.Tags += "," + tag;
                        }
                        saveCard = true;
                    }
                }
            }

            if (workItem.Fields != null && (workItem.Fields.Contains("Original Estimate") || workItem.Fields.Contains("Story Points")))
            {
                if (workItem.Fields.Contains("Original Estimate") && workItem.Fields["Original Estimate"] != null && workItem.Fields["Original Estimate"].Value != null)
                {
                    double cardSize;
                    var    isNumber = Double.TryParse(workItem.Fields["Original Estimate"].Value.ToString(), out cardSize);
                    if (isNumber)
                    {
                        var size = (int)cardSize;
                        if (card.Size != size)
                        {
                            card.Size = size;
                            saveCard  = true;
                        }
                    }
                }
                else if (workItem.Fields.Contains("Story Points") && workItem.Fields["Story Points"] != null && workItem.Fields["Story Points"].Value != null)
                {
                    double cardSize;
                    var    isNumber = Double.TryParse(workItem.Fields["Story Points"].Value.ToString(), out cardSize);
                    if (isNumber)
                    {
                        var size = (int)cardSize;
                        if (card.Size != size)
                        {
                            card.Size = size;
                            saveCard  = true;
                        }
                    }
                }
            }

            if ((card.Tags == null || !card.Tags.Contains(ServiceName)) && project.TagCardsWithTargetSystemName)
            {
                if (string.IsNullOrEmpty(card.Tags))
                {
                    card.Tags = ServiceName;
                }
                else
                {
                    card.Tags += "," + ServiceName;
                }
                saveCard = true;
            }

            if (saveCard)
            {
                Log.Info("Updating card [{0}]", card.Id);
                LeanKit.UpdateCard(boardId, card);
            }

            // check the state of the work item
            // if we have the state mapped to a lane then check to see if the card is in that lane
            // if it is not in that lane then move it to that lane
            if (!project.UpdateCardLanes || string.IsNullOrEmpty(workItem.State))
            {
                return;
            }

            // if card is already in archive lane then we do not want to move it to the end lane
            // because it is effectively the same thing with respect to integrating with TFS
            if (card.LaneId == project.ArchiveLaneId)
            {
                return;
            }

            var laneIds = project.LanesFromState(workItem.State);

            if (laneIds.Any())
            {
                if (!laneIds.Contains(card.LaneId))
                {
                    // first let's see if any of the lanes are sibling lanes, if so then
                    // we should be using one of them. So we'll limit the results to just siblings
                    if (project.ValidLanes != null)
                    {
                        var siblingLaneIds = (from siblingLaneId in laneIds
                                              let parentLane =
                                                  project.ValidLanes.FirstOrDefault(x =>
                                                                                    x.HasChildLanes &&
                                                                                    x.ChildLaneIds.Contains(siblingLaneId) &&
                                                                                    x.ChildLaneIds.Contains(card.LaneId))
                                                  where parentLane != null
                                                  select siblingLaneId).ToList();
                        if (siblingLaneIds.Any())
                        {
                            laneIds = siblingLaneIds;
                        }
                    }

                    LeanKit.MoveCard(project.Identity.LeanKit, card.Id, laneIds.First(), 0, "Moved Lane From TFS Work Item");
                }
            }
        }
Esempio n. 15
0
        private void CreateCardFromWorkItem(BoardMapping project, WorkItem workItem)
        {
            if (workItem == null)
            {
                return;
            }

            var boardId = project.Identity.LeanKit;

            var mappedCardType = workItem.LeanKitCardType(project);

            var laneId = project.LanesFromState(workItem.State).First();
            var card   = new Card
            {
                Active             = true,
                Title              = workItem.Title,
                Description        = workItem.LeanKitDescription(GetTfsVersion()),
                Priority           = workItem.LeanKitPriority(),
                TypeId             = mappedCardType.Id,
                TypeName           = mappedCardType.Name,
                LaneId             = laneId,
                ExternalCardID     = workItem.Id.ToString(CultureInfo.InvariantCulture),
                ExternalSystemName = ServiceName
            };

            if (workItem.Fields.Contains("Tags") && workItem.Fields["Tags"] != null && workItem.Fields["Tags"].Value != null)
            {
                card.Tags = workItem.Fields["Tags"].Value.ToString();
            }

            if (project.TagCardsWithTargetSystemName && (card.Tags == null || !card.Tags.Contains(ServiceName)))
            {
                if (string.IsNullOrEmpty(card.Tags))
                {
                    card.Tags = ServiceName;
                }
                else
                {
                    card.Tags += "," + ServiceName;
                }
            }

            if (_projectHyperlinkService != null)
            {
                card.ExternalSystemUrl = _projectHyperlinkService.GetWorkItemEditorUrl(workItem.Id).ToString();
            }

            if (workItem.Fields != null && workItem.Fields.Contains("Assigned To"))
            {
                if (workItem.Fields["Assigned To"] != null && workItem.Fields["Assigned To"].Value != null)
                {
                    var assignedUserId = CalculateAssignedUserId(boardId, workItem.Fields["Assigned To"].Value.ToString());
                    if (assignedUserId != null)
                    {
                        card.AssignedUserIds = new[] { assignedUserId.Value }
                    }
                    ;
                }
            }

            if (workItem.Fields != null && workItem.Fields.Contains("Due Date"))
            {
                if (workItem.Fields["Due Date"] != null && workItem.Fields["Due Date"].Value != null)
                {
                    DateTime tfsDueDate;
                    var      isDate = DateTime.TryParse(workItem.Fields["Due Date"].Value.ToString(), out tfsDueDate);
                    if (isDate)
                    {
                        if (CurrentUser != null)
                        {
                            var dateFormat = CurrentUser.DateFormat ?? "MM/dd/yyyy";
                            card.DueDate = tfsDueDate.ToString(dateFormat);
                        }
                    }
                }
            }

            if (workItem.Fields != null && (workItem.Fields.Contains("Original Estimate") || workItem.Fields.Contains("Story Points")))
            {
                if (workItem.Fields.Contains("Original Estimate") && workItem.Fields["Original Estimate"] != null && workItem.Fields["Original Estimate"].Value != null)
                {
                    double cardSize;
                    var    isNumber = Double.TryParse(workItem.Fields["Original Estimate"].Value.ToString(), out cardSize);
                    if (isNumber)
                    {
                        card.Size = (int)cardSize;
                    }
                }
                else if (workItem.Fields.Contains("Story Points") && workItem.Fields["Story Points"] != null && workItem.Fields["Story Points"].Value != null)
                {
                    double cardSize;
                    var    isNumber = Double.TryParse(workItem.Fields["Story Points"].Value.ToString(), out cardSize);
                    if (isNumber)
                    {
                        card.Size = (int)cardSize;
                    }
                }
            }

            Log.Info("Creating a card of type [{0}] for work item [{1}] on Board [{2}] on Lane [{3}]", mappedCardType.Name, workItem.Id, boardId, laneId);

            CardAddResult cardAddResult = null;

            var tries   = 0;
            var success = false;

            while (tries < 10 && !success)
            {
                if (tries > 0)
                {
                    Log.Warn(String.Format("Attempting to create card for work item [{0}] attempt number [{1}]", workItem.Id,
                                           tries));
                    // wait 5 seconds before trying again
                    Thread.Sleep(new TimeSpan(0, 0, 5));
                }

                try
                {
                    cardAddResult = LeanKit.AddCard(boardId, card, "New Card From TFS Work Item");
                    success       = true;
                }
                catch (Exception ex)
                {
                    Log.Error(ex, string.Format("An error occurred creating a new card for work item [{0}]", workItem.Id));
                }
                tries++;
            }
            card.Id = cardAddResult.CardId;

            Log.Info("Created a card [{0}] of type [{1}] for work item [{2}] on Board [{3}] on Lane [{4}]", card.Id, mappedCardType.Name, workItem.Id, boardId, laneId);
        }