Frankenstein’s Custom Task: A RoboCopy Custom Task for Team Build

I was recently working at a client on a TFS implementation.  They had been using TFS for a few months and had some cycles invested in their build process.  As part of the process, they  needed to deploy the compiled web sites out to a development test server so that they could review the code with their BAs prior to calling the Story complete.  They also had a requirement that they be able to have an indication that the deployment step was occurring during the build (in the Build Status page).

Their Team Build was constructed using the task to call RoboCopy to do an “sync” between the drop folder and the deployment folder on the target web server.  Unfortunately, every time they ran this task the build broke.  It seems that RoboCopy doesn’t follow the standard rules of command-line apps.  The standard rule is “Return code is 0 on success and anything else denotes an error condition”. 

RoboCopy returns the following codes (from the RoboCopy documentation):

Hex Bit ValueDecimal ValueMeaning If Set
0x1016Serious error. RoboCopy did not copy any files. This is either a usage error or an error due to insufficient access privileges on the source or destination directories.
0x088Some files or directories could not be copied (copy errors occurred and the retry limit was exceeded). Check these errors further.
0x04

4

Some Mismatched files or directories were detected. Examine the output log. Housekeeping is probably necessary.
0x022Some Extra files or directories were detected. Examine the output log. Some housekeeping may be needed.
0x011One or more files were copied successfully (that is, new files have arrived).
0x000No errors occurred, and no copying was done. The source and destination directory trees are completely synchronized.

 

So as you can see, if RoboCopy returns the expected zero for success it really means that “Nothing was done.”  A successful run is actually denoted by any Return Code less than 8.

What’s a consultant to do?  Why I Googled up “MSBuild RoboCopy” and was rewarded with a link to the MSBuild Community Tasks on Tigris.org.  Sweet!  I knew that they had code to do what I wanted, so I grabbed it from their repository (thanks guys).  This code is for a straight MSBuild task and therefore couldn’t talk to Team Build (and by extension TFS). 

To get that functionality, I remembered an article by Aaron Hallberg entitled “Adding BuildSteps to Team Build Through a Custom Task.”  I brought up the article and nabbed that code too.  I also had some code laying around from earlier custom tasks I wrote to wrap command-line tools since I needed to evaluate and correctly interpret RoboCopy Return Code. 

With all of this code in hand I went down to my mad-scientist lab to cobble together the Frankenstein’s Monster of custom tasks, a RoboCopy task that will correctly evaluate the return   code and add a BuildStep to a Team Build. [Evil laugh here]

To make this work I had my RoboCopy task inherit from Aaron’s TeamBuildTask to get me the BuildStep message functionality.  Accordingly, I have to implement the GetBuildStepName, GetBuildStepMessage, and ExecuteInternal methods.  I then stuffed the Tigris.org RoboCopy code into the class to do the hard work of adding the task parameters and grabbing the support methods to correctly build the command line.  Afterward, I filled the ExecuteInternal method with my code that spins up a Process, redirects STDOUT and STDERR into accessible buffers and runs the RoboCopy command using the command line provided by Tigris’ GenerateCommandLineCommands method. 

After the RoboCopy process finishes, I have to evaluate the Return Code from the Process to determine if an actual error occurred.  If one occurred, I write the error (from STDERR) to the MSBuild log file with high importance and return False from the task to let MSBuild know about it.  If the Return Code was less than 8, everything is well so I return True to MSBuild and everything runs as normal.  In either case I write the contents of STDOUT to the MSBuild Log file with low importance. 

I’ve put links below to the solution and binaries.  This custom task could easily be updated to call any command-line tool while logging BuildSteps to the Team Build.  This task will only work under Team Build because it requires a BuildURI and TeamFoundationServerURL parameters but it could be easily modified to remove the Build Steps and work under MSBuild alone.

Let me know what you think…

 

Compiled Assembly is here.

Source Code is here.