Рабочие процессы перехода состояний рабочего элемента - PullRequest
1 голос
/ 17 ноября 2009

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

В процессе редактирования существующих рабочих элементов я должен иметь возможность автоматически устанавливать значения поля «Причина» в соответствии с изменением состояния WI (имитируя Visual Studio). (например) - Когда я редактирую ошибку, когда состояние изменяется с Активного на Разрешенное, Причиной по умолчанию является «Фиксированный» и аналогично Причиной по умолчанию = «Отложенный», когда состояние переходит из Активного в Закрытое. (Как определено в 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];
        }
    }

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

Спасибо, Тара.

1 Ответ

1 голос
/ 02 марта 2011

Я пробовал 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...