Thursday, July 26, 2007

Automating your builds in TFS

In development we consistently try to find ways to make our processes faster and more useful. As for deployment and test builds, Team Foundation Server has made it easy to automate your builds by use of Tasks performed within a build project. Developers can build classes implementing the Microsoft.Sdc.Tasks.TaskBase class (derived from Microsoft.Build.Utilities.Task) which has an overrided method named InternalExecute. As a short example to the powerful uses of this class I will demonstrate writing your own class that will handle executing an external application.

In this demonstration I will be using Micsoft.Sdc.Tasks source project to add my class.

First we need to create a class, I am doing so in the File folder as this pertains to files and System.IO. I will name this class Execute. Add the basic namespaces we will need:

using System;
using System.Xml;
using System.Globalization;
using System.IO;
using Microsoft.Build.Framework;
using System.Collections;
using System.Diagnostics;
public class Execute : TaskBase




We might want to add a property that allows us to
specify if an error occurs to treat it as a warning and move on.
/// <summary>
/// If TRUE any errors will be logged as warnings
/// </summary>
public bool TreatErrorsAsWarnings
{
get { return treatErrorsAsWarnings; }
set { treatErrorsAsWarnings = value; }
}
And of course we need Command Line Arguments:
private string _CommandLineArgs;
public string CommandLineArgs
{
get
{
return _CommandLineArgs;
}
set
{
_CommandLineArgs = value;
}
}
private ITaskItem file;

/// <summary>
/// The file to be Executed
/// </summary>
/// <value>An ITaskItem of file</value>
[Required]
public ITaskItem File
{
get { return this.file; }
set { this.file = value; }
}








Now we need to override the Internal Execute method
so our code is called from the MSBUILD.
/// <summary>
/// Performs the action of this task.
/// </summary>
protected override void InternalExecute()
{
try
{
if (System.IO.File.Exists(File.ItemSpec))
{
// Display the File we are about to execute
base.Log.LogMessage("Executing File - " +
File.ItemSpec + "\rCommand Line Args - "+CommandLineArgs);
// Setup our startup information
ProcessStartInfo psi = new ProcessStartInfo();
string[] args = CommandLineArgs.Split(' ');

// Retrieve the arguments
if (args.Length > 0)
{
args[0] = "\"" + args[0] + "\"";
foreach (string str in args)
{
CommandLineArgs = str + " ";
}

CommandLineArgs = CommandLineArgs.TrimEnd(' ');
}
// Execute
psi.FileName = File.ItemSpec;
psi.Arguments = CommandLineArgs;
Process.Start(psi);
}
else
{
if (!TreatErrorsAsWarnings)
throw new
FileNotFoundException("File does not exists - " + File.ItemSpec);
else
base.Log.LogWarning("File does not exists - " +
File.ItemSpec);
}

}
catch (Exception ex)
{
if (TreatErrorsAsWarnings)
{
Utilities.RethrowUnlessFileIO(ex);
}

this.LogError(File, ex);
    }
}

Now we have a class we can use to execute external files within
our team build. Notice the CommandLineArgs is expecting the
argument to be separated using the standard spacing (CHAR 32).
You can customize this to use commas or semicolons if you like.
Compile the Microsoft.Sdc.Tasks project and copy the dll to your team
server in the location you are keeping your automated build files.
To configure look out for Configuring your Customized Task in this blog.



No comments:

 
Creative Commons License
Blogged Information and Code is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License.