2009-11-17 4 views
1

2010 Beta 2 API (예 : 새 팀 프로젝트 만들기, 새로운 작업 항목, 선택 빌드 등)를 사용하여 일반적인 TFS 작업을 수행하는 Windows 앱을 개발 중입니다.작업 항목 상태의 전환 워크 플로

기존 작업 항목을 편집하는 과정에서 WI의 상태 변경 (Visual Studio 모방)에 따라 'Reason'필드의 값을 자동으로 설정할 수 있어야합니다. (예) - 버그를 편집 할 때 Active에서 Resolved로 상태가 변경되면 기본 Reason은 'Fixed'이고 유사하게 상태는 Active에서 Closed로 바뀌면 기본 Reason = 'Deferred'입니다. (작업 항목 형식 정의 xml 파일에 정의 된대로)이 전환은 버그를 처음 편집 할 때 초기 상태가 활성 상태가되므로 양식의 간단한 이벤트 처리기에서 캡처하고 구현하기 쉽습니다.

Resolved to Closed (Reason = Fixed), Resolved to Active (Reason = 테스트 실패/고정되지 않음) 또는 Closed to Active (Reason = Reactivated/Regression)와 같은 나머지 전환을 구현하는 방법을 알고 싶습니다.

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]; 
     } 
    } 

사람이 폼에서 이러한 이벤트를 처리하는 방법을 보여 수 있습니까?

감사합니다. 타라.

답변

1

나는 GetNextState를 시도했다. 내가 필요로하는 것을 충분히 신뢰할 수 없었습니다.

그래서 상태 "A"에서 상태 "B"로 이동할 때 "상태가 전환되었습니다"라는 상태 전환 코드가 나에게 잘 돌아갔습니다. 조금 길지만, 당신이 찾고있는 것이 있어야합니다.

참고 : GetNextState 메서드를 사용하지 않기 때문에 어떻게 든 다음 상태를 가져와야합니다. 이를 수행하는 방법은 해당 작업 항목 유형의 XML을 다운로드하는 것입니다. 그것을 파싱하고이를 사용하여 전환 목록 (_ allTransistions)을 만듭니다.

이렇게하려면 TFS 2010의 사용 권한 수준이 Team Foundation 관리자 또는 프로젝트 관리자입니다. 부수적으로 TFS 2008 및 2005에서는 모든 유효한 사용자가이 작업을 수행 할 수 있습니다.

코드 플렉스의 TFS Aggregator 프로젝트의 WorkItemHelpers.cs 파일에서이 코드를 사용하는 전체 코드를 찾을 수 있습니다.

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; 
} 
관련 문제