2009-11-17 2 views
1

Я разрабатываю приложение Windows, которое выполняет некоторые общие задачи TFS с использованием API бета-версии 2010 года (например, создание новых командных проектов, новых рабочих элементов, выборочной сборки и т. Д.).Рабочие процессы перехода состояний рабочего элемента

В процессе редактирования существующих рабочих элементов я должен иметь возможность автоматически устанавливать значения поля «Причина» в соответствии с изменением состояния WI (имитационная Visual Studio). (например). Когда я редактирую ошибку, когда состояние изменяется с Активного на Разрешенное, причина по умолчанию «Исправлена» и аналогично по умолчанию Reason = «Отложенная», когда состояние переходит из Активного в Закрытое. (Как определено в XML-файле определения типа рабочего элемента.) Этот переход легко захватывается и реализуется внутри простого обработчика событий в форме, так как начальное состояние будет активным, когда ошибка будет отредактирована впервые.

Я хочу знать, как реализовать оставшиеся переходы, такие как «Разрешено к закрытию» («Причина = Исправлено»), «Разрешено к активному» («Причина = Тест не выполнен/Не исправлен») или «Закрыто до Активного» (Причина = Реактивированная/Регрессия).

Я знаю, что существует метод WorkItem.GetNextState (current_state, action), но это не помогает, поскольку для этого требуется определенное действие.

То, что я сделал до сих пор показано ниже:

void cmbBugState_SelectedIndexChanged(object sender, EventArgs e) 
    { 
     //private enum bugWorkFlows{"Fixed","Deferred","Duplicate","As Designed","Cannot Reproduce","Obsolete","Test Failed","Not Fixed","Reactivated","Regression"} 
     string[] activeToResolvedReasons = { "Fixed", "Deferred", "Duplicate", "As Designed", "Cannot Reproduce", "Obsolete" }; 
     string[] resolvedToActiveReasons = { "Test Failed", "Not fixed" }; 
     string[] resolvedToClosedReasons = activeToResolvedReasons; 
     string[] closedToActiveReasons = { "Reactivated", "Regression" }; 
     string[] activeToClosedReasons = activeToResolvedReasons; 

     cmbBugReason.Items.AddRange(activeToResolvedReasons); 
     // Set the default reason according to change of state of the work item. 
     if (cmbBugState.SelectedItem.ToString() == "Resolved") 
     { 
      cmbBugReason.Enabled = true; 
      cmbBugReason.SelectedItem = activeToResolvedReasons[0]; 
     } 
     if (cmbBugState.SelectedItem.ToString() == "Closed") 
     { 
      cmbBugReason.Enabled = true; 
      cmbBugReason.SelectedItem = activeToResolvedReasons[1]; 
     } 
    } 

Может кто-нибудь показать, как обрабатывать эти события на форме?

Thanks, Tara.

ответ

1

Я пробовал GetNextState. Он никогда не был достаточно надежным для того, что мне было нужно.

Таким образом, я «перевернул свой» код перехода штата, который работал очень хорошо для меня, когда я перехожу из состояния «А» в состояние «В». Это немного длиннее, но в нем должно быть то, что вы ищете.

В качестве побочного примечания: поскольку этот метод не использует метод GetNextState, он должен каким-то образом получить следующее состояние. То, как это делается, - это загрузить XML соответствующего типа рабочего элемента. Он анализирует это и использует его для создания списка перехода (_ allTransistions).

Уровни разрешений в TFS 2010 необходимо сделать следующие: Администраторы Team Foundation или Администраторы проекта. (В качестве примечания, в TFS 2008 и 2005 все действительные пользователи могли это сделать.)

Полный код, который использует это, можно найти в файле WorkItemHelpers.cs в проекте TFS Aggregator на codeplex.

public static void TransitionToState(this WorkItem workItem, string state, string commentPrefix) 
{ 
    // Set the sourceWorkItem's state so that it is clear that it has been moved. 
    string originalState = (string)workItem.Fields["State"].Value; 

    // Try to set the state of the source work item to the "Deleted/Moved" state (whatever is defined in the file). 

    // We need an open work item to set the state 
    workItem.TryOpen(); 

    // See if we can go directly to the planned state. 
    workItem.Fields["State"].Value = state; 


    if (workItem.Fields["State"].Status != FieldStatus.Valid) 
    { 
     // Revert back to the orginal value and start searching for a way to our "MovedState" 
     workItem.Fields["State"].Value = workItem.Fields["State"].OriginalValue; 

     // If we can't then try to go from the current state to another state. Saving each time till we get to where we are going. 
     foreach (string curState in workItem.Type.FindNextState((string)workItem.Fields["State"].Value, state)) 
     { 
      string comment; 
      if (curState == state) 
       comment = commentPrefix + Environment.NewLine + " State changed to " + state; 
      else 
       comment = commentPrefix + Environment.NewLine + " State changed to " + curState + " as part of move toward a state of " + state; 

      bool success = ChangeWorkItemState(workItem, originalState, curState, comment); 
      // If we could not do the incremental state change then we are done. We will have to go back to the orginal... 
      if (!success) 
       break; 
     } 
    } 
    else 
    { 
     // Just save it off if we can. 
     string comment = commentPrefix + "\n State changed to " + state; 
     ChangeWorkItemState(workItem, originalState, state, comment); 

    } 
} 
private static bool ChangeWorkItemState(this WorkItem workItem, string orginalSourceState, string destState, String comment) 
{ 
    // Try to save the new state. If that fails then we also go back to the orginal state. 
    try 
    { 
     workItem.TryOpen(); 
     workItem.Fields["State"].Value = destState; 
     workItem.History = comment; 
     workItem.Save(); 
     return true; 
    } 
    catch (Exception) 
    { 
     // Revert back to the original value. 
     workItem.Fields["State"].Value = orginalSourceState; 
     return false; 
    } 
} 

/// <summary> 
/// Used to find the next state on our way to a destination state. 
/// (Meaning if we are going from a "Not-Started" to a "Done" state, 
/// we usually have to hit a "in progress" state first. 
/// </summary> 
/// <param name="wiType"></param> 
/// <param name="fromState"></param> 
/// <param name="toState"></param> 
/// <returns></returns> 
public static IEnumerable<string> FindNextState(this WorkItemType wiType, string fromState, string toState) 
{ 
    var map = new Dictionary<string, string>(); 
    var edges = wiType.GetTransitions().ToDictionary(i => i.From, i => i.To); 
    var q = new Queue<string>(); 
    map.Add(fromState, null); 
    q.Enqueue(fromState); 
    while (q.Count > 0) 
    { 
     var current = q.Dequeue(); 
     foreach (var s in edges[current]) 
     { 
      if (!map.ContainsKey(s)) 
      { 
       map.Add(s, current); 
       if (s == toState) 
       { 
        var result = new Stack<string>(); 
        var thisNode = s; 
        do 
        { 
         result.Push(thisNode); 
         thisNode = map[thisNode]; 
        } while (thisNode != fromState); 
        while (result.Count > 0) 
         yield return result.Pop(); 
        yield break; 
       } 
       q.Enqueue(s); 
      } 
     } 
    } 
    // no path exists 
} 

private static readonly Dictionary<WorkItemType, List<Transition>> _allTransistions = new Dictionary<WorkItemType, List<Transition>>(); 

/// <summary> 
/// Deprecated 
/// Get the transitions for this <see cref="WorkItemType"/> 
/// </summary> 
/// <param name="workItemType"></param> 
/// <returns></returns> 
public static List<Transition> GetTransitions(this WorkItemType workItemType) 
{ 
    List<Transition> currentTransistions; 

    // See if this WorkItemType has already had it's transistions figured out. 
    _allTransistions.TryGetValue(workItemType, out currentTransistions); 
    if (currentTransistions != null) 
     return currentTransistions; 

    // Get this worktype type as xml 
    XmlDocument workItemTypeXml = workItemType.Export(false); 

    // Create a dictionary to allow us to look up the "to" state using a "from" state. 
    var newTransistions = new List<Transition>(); 

    // get the transistions node. 
    XmlNodeList transitionsList = workItemTypeXml.GetElementsByTagName("TRANSITIONS"); 

    // As there is only one transistions item we can just get the first 
    XmlNode transitions = transitionsList[0]; 

    // Iterate all the transitions 
    foreach (XmlNode transitionXML in transitions) 
    { 
     // See if we have this from state already. 
     string fromState = transitionXML.Attributes["from"].Value; 
     Transition transition = newTransistions.Find(trans => trans.From == fromState); 
     if (transition != null) 
     { 
      transition.To.Add(transitionXML.Attributes["to"].Value); 
     } 
     // If we could not find this state already then add it. 
     else 
     { 
      // save off the transistion (from first so we can look up state progression. 
      newTransistions.Add(new Transition 
      { 
       From = transitionXML.Attributes["from"].Value, 
       To = new List<string> { transitionXML.Attributes["to"].Value } 
      }); 
     } 
    } 

    // Save off this transition so we don't do it again if it is needed. 
    _allTransistions.Add(workItemType, newTransistions); 

    return newTransistions; 
} 
Смежные вопросы