Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / DevOps / TFS

TFS SDK: Workspace Explorer & Statistics

5.00/5 (2 votes)
31 Aug 2011CPOL3 min read 26.9K  
TFS SDK: Workspace Explorer & Statistics
 

The Team Explorer is a wonderful view of the position of your version control in the team foundation server. However, there is no one window of such truth available for the workspace. I am a very active member of the MSDN community and have come across questions on:

  • How do I see a list of all files that are not mapped to TFS but are in my workspace? (Yes, you can use the TFS power tools tfpt.exe /scorch or /treeclean to achieve this.)
  • I would like to see all pending changes in just one folder and not recursively in the subfolders.
  • I would like to analyze my workspace, what file types I have, what is the size of file by type, etc.

There are workarounds available, but because TFS does not provide these features natively, the experience is nothing as compared to browsing server artifacts through Team Explorer.

image

Welcome to Workspace Explorer – A solution using TFS API

  1. Get a list of all workspaces, all workspace and multiple folder mappings under a workspace. I have seen developers map multiple folders under a workspace and then complain it takes too long to do get latest, not all go to the workspace folder mapping to verify for what they are requesting the get latest?
  2. Explorer Style Navigation, along with a column to indicate the pending change type and a column to indicate whether the file in workspace is mapped to version control. When peer reviews are carried using shelve sets, reviewers have new files from the shelve sets left in their workspace.
  3. Workspace Statistics – A chart to break down the files by extension and size, this can be done both at the current directory level or recursively for all files in directory and subdirectories.
  4. Pending Changes – A list of all pending changes, this again can be done both at the current directory level or recursively.
  5. Missing Mappings – A list of all files in the workspace not mapped to the server, this again can be done at the current directory level or recursively.

1. Get all Workspaces Programmatically using TFS API

I have a blog post on workspaces – Get List of user workspace and checked out files programmatically

Add a new ListView and set the property view to ‘Details’. Add the columns you would like to display to the property ‘Columns’.

C#
private void PopulateWorkspaceTracker()
        {
            // Connect to TFS - VersioControlServer service
            var tfs =
                TfsTeamProjectCollectionFactory.GetTeamProjectCollection
		(new Uri("https://tfs2010:8080/defaultcollection"));
            var vcs = tfs.GetService<VersionControlServer>();

            // Get all workspaces for the user on the machine
            var workspaces = vcs.QueryWorkspaces(null, vcs.AuthorizedUser, 
				Environment.MachineName);

            // Clear the ListView control
            lstWorkspaceDetails.Items.Clear();
            ListViewItem.ListViewSubItem[] subItems;
            ListViewItem item = null;

            // For all workspaces add the values to the columns
            foreach (var workspace in workspaces)
            {
                foreach (var wk in workspace.Folders)
                {
                    item = new ListViewItem(workspace.Name, 0);
                    subItems = new[]
                               {
                                   new ListViewItem.ListViewSubItem(item, wk.LocalItem),
                                   new ListViewItem.ListViewSubItem(item, wk.ServerItem), 
                                   new ListViewItem.ListViewSubItem
				(item, workspace.EffectivePermissions.ToString()),
                                   new ListViewItem.ListViewSubItem
				(item, wk.IsCloaked.ToString()),
                                   new ListViewItem.ListViewSubItem
				(item, workspace.OwnerName)
                               };
                    item.SubItems.AddRange(subItems);
                    lstWorkspaceDetails.Items.Add(item);
                }
            }
            lstWorkspaceDetails.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
        }

2. Explorer like Navigation for the Workspace Folders

Well, I have created an explorer style interface using ListView and TreeView controls. Click here for a walkthrough on how to do this.

You can use the code below if do not want to follow the walkthrough at this time.

C#
private void PopulateTreeView(string workspaceName)
{
    // Connect to TFS - VersionControlServer Service
    var tfs =
        TfsTeamProjectCollectionFactory.GetTeamProjectCollection
		(new Uri("https://tfs2010:8080/defaultcollection"));
    var vcs = tfs.GetService<VersionControlServer>();

    // Get the workspace the user has currently selected
    var workspace = vcs.QueryWorkspaces(workspaceName, 
		vcs.AuthorizedUser, Environment.MachineName)[0];
    _workspace = workspace;
    tvWksNavigator.Nodes.Clear();

    // Loop through all folders and get directories and files
    foreach (var folder in workspace.Folders)
    {
        var info = new DirectoryInfo(folder.LocalItem);
        if (info.Exists)
        {
            var rootNode = new TreeNode(info.Name) { Tag = info };
            GetDirectories(info.GetDirectories(), rootNode);
            tvWksNavigator.Nodes.Add(rootNode);
        }
    }
}

// Get directories recursively and add them to the tree view
private static void GetDirectories(IEnumerable<DirectoryInfo> subDirs,
                            TreeNode nodeToAddTo)
{
    TreeNode aNode;
    DirectoryInfo[] subSubDirs;
    foreach (var subDir in subDirs)
    {
        aNode = new TreeNode(subDir.Name, 0, 0);
        aNode.Tag = subDir;
        aNode.ImageKey = "folder";
        subSubDirs = subDir.GetDirectories();

        if (subSubDirs.Length != 0)
        {
            GetDirectories(subSubDirs, aNode);
        }
        nodeToAddTo.Nodes.Add(aNode);
    }
}

3. Check if a File is Pending Change Programmatically using TFS API

Using the method QueryPendingChanges, it is possible to pass a file path and see if the file is pending change, if so, what is lock type, and also get the download details for the file.

C#
var status = _workspace.QueryPendingSets(new[] { new ItemSpec(
                                                    dir.FullName, 
                                                    RecursionType.None) },
                                                    _workspace.Name, vcs.AuthorizedUser, 
					      false);

4. Check if a File in Workspace is Mapped to Version Control using TFS API

Using the method ServerItemExists, it is possible to pass a file path and see if the file has a server mapping.

C#
var isValid =
    _workspace.VersionControlServer.ServerItemExists(
        _workspace.GetServerItemForLocalItem(dir.FullName), ItemType.Any);

 

5. Workspace Statistics

The chart control impressed me, with few customizations, I could easily generate visually attractive graphs to visualize my workspace for files by extension and size. Add a chart control and use the below code. You can also look at the possibilities with chart controls on this interesting MSDN. Read it here.

C#
// Check whether the user has requested all files or files
// in just the selected folder. 
if (cbRecursionType.SelectedItem == "Recursive")
{
    // Use a simple stack to get all directories and files
    while (stack.Count > 0)
    {
        var dir = stack.Pop();

        filesInformation.AddRange(dir.GetFiles("*.*"));

        foreach (var dn in dir.GetDirectories("*.*"))
        {
            stack.Push(dn);
        }
    }    
}
else // current directory
{
    while (stack.Count > 0)
    {
        var dir = stack.Pop();
        filesInformation.AddRange(dir.GetFiles("*.*"));
    }
}

// Get all distinct extensions from all files
var extensions = filesInformation.Select(f => f.Extension).Distinct();
// Group files by extensions
var workspaceStatisticsCollection = extensions.Select(extension => 
					(from fileInfo in filesInformation
                                               where fileInfo.Extension == extension
                                               select new WorkspaceStatistic() 
					{ File = fileInfo }).ToList()).ToList();

// Statistics - chart
var yval = new int[extensions.ToList().Count];
var xval = new string[extensions.ToList().Count];
var count = 0;

// Add points to x and y axis 
foreach (var workspaceStats in workspaceStatisticsCollection)
{
    var extension = extensions.ToArray()[count];
    // Y = File count
    yval[count] = workspaceStats.Count;
    // X = Extensions
    xval[count] = extension;
    count += 1;
}

// Some designing to the chart
Series series1 = chart1.Series[0];
chart1.Series[0].ChartType = SeriesChartType.Bar;
chart1.Series[0]["PointWidth"] = "0.6";
chart1.Series[0].IsValueShownAsLabel = true;
chart1.Series[0]["BarLabelStyle"] = "Center";
chart1.ChartAreas[0].Area3DStyle.Enable3D = true;
chart1.Series[0]["DrawingStyle"] = "Emboss";
chart1.Series[0].Points.DataBindXY(xval, yval);
chart1.Series[0].Name = "FilesByExtension";
chart1.Visible = true;
chart1.DataBind();
lblTotal.Text = String.Format("Total {0} files, compute to {1} bytes", 
					filesInformation.Count,
                              filesInformation.Sum(f => f.Length));

And done! I have a working solution, but I am yet to test various scenarios. I will upload the code to CodePlex once tested (yes, I am a responsible developer). Anyways, if you find this interesting and want a copy of the working solution, please feel free to email me and I’ll be happy to share the code with you.

What do you think, good bad ugly, share your feedback?Image 2

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)