If you are like me doing code review all the time using TFS, you would like to have a tool, by which you enter a work item number, the tool will provide you with a list of files, and for each of the files, it offers a list of changeset number.
Well, out-of-box TFS explorer does not offer the tool I am draming of. However, TFS does provide a very rich set of of API, by which you can write the tool yourself.
This is how I did:
1) Started my solution with a class libarary project with the language you like ( I selected C#). Name it in the way you want it, (I named it as TFSAdapter).
2) Add referecne to the following assembilies:
a. Microsoft.TeamFoundation.Client
b. Microsoft.TeamFoundation.Common
c. Microsoft.TeamFoundation.VersionControl.Client
d. Microsoft.TeamFoundation.WorkItemTracking.Client
3) Rename the class1.cs to a meaningful name, ( I named it as WorkItemAgent)
4) Add a small entity class to the project
public class FileTouched
{
public string FileName { get; set;}
public List<int> ChangeSets { get; set; }
public FileTouched()
{
ChangeSets = new List<int>();
}
public FileTouched(string fileName) : this()
{
FileName = fileName;
}
}
5) Add following private variables to the WorkItemAgent class:
private Uri collectionUri;
private TfsTeamProjectCollection projectCollection;
private WorkItemStore workItemStore;
private VersionControlServer vcs;
6) Add a constrcutor as following:
public WorkItemAgent(string tfsServerUrl )
{
collectionUri = new Uri(tfsServerUrl);
projectCollection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(collectionUri);
vcs = (VersionControlServer)projectCollection.GetService(typeof(VersionControlServer));
workItemStore = projectCollection.GetService<WorkItemStore>();
}
7) Add first private method, named GetWorkItem
public WorkItem GetWorkItem(int workItemNumber)
{
return workItemStore.GetWorkItem(workItemNumber);
}
8) Add another private method GetChangeSets
public List<Changeset> GetChangeSets(WorkItem workitem)
{
List<Changeset> associatedChangesets = new List<Changeset>();
ExternalLink extLink ;
foreach (Link link in workitem.Links)
{
if (link.BaseType == BaseLinkType.ExternalLink)
{
extLink = link as ExternalLink;
if (extLink != null)
{
ArtifactId artifact = LinkingUtilities.DecodeUri(extLink.LinkedArtifactUri);
if (String.Equals(artifact.ArtifactType, "Changeset", StringComparison.Ordinal))
{
associatedChangesets.Add(vcs.ArtifactProvider.GetChangeset(new Uri(extLink.LinkedArtifactUri)));
}
}
}
}
return associatedChangesets;
}
9) Add last private method GetFilesAssociatedWithChangeSet
public List<string> GetFilesAssociatedWithChangeSet(Changeset changeSet)
{
List<string> files = new List<string>();
foreach (var changedItem in changeSet.Changes)
{
string item = changedItem.Item.ServerItem;
if (!files.Contains(item))
{
files.Add(item);
}
}
return files;
}
10) Now, we have done enough ground work, let’s add a a public method named GetFileList as following:
public List<FileTouched> GetFileList(int workItemNumber)
{
Dictionary<string, FileTouched> result = new Dictionary<string, FileTouched>();
WorkItem myWorkitem = this.GetWorkItem(workItemNumber);
List<Changeset> ChangeSets = this.GetChangeSets(myWorkitem);
List<string> filelist;
foreach (Changeset cs in ChangeSets)
{
filelist = GetFilesAssociatedWithChangeSet(cs);
foreach (string fileName in filelist)
{
if (!result.ContainsKey(fileName))
{
result.Add(fileName, new FileTouched(fileName));
}
result[fileName].ChangeSets.Add(cs.ChangesetId);
}
}
List<FileTouched> listResult = new List<FileTouched>();
foreach (string key in result.Keys)
{
listResult.Add(result[key]);
}
var sortedresult = from file in listResult orderby file.ChangeSets.Count select file;
return sortedresult.ToList();
}
11) If you like me is a big fun of unit testing, you wouild add a test project to test these methods, let me show you one of the test cases I have made:
[TestMethod()]
public void GetFileListTest()
{
WorkItemAgent target = new WorkItemAgent(“the URL for the TFS Server”); // something like http://newtoy:8080/tfs/defaultcollection
int workItemNumber = 77675; // TODO: the work item number you have to an appropriate value
List<FileTouched> actual;
actual = target.GetFileList(workItemNumber);
foreach (FileTouched file in actual)
{
Console.WriteLine(file.FileName);
foreach (int cs in file.ChangeSets)
{
Console.Write(cs.ToString() + ",");
}
Console.WriteLine();
}
}
No comments:
Post a Comment