Delete Another User’s Workspace in TFS

I’ve run into this problem several times. A build blows up for some reason and creates an orphaned workspace. Other builds then fail with the message The path […] is already mapped in workspace […].

tfsbuild_alreadymapped

The way that I’ve dealt with this in the past is to simply delete the workspace, which you can do easily enough by using the tf workspace command.

tf workspace /delete someworkspace;somedomain\someuser

When you run the command, you’ll be warned that deleted workspaces cannot be recovered and prompted to confirm.

tfsbuild_reallydeleteworksp

Type “Yes” and the deed is done. Run another build, and you should be good!

 

Filter Pending Changes By Solution in TFS

I just learned about a neat feature in Visual Studio’s Pending Changes window: filter by solution. If you’re viewing pending changes and have a solution open, you can use this toggle button to filter the list of files in your Pending Changes to only files included in that solution. This is a great way to ensure you’re only checking in changes that are related to the task or story that you’re working on when multitasking or managing several works-in-progress.

 

TFS Build Notifications Tool

I just learned about a useful tool for keeping an eye on builds in TFS. The Build Notifications tool can be accessed from the Start menu under Microsoft Visual Studio 2010 > Team Foundation Server Tools.

This tool runs in the task tray. You can configure it with which builds you want to monitor and whether to monitor for just yourself or anyone. You can also configure it to alert you for builds that are queued, started, or finished. With the alerts configured, you’ll receive pop-up notifications each time an event occurs for a monitored build definition.

Double-clicking the icon in the task tray brings up the Build Status window which shows you the last build result for each build being monitored. This is a great way to ensure that builds don’t stay broken for too long.

TFS SDK: Getting Started

TFS is great, but it simply doesn’t do everything I need it to do. My team has a TFS work-item-driven software development life-cycle that depends on having stories organized with tasks of certain activity types performed in a specific order. It’s a difficult process for new team members to internalize, and it requires discipline for even our veteran team members. One of the things that I’ve decided to do to help my team manage this process successfully is to create a custom tool with built in “queues” that will display their work items as they need attention without relying on the developer to manually run different queries and discover items on their own.

And so that brings us to the TFS SDK. I’m going write a series of short posts detailing how to do some simple tasks that can be combined to do very powerful things. One of the simplest and most powerful things you can do with the TFS SDK is run WIQL queries to query work items using a SQL-like syntax.

The first step you need to do is simply to add the TFS SDK references to your project. These are the three I added to my project:

Microsoft.TeamFoundation.Client
Microsoft.TeamFoundation.Common
Microsoft.TeamFoundation.WorkItemTracking.Client

Once you’ve got that, you can build an execute a query with the following block of code:

var tpc = new TfsTeamProjectCollection(new Uri("http://YourTfsServer:8080/tfs/YourCollection"));
var workItemStore = tpc.GetService(); 
var queryResults = workItemStore.Query(@"
    SELECT [System.Id], [System.WorkItemType], [System.Title], [System.AssignedTo], [System.State] 
    FROM WorkItems 
    WHERE [System.AssignedTo] = @me 
    ORDER BY [System.Id]
    ");
foreach (WorkItem wi in queryResults)
{
    Console.WriteLine("{0} | {1}", wi.Fields["State"].Value, wi.Fields["Title"].Value);
}

Bonus tip: you can construct your WIQL query by building it from Visual Studio’s Team Explorer and saving it to file. For my application, I’m storing the WIQL query in my app.config to allow for quick & easy customization.

Undoing Pending Changes from Another User in TFS

From time to time, we run into a situation where a team member leaves or becomes unavailable, but they still have files checked out in TFS. This can be troublesome if they have an exclusive lock on a file, or it can be a housekeeping issue if they have a lot of files checked out everywhere.

If you have rights, there is a relatively simple way to undo changes from another user to clean-up a bit.

First, you need to know the name of the user’s workspace(s). You can do this by running the following command:

tf workspaces /owner:"username" /server:http://tfsserver:8080/collection

Then, to undo all pending changes from a particular workspace, run this command:

tf undo /workspace:"WORKSPACE;username" /server:http://tfsserver:8080/collection /recursive "$/teamproject"

If successful, you should receive a message like this:

The operation completed successfully.  Because the workspace xxxx;xxxxxxxx is not on this computer, you must perform a separate get operation in that workspace to update it with the changes that have been made on the server.

Reference: here.

Clean TFS Workspaces with Scorch & Treeclean

If you’ve been working with a TFS workspace for a long time, you know it can get filled up with all kinds of built objects and temporary files. There’s a super-easy way to clean-up using the TFS PowerTools, though.

Check out these two commands:

  • tfpt scorch – Ensure source control and the local disk are identical
  • tfpt treeclean – Delete files and folders not under version control

(Taken from this MSDN forum post.)

7/2/2013 Update:
A co-worker and I were reviewing the scorch command and whether or not pending changes will be deleted through its use. That concern is addressed directly in the help text for the command, accessed by running tfpt scorch /? from the command prompt. Note the last line in the excerpt below, highlighted in red.

Items not in source control will be deleted from disk, just as with the tfpt treeclean command. Items determined to be different on disk from the workspace version will be redownloaded from the server. Items missing on disk will also be redownloaded. Items with pending changes are exempted.

So, it is safe to use scorch while you have pending changes; they will simply be ignored.

Private Builds in TFS

My team has configured TFS to automatically kick-off continuous integration (CI) builds when developers check-in changes. The build depends on the affected area, and the time to complete depends on the build. Some of our builds contains hundreds of projects and thousands of unit tests, and these can take the better part of an hour to complete. We also have nightly builds that build even more and take even longer.

Occasionally, I’ll have some changes to check-in at the end of the day. I check them in, and I get a notification that I broke the build when I’m halfway home. Crap. I need to fix the change before the nightly build starts, or it’s going to break, too.

Wouldn’t it be great if there was a way to run a build with my pending changes and then check them in automatically if the build succeeds? Well… There is! TFS has support for private builds (or “buddy builds”) that you can queue with a shelveset.

When I choose to queue a build, I choose to build with local sources plus a shelveset. Then I specify which shelveset, and I have the option to check-in my changes if the build succeeds. Splendid!

Move Shelvesets Between Branches in TFS

At my company, we do a lot of concurrent development between a number of branches. It’s not uncommon for a change made in one branch to be needed in another branch. TFS Power Tools includes functionality to help you quickly and easily migrate a shelveset from one branch into another.

The usage is simple, too. Go to the command-line and type the following (make sure you run it from a directory mapped to a workspace):

tfpt unshelve "My Shelveset" /migrate /source:$/SourceBranch /target:$/TargetBranch

When you run the command, it will load the changes stored in the shelveset into the specified target branch. Super!

Mass find & replace in TFS using Powershell

One of the problems that seems to come up semi-frequently is, “We need to update all x files to have y!” The old solution to this was manually going through all x files and updating them to have y. However, this can be accomplished quickly and easily using Powershell.
Here’s an example. We had a number of VB6 project files whose BCO paths were set to use a mapped “O:” drive that no longer existed. Instead, these projects should be using a relative path. There were 100 or so of these projects that needed to be updated, and I was able to check them out from TFS and make the change to all of them in a matter of seconds by using the following script (sorry for the formatting!):

Get-ChildItem "C:\Code" -recurse | 
    Where-Object {$_.Extension -eq ".vbp"} | 
    ForEach-Object {Write-Host "  "$_.FullName; & "C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\TF.exe" checkout "$($_.FullName)" | Out-Null; (Get-Content $_.FullName) | 
        ForEach-Object {$_ -replace "O:\\.*?\\BCO\\", "..\..\BCO\"} | 
            Set-Content $_.FullName -Force}

And another example. I needed to update the revision numbers of all projects in a sub-directory to be automatic. Here’s the same script modified to accomplish that. I’ve made this more re-usable by accepting parameter values from the command line.

# example usage: .\UpdateVersion.ps1 -path "C:\Code" -build "1.0.0.*"

# get param values
param(
  [int] $build, 
  [string] $path, 
  [string] $root)


if ($build -eq $null)
{
    $build = Read-Host "Build number:"
}
if ($path -eq $null)
{
    $path = ".\"
}

# $root will be trimmed from start of directory string
# when checking for exceptions
if ($root -eq $null)
{
    $root = "c:\"
}


# $exceptionDirs will not have their versions updated
$exceptionDirs = "test"

Write-Host "Updated the following files:"

# recursively search $path for AssemblyInfo.cs
# if found, update version number & save
Get-ChildItem $path -recurse | 
    Where-Object {$_.Name -eq "AssemblyInfo.cs"} | 
    Where-Object {$exceptionDirs -notcontains $_.Directory.ToString().ToUpper().TrimStart($root.ToUpper())} |
    ForEach-Object {Write-Host "  "$_.FullName; & "C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\TF.exe" checkout "$($_.FullName)"; (Get-Content $_.FullName) | 
        ForEach-Object {$_ -replace "(?(\d+\.){3})\d+", "`${ver}$build"} | 
            Set-Content $_.FullName -Force}

❤ Powershell!

Link TFS Work Items Programmatically

One of the things that’s bothered me with TFS is the need to manually link Sprint Backlog Items to Product Backlog Items. During sprint planning meetings, we use Excel to quickly create lots of sprint backlog items for everybody on the team, but then we need to go through and manually create links to related product backlog items that we use for release planning and release progress tracking.

I decided to do a little research and found that TFS work items can be linked programmatically by utilizing the Visual Studio SDK’s TeamFoundation libraries. I use a TFPT command-line wiql query to find potential link candidates, then parse work item titles for a common number than can be used to find related work items. I do another wiql query to search for the work item ID of the related product backlog item. If found, I attempt to create a link between the two work items.

Here’s the relevant code:

TeamFoundationServer tfs = TeamFoundationServerFactory.GetServer("mytfs");
WorkItemStore store = (WorkItemStore)tfs.GetService(typeof(WorkItemStore));
 
WorkItem sbiWorkItem = store.GetWorkItem(sbiId);
 
try
{
    sbiWorkItem.Links.Add(new RelatedLink(pbiId));
    sbiWorkItem.Save();
    Console.WriteLine(string.Format("Linked SBI {0} to PBI {1}", sbiId, pbiId));
}
catch (Exception ex)
{
    // ignore "duplicate link" errors
    if (!ex.Message.StartsWith("TF26181"))
        Console.WriteLine("ex: " + ex.Message);
}

Resources:
Visual Studio 2008 SDK v1.1
http://download.microsoft.com/download/c/2/0/c20073e0-c842-44a8-a4e9-7dd5d289eafe/VsSDK_sfx.exe