Copy TFS queries between iterations

In an old post I spoke about a simple routine to copy queries between iterations in TFS, now it is time to show the code, behind this simple command.

Everything is really simple, the first step is creating a connection with the TFS server and retrieve a reference to QueryHierarchy object

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
string userName = GetParameterValue<String>("user");
string password = GetParameterValue<String>("pwd");
TfsTeamProjectCollection tfs =
new TfsTeamProjectCollection(new Uri(GetParameterValue<String>("collection")),
new NetworkCredential(userName, password));
 
 
string projectName = GetParameterValue<String>("teamproject");
WorkItemStore store = (WorkItemStore) tfs.GetService<WorkItemStore>();
string iterationsource = GetParameterValue<String>("iterationsource");
QueryHierarchy queryHierarchy = store.Projects[projectName].QueryHierarchy;

The code is really simple, just create a TfsTeamProjectCollection, pass the url of the collection as well as network credential and the connection to the TFS is done. Now I recover projectName from the command line parameters, and grab a reference to a WorkItemStore object thanks to the well known GetService() method of the TfsTeamProjectCollection object.

After I got a reference to the WorkItemStore I can finally grab a reference to QueryHierarchy object  (line 11) from the WorkItemStore object, passing the name of the team project you want to handle.

Since the query structure of TFS is a tree, I need to build a function that iterate in all the node of the tree to find the source iteration and the destination iteration.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private QueryFolder Search(QueryHierarchy hierarchy, String name)
{
foreach (QueryFolder queryFolder in hierarchy)
{
var result = Search(queryFolder, name);
if (result != null) return result;
}
return null;
}
private QueryFolder Search(QueryFolder hierarchy, String name)
{
foreach (QueryItem queryFolder in hierarchy)
{
QueryFolder folder = queryFolder as QueryFolder;
if (folder == null) continue;
if (name.Equals(folder.Name, StringComparison.OrdinalIgnoreCase))
return folder;
var result = Search(folder, name);
if (result != null)
return result;
}
return null;
}

The code is really simple, the entry point Search method accepts a QueryHierarchy object and the name of the iteration to search, it simply iterates in all the QueryItem contained in the hierarchy, and for each one it checks the type, and if it a QueryFolder, it calls a recursive function. Everything is based on the fact that a QueryFolder implements the IEnumerable<QueryItem> interface, that permits to iterate in all child nodes, of type QueryItem. During the loop, since I’am searching for an Iteration folder, I need to verify if the QueryItem is a QueryFolder object, if not I simply skip that element and move to the next one with a  continue. If a QueryFolder with the desidered name is found, simply returns it to the caller.

Thanks to this function in the main flow of execution I can simply search for the two iteration folder, and then duplicate all the queries.

1
2
3
4
5
var qj = Search(queryHierarchy, iterationsource);
string iterationdest = GetParameterValue<String>("iterationdest");
var qd = Search(queryHierarchy, iterationdest);
Duplicate(qj, qd, iterationsource, iterationdest);
queryHierarchy.Save();

Line 5 calls the method Save() of the queryHierarchy item, because all the modification you can do to this object are held in memory until you explicitly save to the TFS server. Now lets examine the Duplicate() method that does all the work.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
private void Duplicate(QueryFolder qj, QueryFolder qd, string iterationsource, string iterationdest)
{
foreach (QueryItem item in qj)
{
if (item is QueryFolder)
{
QueryFolder queryFolder = new QueryFolder(item.Name);
qd.Add(queryFolder);
Duplicate(item as QueryFolder, queryFolder, iterationsource, iterationdest);
}
else if (item is QueryDefinition)
{
if (qd.Contains(item.Name)) continue;
 
QueryDefinition def = item as QueryDefinition;
string queryText = def.QueryText.Replace(iterationsource, iterationdest);
QueryDefinition queryDefinition = new QueryDefinition(def.Name, queryText);
qd.Add(queryDefinition);
}
}
}

Thanks to TFS API the code is really really simple, it accepts the source and destination QueryFolder, as well as the name of the source iteration and the destination iteration.

The code simply iterate in all QueryItem, if it is a QueryFolder I create a QueryFolder with the same name on destination node, and I recursively call the Duplicate function. If the QueryItem is a QueryDefinition object (the actual query that you find in TeamExplorer) it sould be duplicated. First of all I check if the destination folder already contains a QueryItem with the same name, (to avoid error for conflicting names), then I create a copy of the QueryDefinition, replacing the name of the old iteration with the new one. This is possible because the query is a simple text, that can be handled with the standard string functions.

Thanks to few lines of code you are able to duplicate query definition, changing at the same time the Query Text to make copies point to the new iteration.

Alk.