public Card ToCard() { var card = new Card(); card.Active = Active; card.ClassOfServiceId = ClassOfServiceId; card.BlockReason = BlockReason; card.Description = Description; card.StartDate = StartDate; card.DueDate = DueDate; card.ExternalCardID = ExternalCardID; card.ExternalSystemName = ExternalSystemName; card.ExternalSystemUrl = ExternalSystemUrl; card.Id = Id; card.Index = Index; card.IsBlocked = IsBlocked; card.LaneId = LaneId; card.Priority = (int) Priority; card.Size = Size; card.Tags = Tags; card.Title = Title; card.TypeId = TypeId; card.Version = Version; card.AssignedUserIds = (AssignedUsers != null) ? AssignedUsers.Select(x => x.AssignedUserId).ToArray() : null; card.Comments = Comments; card.HistoryEvents = HistoryEvents; card.HistoryEvents = HistoryEvents; card.LastMove = LastMove; card.LastActivity = LastActivity; card.LastComment = LastComment; card.DateArchived = DateArchived; return card; }
public void It_should_not_call_unfuddle_to_update_ticket_for_states_it_is_in_or_past() { Card card2 = new Card() { Id = 2, ExternalSystemName = "Unfuddle", ExternalCardID = "2" }; Card card4 = new Card() { Id = 4, ExternalSystemName = "Unfuddle", ExternalCardID = "4" }; ((TestUnfuddle)TestItem).TestUpdateStateOfExternalItem(card2, _mapping.LaneToStatesMap[2], _mapping); ((TestUnfuddle)TestItem).TestUpdateStateOfExternalItem(card4, _mapping.LaneToStatesMap[2], _mapping); MockRestClient.Verify(x => x.Execute(It.Is<RestRequest>(y => y.Resource.Contains("tickets/2") && y.Method == Method.GET)), Times.Exactly(3)); MockRestClient.Verify(x => x.Execute(It.Is<RestRequest>(y => y.Resource.Contains("tickets/2") && y.Method == Method.PUT)), Times.Exactly(2)); MockRestClient.Verify(x => x.Execute(It.Is<RestRequest>(y => y.Resource.Contains("tickets/4") && y.Method == Method.GET)), Times.Exactly(2)); MockRestClient.Verify(x => x.Execute(It.Is<RestRequest>(y => y.Resource.Contains("tickets/4") && y.Method == Method.PUT)), Times.Exactly(1)); }
public void AddTaskboardCard(Card card, long taskboardId, string wipOverrideReason) { //var results = string.IsNullOrEmpty(wipOverrideReason) // ? _api.AddTaskboardCard(_boardId, taskboardId, card) // : _api.AddTaskboardCard(_boardId, taskboardId, card, wipOverrideReason); //_boardLock.EnterWriteLock(); //try { // //TODO: Figure out what to do for taskboards // //ApplyBoardChanges(results.BoardVersion, new[] {results.Lane}); //} finally { // _boardLock.ExitWriteLock(); //} }
public void UpdateTask(Card task, long cardId, string wipOverrideReason) { //var results = string.IsNullOrEmpty(wipOverrideReason) // ? _api.UpdateTask(_boardId, cardId, task) // : _api.UpdateTask(_boardId, cardId, task, wipOverrideReason); //TODO: Figure out how to handle taskboards // CardView cardView = results.CardDTO; // Lane lane = _board.GetLaneById(cardView.LaneId); // //TODO: handle the situation where a card in moved through the Update method // // _boardLock.EnterWriteLock(); // try { // lane.UpdateCard(cardView); // ApplyBoardChanges(results.BoardVersion, new[] { lane }); // } // finally { // _boardLock.ExitWriteLock(); // } }
public void AddTask(Card task, long cardId) { AddTask(task, cardId, string.Empty); }
public virtual void UpdateCard(Card card) { UpdateCard(card, string.Empty); }
public virtual void AddCard(Card card) { AddCard(card, string.Empty); }
protected abstract void CardUpdated(Card card, List<string> updatedItems, BoardMapping boardMapping);
public void It_should_not_call_github_to_update_pull_if_externalsystemname_does_not_match() { Card card = new Card() {Id = 4, ExternalSystemName = "GitHubby", ExternalCardID = "4|4"}; ((TestGitHubPulls) TestItem).TestUpdateStateOfExternalItem(card, _mapping.LaneToStatesMap[2], _mapping); MockRestClient.Verify( x => x.Execute(It.Is<RestRequest>(y => y.Resource.Contains("pulls/4") && y.Method == Method.GET)), Times.Never()); MockRestClient.Verify( x => x.Execute(It.Is<RestRequest>(y => y.Resource.Contains("pulls/4") && y.Method == Method.PATCH)), Times.Never()); }
public void It_should_not_call_github_to_update_pull_state_is_already_end_state() { Card card = new Card() {Id = 2, ExternalSystemName = "GitHub", ExternalCardID = "2|2"}; ((TestGitHubPulls) TestItem).TestUpdateStateOfExternalItem(card, _mapping.LaneToStatesMap[2], _mapping); MockRestClient.Verify( x => x.Execute(It.Is<RestRequest>(y => y.Resource.Contains("pulls/2") && y.Method == Method.GET)), Times.Exactly(1)); MockRestClient.Verify( x => x.Execute(It.Is<RestRequest>(y => y.Resource.Contains("pulls/2") && y.Method == Method.PATCH)), Times.Never()); }
public void TestUpdateStateOfExternalItem(Card card, List<string> laneStateMap, BoardMapping boardConfig) { base.UpdateStateOfExternalItem(card, laneStateMap, boardConfig, true); }
public void It_should_not_call_github_to_update_pull_if_externalsystemname_is_different() { Card card = new Card(); card.ExternalCardID = "5|5"; card.ExternalSystemName = "GitHubby"; card.Description = "Pull 5"; card.Title = "Pull 5"; ((TestGitHubPulls) TestItem).TestCardUpdated(card, new List<string>(), _mapping); MockRestClient.Verify( x => x.Execute(It.Is<RestRequest>(y => y.Resource.Contains("pulls/5") && y.Method == Method.GET)), Times.Never()); MockRestClient.Verify( x => x.Execute(It.Is<RestRequest>(y => y.Resource.Contains("pulls/5") && y.Method == Method.PATCH)), Times.Never()); }
public void It_should_not_call_github_to_update_pull_if_no_identified_properties_change() { Card card = new Card(); card.ExternalCardID = "4|4"; card.ExternalSystemName = "GitHub"; card.Description = "Pull 4"; card.Title = "Pull 4"; ((TestGitHubPulls) TestItem).TestCardUpdated(card, new List<string>(), _mapping); MockRestClient.Verify( x => x.Execute(It.Is<RestRequest>(y => y.Resource.Contains("pulls/4") && y.Method == Method.GET)), Times.Exactly(1)); MockRestClient.Verify( x => x.Execute(It.Is<RestRequest>(y => y.Resource.Contains("pulls/4") && y.Method == Method.PATCH)), Times.Never()); }
public void TestCardUpdated(Card card, List<string> updatedItems, BoardMapping boardMapping) { base.CardUpdated(card, updatedItems, boardMapping); }
public void It_should_not_call_unfuddle_to_update_ticket_if_externalstatename_does_not_match() { Card card = new Card() { Id = 5, ExternalSystemName = "Unfuddlest", ExternalCardID = "5" }; ((TestUnfuddle)TestItem).TestUpdateStateOfExternalItem(card, _mapping.LaneToStatesMap[2], _mapping); MockRestClient.Verify(x => x.Execute(It.Is<RestRequest>(y => y.Resource.Contains("tickets/5") && y.Method == Method.GET)), Times.Never()); MockRestClient.Verify(x => x.Execute(It.Is<RestRequest>(y => y.Resource.Contains("tickets/5") && y.Method == Method.PUT)), Times.Never()); }
protected override void CreateNewItem(Card card, BoardMapping boardMapping) { var project = _projectCollectionWorkItemStore.Projects[boardMapping.Identity.TargetName]; var tfsWorkItemType = GetTfsWorkItemType(boardMapping, project.WorkItemTypes, card.TypeId); var workItemType = project.WorkItemTypes[tfsWorkItemType.Name]; // Note: using the default state var workItem = new WorkItem(workItemType) { Title = card.Title, Description = card.Description, }; SetWorkItemPriority(workItem, card.Priority); if (!string.IsNullOrEmpty(card.DueDate)) { if (workItem.Fields.Contains("Due Date")) workItem.Fields["Due Date"].Value = card.DueDate; } if (card.AssignedUserIds != null && card.AssignedUserIds.Any()) { SetAssignedUser(workItem, boardMapping.Identity.LeanKit, card.AssignedUserIds[0]); } if (!string.IsNullOrEmpty(boardMapping.IterationPath)) { workItem.Fields["System.IterationPath"].Value = boardMapping.IterationPath; } try { Log.Debug("Attempting to create Work Item from Card [{0}]", card.Id); workItem.Save(); Log.Debug("Created Work Item [{0}] from Card [{1}]", workItem.Id, card.Id); card.ExternalCardID = workItem.Id.ToString(CultureInfo.InvariantCulture); card.ExternalSystemName = ServiceName; if (_projectHyperlinkService != null) { card.ExternalSystemUrl = _projectHyperlinkService.GetWorkItemEditorUrl(workItem.Id).ToString(); } // now that we've created the work item let's try to set it to any matching state defined by lane var states = boardMapping.LaneToStatesMap[card.LaneId]; if (states != null) { UpdateStateOfExternalItem(card, states, boardMapping, true); } LeanKit.UpdateCard(boardMapping.Identity.LeanKit, card); } catch (ValidationException ex) { Log.Error("Unable to create WorkItem from Card [{0}]. ValidationException: {1}", card.Id, ex.Message); } catch (Exception ex) { Log.Error("Unable to create WorkItem from Card [{0}], Exception: {1}", card.Id, ex.Message); } }
protected abstract void UpdateStateOfExternalItem(Card card, List<string> states, BoardMapping boardMapping);
public void CallWillUpdateCard() { Board board = GetSampleBoard(); _apiMock.Expect(x => x.GetBoard(1)).Return(board); Card cardToUpdate = new Card { Id = 1, Title = "Card 1 Updated", LaneId = 1, Description = "some desc 1", TypeId = 1, ExternalCardID = "123" }; CardUpdateResult result = new CardUpdateResult {BoardVersion = 1, CardDTO = cardToUpdate.ToCardView()}; _apiMock.Expect(x => x.UpdateCard(Arg<long>.Is.Anything, Arg<Card>.Is.Anything)).Return(result); _integration = new LeanKitIntegration(1, _apiMock); _integration.ShouldContinue = false; _integration.StartWatching(); _integration.UpdateCard(cardToUpdate); Card card = _integration.GetCard(1); Assert.NotNull(card); Assert.AreEqual("Card 1 Updated", card.Title); }
protected abstract void CreateNewItem(Card card, BoardMapping boardMapping);
public void CallWillAddCard() { Board board = GetSampleBoard(); _apiMock.Expect(x => x.GetBoard(1)).Return(board); Card cardToAdd = new Card { Id = 1, Title = "Card 1 Updated", LaneId = 1, Description = "some desc 1", TypeId = 1, ExternalCardID = "123" }; Lane affectedLane = new Lane { Id = 1, Title = "Lane 1", Cards = new List<CardView> { new CardView { Id = 1, Title = "Card 1", LaneId = 1, Description = "some desc 1", Type = new CardType {Id = 1, Name = "Card type 1", IconPath = @"C:\"} }, new CardView { Id = 2, Title = "Card 2", LaneId = 1, Description = "some desc 2", Type = new CardType {Id = 1, Name = "Card type 1", IconPath = @"C:\"} }, new CardView { Id = 4, Title = "Card 4", LaneId = 1, Description = "some desc 4", Type = new CardType {Id = 1, Name = "Card type 1", IconPath = @"C:\"} }, }, }; CardAddResult result = new CardAddResult {BoardVersion = 1, CardId = 4, Lane = affectedLane}; _apiMock.Expect(x => x.AddCard(Arg<long>.Is.Anything, Arg<Card>.Is.Anything)).Return(result); _integration = new LeanKitIntegration(1, _apiMock); _integration.ShouldContinue = false; _integration.StartWatching(); _integration.AddCard(cardToAdd); Card card = _integration.GetCard(4); Assert.NotNull(card); Assert.AreEqual("Card 4", card.Title); }
public void AddCard(Card card, string wipOverrideReason) { var results = string.IsNullOrEmpty(wipOverrideReason) ? _api.AddCard(_boardId, card) : _api.AddCard(_boardId, card, wipOverrideReason); _boardLock.EnterWriteLock(); try { ApplyBoardChanges(results.BoardVersion, new[] {results.Lane}); } finally { _boardLock.ExitWriteLock(); } }
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); }
public virtual void UpdateCard(Card card, string wipOverrideReason) { var results = string.IsNullOrEmpty(wipOverrideReason) ? _api.UpdateCard(_boardId, card) : _api.UpdateCard(_boardId, card, wipOverrideReason); var cardView = results.CardDTO; var lane = _board.GetLaneById(cardView.LaneId); //TODO: handle the situation where a card in moved through the Update method _boardLock.EnterWriteLock(); try { lane.UpdateCard(cardView); ApplyBoardChanges(results.BoardVersion, new[] {lane}); } finally { _boardLock.ExitWriteLock(); } }
protected override void UpdateStateOfExternalItem(Card card, List<string> states, BoardMapping boardMapping) { UpdateStateOfExternalItem(card, states, boardMapping, false); }
public void UpdateTask(Card task, long cardId) { UpdateTask(task, cardId, string.Empty); }
protected void UpdateStateOfExternalItem(Card card, List<string> states, BoardMapping mapping, bool runOnlyOnce) { if (!mapping.UpdateTargetItems) return; if (!card.ExternalSystemName.Equals(ServiceName, StringComparison.OrdinalIgnoreCase)) return; if (string.IsNullOrEmpty(card.ExternalCardID)) return; int workItemId; // use external card id to get the TFS work item try { workItemId = Convert.ToInt32(card.ExternalCardID); } catch (Exception) { Log.Debug("Ignoring card [{0}] with missing external id value.", card.Id); return; } if (states == null || states.Count == 0) return; var tries = 0; var success = false; while (tries < 10 && !success && (!runOnlyOnce || tries == 0)) { if (tries > 0) { Log.Warn(String.Format("Attempting to update external work item [{0}] attempt number [{1}]", workItemId, tries)); // wait 5 seconds before trying again Thread.Sleep(new TimeSpan(0, 0, 5)); } Log.Debug("Attempting to retrieve work item [{0}]", workItemId); var workItemToUpdate = _projectCollectionWorkItemStore.GetWorkItem(workItemId); if (workItemToUpdate != null) { var initialState = workItemToUpdate.State; // iterate through the configured states until we find the one that works. // Alternately we could do something with the validation results and check AllowedStates // may be able to figure out the issue and handle it // see http://bartwullems.blogspot.com/2012/04/tf237124-work-item-is-not-ready-to-save.html // according to docs the result should be a collection of Microsoft.TeamFoundation.WorkItemTracking.Client, not sure why it is an ArrayList var ctr = 0; var valid = false; foreach (var st in states) { if (ctr > 0) workItemToUpdate = _projectCollectionWorkItemStore.GetWorkItem(workItemId); var attemptState = st; // Check for a workflow mapping to the closed state if (attemptState.Contains(">")) { var workflowStates = attemptState.Split('>'); // check to see if the workitem is already in one of the workflow states var alreadyInState = workflowStates.FirstOrDefault(x => x.Trim().ToLowerInvariant() == workItemToUpdate.State.ToLowerInvariant()); if (!string.IsNullOrEmpty(alreadyInState)) { // change workflowStates to only use the states after the currently set state var currentIndex = Array.IndexOf(workflowStates, alreadyInState); if (currentIndex < workflowStates.Length - 1) { var updatedWorkflowStates = new List<string>(); for (var i = currentIndex + 1; i < workflowStates.Length; i++) { updatedWorkflowStates.Add(workflowStates[i]); } workflowStates = updatedWorkflowStates.ToArray(); } } // UpdateStateOfExternalItem(card, new List<string>() { workflowState.Trim() }, mapping, runOnlyOnce); if (workflowStates.Length > 0) { // if it is already in the final state then bail if (workItemToUpdate.State.ToLowerInvariant() == workflowStates.Last().ToLowerInvariant()) { Log.Debug("WorkItem [{0}] is already in state [{1}]", workItemId, workItemToUpdate.State); return; } // check to make sure that the first state is valid // if it is then update the work item through the workflow // if not then just process the states from the config file as normal workItemToUpdate.State = workflowStates[0]; // check to see if the work item is already in any of the states // if so then skip those states if (workItemToUpdate.IsValid()) { Log.Debug("Attempting to process WorkItem [{0}] through workflow of [{1}].", workItemId, attemptState); foreach (var workflowState in workflowStates) { UpdateStateOfExternalItem(card, new List<string> {workflowState.Trim()}, mapping, runOnlyOnce); } // Get the work item again and check the current state. // if it is not in the last state of the workflow then something went wrong // so reverse the updates we made and it will then try the next configuration workflow if there is one var updatedWorkItem = _projectCollectionWorkItemStore.GetWorkItem(workItemId); if (updatedWorkItem != null) { if (updatedWorkItem.State.ToLowerInvariant() == workflowStates.Last().ToLowerInvariant()) { return; } // try to reverse the changes we've made Log.Debug("Attempted invalid workflow for WorkItem [{0}]. Attempting to reverse previous state changes.", workItemId); foreach (var workflowState in workflowStates.Reverse().Skip(1)) { UpdateStateOfExternalItem(card, new List<string> {workflowState.Trim()}, mapping, runOnlyOnce); } // now try to set it back whatever it was before Log.Debug("Attempted invalid workflow for WorkItem [{0}]. Setting state back to initial state of [{1}].", workItemId, initialState); UpdateStateOfExternalItem(card, new List<string> {initialState.Trim()}, mapping, runOnlyOnce ); // set the current attempt to empty string so that it will not be valid and // we'll try the next state (or workflow) attemptState = ""; } } } } if (workItemToUpdate.State.Equals(attemptState, StringComparison.InvariantCultureIgnoreCase)) { Log.Debug(string.Format("WorkItem [{0}] is already in state [{1}]", workItemId, workItemToUpdate.State)); return; } if (!string.IsNullOrEmpty(attemptState)) { workItemToUpdate.State = attemptState; valid = workItemToUpdate.IsValid(); } ctr++; if (valid) break; } if (!valid) { Log.Warn("Unable to update WorkItem [{0}] to [{1}] because the state is invalid from the current state.", workItemId, workItemToUpdate.State); return; } try { workItemToUpdate.Save(); success = true; Log.Debug("Updated state for mapped WorkItem [{0}] to [{1}]", workItemId, workItemToUpdate.State); } catch (ValidationException ex) { Log.Warn("Unable to update WorkItem [{0}] to [{1}], ValidationException: {2}", workItemId, workItemToUpdate.State, ex.Message); } catch (Exception ex) { Log.Error(ex, string.Format("Unable to update WorkItem [{0}] to [{1}]", workItemId, workItemToUpdate.State)); } } else { Log.Debug("Could not retrieve WorkItem [{0}] for updating state to [{1}]", workItemId, workItemToUpdate.State); } tries++; } }
public void AddTaskboardCard(Card card, long taskboardId) { AddTaskboardCard(card, taskboardId, string.Empty); }
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"); } } }
public void UpdateTaskboardCard(Card card, long taskboardId) { UpdateTaskboardCard(card, taskboardId, string.Empty); }
protected override void CardUpdated(Card card, List<string> updatedItems, BoardMapping boardMapping) { if (!card.ExternalSystemName.Equals(ServiceName, StringComparison.OrdinalIgnoreCase)) return; if (string.IsNullOrEmpty(card.ExternalCardID)) return; Log.Info("Card [{0}] updated.", card.Id); int workItemId; try { workItemId = Convert.ToInt32(card.ExternalCardID); } catch (Exception) { Log.Debug("Ignoring card [{0}] with missing external id value.", card.Id); return; } Log.Debug("Attempting to load Work Item [{0}]", workItemId); WorkItem workItem; try { workItem = _projectCollectionWorkItemStore.GetWorkItem(workItemId); } catch (Exception ex) { Log.Error(ex, string.Format("Could not load Work Item [{0}]", workItemId)); return; } if (workItem == null) { Log.Debug("Failed to find work item matching [{0}].", workItemId); return; } if (updatedItems.Contains("Title") && workItem.Title != card.Title) workItem.Title = card.Title; if (updatedItems.Contains("Description")) { var description = workItem.LeanKitDescription(GetTfsVersion()); if (description != card.Description) { if (workItem.UseReproSteps()) workItem.Fields["Repro Steps"].Value = card.Description; else workItem.Description = card.Description; } } if (updatedItems.Contains("Priority")) { var currentWorkItemPriority = workItem.LeanKitPriority(); if (currentWorkItemPriority != card.Priority) SetWorkItemPriority(workItem, card.Priority); } if (updatedItems.Contains("DueDate")) { SetDueDate(workItem, card.DueDate); } if (workItem.IsDirty) { Log.Info("Updating corresponding work item [{0}]", workItem.Id); workItem.Save(); } // unsupported properties; append changes to history if (updatedItems.Contains("Size")) { workItem.History += "Card size changed to " + card.Size + "\r"; workItem.Save(); } if (updatedItems.Contains("Blocked")) { if (card.IsBlocked) workItem.History += "Card is blocked: " + card.BlockReason + "\r"; else workItem.History += "Card is no longer blocked: " + card.BlockReason + "\r"; workItem.Save(); } if (updatedItems.Contains("Tags")) { workItem.History += "Tags in LeanKit changed to " + card.Tags + "\r"; workItem.Save(); } }