我正在尝试扫描曾经在冲刺中的WorkItems
的TFS。
现在通过正常的TFS查询,您可以在Iteration Id
上搜索并使用Was Ever
运算符,但要获取该ID,您必须拥有一个已知的WorkItem
,它已经在某个时间点,当前或在它的历史。
我已经能够在路径是积压或冲刺迭代的地方组装,开始这些迭代的停止日期,而不是ID
理想情况下,我想提供其Guid
或其路径来获取其ID,
但是我无法在哪里获得
目前,我使用以下内容获取迭代树:
public static IterationTreeItem GetIterationTree()
{
var structures = TfsShared.Instance.CommonStructureService.ListStructures(TfsShared.Instance.ProjectInfo.Uri);
var iterationNode = structures.First(_ => _.Name == "Iteration");
var rawIterationTree = TfsShared.Instance.CommonStructureService.GetNodesXml(new[] { iterationNode.Uri }, true);
var iterationTree = rawIterationTree.FirstChild;
var teams = TfsShared.Instance.AllTeams.ToList();
var configs = TfsShared.Instance.TeamSettingsConfigurationService
.GetTeamConfigurations(teams.Select(_ => _.Identity)
.Select(_ => _.TeamFoundationId));
var backLogPaths = configs.Select(_ => _.TeamSettings.BacklogIterationPath)
.OrderBy(_ => _)
.Distinct()
.ToArray();
var fullTree = new IterationTreeItem(iterationTree);
var iterationList = IterationTreeItem.Flatten(fullTree).ToList();
IterationTreeItem.SetBackLogsOrSprints(iterationList, backLogPaths);
return fullTree;
}
我从ICommonStructureServices返回的结构看起来像,但包含更多的团队和冲刺:
<?xml version="1.0" encoding="utf-8"?>
<Nodes xmlns="">
<Node NodeID="vstfs:///Classification/Node/43eaa612-c4b1-4043-bbd6-62f56387a7c8" Name="Iteration" Path="\coresystems\Iteration" ProjectID="vstfs:///Classification/TeamProject/4f1ea3c6-5306-4671-b806-8c2df536d218" StructureType="ProjectLifecycle">
<Children>
<Node NodeID="vstfs:///Classification/Node/6c123a22-c647-489a-a683-ca6a5bb19f92" Name="Team01" ParentID="vstfs:///Classification/Node/43eaa612-c4b1-4043-bbd6-62f56387a7c8" Path="\coresystems\Iteration\Team01" ProjectID="vstfs:///Classification/TeamProject/4f1ea3c6-5306-4671-b806-8c2df536d218" StructureType="ProjectLifecycle">
<Children>
<Node NodeID="vstfs:///Classification/Node/27efc3cf-270f-463b-9aec-1569d7eaec8a" Name="Sprint1" ParentID="vstfs:///Classification/Node/6c123a22-c647-489a-a683-ca6a5bb19f92" Path="\coresystems\Iteration\Team01\Sprint1" ProjectID="vstfs:///Classification/TeamProject/4f1ea3c6-5306-4671-b806-8c2df536d218" StructureType="ProjectLifecycle" />
<Node NodeID="vstfs:///Classification/Node/987b4bae-83ea-4f6f-beba-697ab8bb039f" Name="Sprint2" ParentID="vstfs:///Classification/Node/6c123a22-c647-489a-a683-ca6a5bb19f92" Path="\coresystems\Iteration\Team01\Sprint2" ProjectID="vstfs:///Classification/TeamProject/4f1ea3c6-5306-4671-b806-8c2df536d218" StructureType="ProjectLifecycle" />
</Children>
</Node>
</Children>
</Node>
</Nodes>
现在IterationTreeItem类如下所示:
[DebuggerDisplay("{CleanIterationPath,nq}")]
public class IterationTreeItem
{
private readonly List<IterationTreeItem> _children = new List<IterationTreeItem>();
public IterationTreeItem(XmlNode node)
{
if (node != null)
{
XmlNode = node;
var nodeId = GetNodeId(node);
NodeInfo = TfsShared.Instance.CommonStructureService.GetNode(nodeId);
if (node.FirstChild != null)
{
var children = node.FirstChild.ChildNodes.OfType<XmlNode>()
.Select(_ => new IterationTreeItem(_, this))
.ToArray();
Children.AddRange(children);
}
}
}
private IterationTreeItem(XmlNode node, IterationTreeItem parent)
: this(node)
{
Parent = parent;
}
public List<IterationTreeItem> Children
{
get { return _children; }
}
public string CleanBacklogPath
{
get
{
var parts = CleanIterationPath.Split('\\').ToArray();
return string.Join("\\", parts.Take(Math.Max(parts.Length - 1, 1)));
}
}
public string CleanIterationPath
{
get
{
if (NodeInfo != null)
{
var notStartedWithSlashes = NodeInfo.Path.Substring(1);
return notStartedWithSlashes.Replace("\\Iteration", string.Empty);
}
return string.Empty;
}
}
public bool? IsProductBackLogIteration { get; private set; }
public bool? IsSprintIteration { get; private set; }
public NodeInfo NodeInfo { get; private set; }
public IterationTreeItem Parent { get; private set; }
public XmlNode XmlNode { get; private set; }
public static IEnumerable<IterationTreeItem> Flatten(IterationTreeItem item)
{
yield return item;
foreach (var childChild in item.Children.SelectMany(Flatten))
{
yield return childChild;
}
}
public static void SetBackLogsOrSprints(IEnumerable<IterationTreeItem> items, IEnumerable<string> knownBacklogs)
{
var backLogs = knownBacklogs as List<string> ?? knownBacklogs.ToList();
foreach (var iterationTreeItem in items)
{
if (backLogs.Any(_ => _ == iterationTreeItem.CleanIterationPath))
{
iterationTreeItem.IsProductBackLogIteration = true;
iterationTreeItem.IsSprintIteration = false;
}
else
{
iterationTreeItem.IsProductBackLogIteration = false;
iterationTreeItem.IsSprintIteration = true;
}
}
}
private static string GetNodeId(XmlNode node)
{
if (node.Attributes != null)
{
var otherNodeId = node.Attributes.OfType<XmlAttribute>().First(_ => _.Name == "NodeID").Value;
return otherNodeId;
}
var xml = node.OuterXml;
const string first = "NodeID=\"";
var start = xml.IndexOf(first, StringComparison.Ordinal) + first.Length;
var end = xml.IndexOf("\"", start, StringComparison.Ordinal);
return xml.Substring(start, (end - start));
}
}