- | rssFeed | My book on MSBuild and Team Build | Archives and Categories Tuesday, December 09, 2008

My MSBuild Video on Channel 9

This past weekend I gave a presentation on MSBuild at the Tampa Code Camp, which I'm glad to say went very well. Besides that I met Brian Johnson from Microsoft. He shot a video of me discussion using MSBuild and Web Deployment Projects to automate deployment of Web Projects. You can see the video at http://channel9.msdn.com/posts/brianjo/Sayed-Hashimi-on-MS-Build/

Let me know what you think, I'm pretty excited because this is my first Channel 9 video.

The sample demonstrated here was inspired by some content that can be found in my new book Inside the Microsoft Build Engine. The book will be published the beginning of January, please buy several copies! I will post more detailed information about the book soon, but we have completed working on it.


Sayed Ibrahim Hashimi

msbuild | Channel9 | Video Tuesday, December 09, 2008 5:09:44 AM (GMT Standard Time, UTC+00:00)  #     | 
Friday, December 05, 2008

Speaking at Tampa Code Camp

I am not sure why but for some reason I always manage to post these messages at the last minute, sorry for that. I will be speaking at the Tampa Code Camp on Saturday December 6. We will cover various features of MSBuild. If you are in the area, and interested in MSBuild, please come check out my presentation.

 

Sayed Ibrahim Hashimi

msbuild | Presentations Friday, December 05, 2008 5:35:58 AM (GMT Standard Time, UTC+00:00)  #     | 
Monday, November 10, 2008

Team Build - Creating Delta Builds

Out of the box Team Build does not support Delta Builds. Thomas Janssen has a detailed post Realizing Delta Builds with VSTS Team Build for Delta Deployments which describes how this can be achieved. I have not had the opportunity to try this myself, but the blog post looks very through and informative. You can also download his DeltaBuild.targets file from his blog. I have the following comments relating to this; perhaps he will upgrade this file to reflect these comments.

This guidance is appropriate for target files which are designed to be consumed by others.

Don't override targets like AfterCompileSolution

Don't override targets like AfterCompileSolution. Instead extend the CompileSolutionDependsOn property in the manner:

<PropertyGroup>

<CompileSolutionDependsOn>

$(CompileSolutionDependsOn);

DeltaAfterCompileSolution

</CompileSolutionDependsOn>

</PropertyGroup>

This is because some consumers of this file may have already defined the AfterCompileSolution target. In which case one of them will be overridden.

Notice that I named the new target DeltaAfterCompileSolution. It is a best practice to prefix your targets with a value that should be unique. This will minimize the chances of your targets colliding with those defined by others. For example this could have been named MyAfterCompileSolution, but I bet there are a bunch of these already defined.

DependsOnTargets should always be taken from a property

You should define the DependsOnTargets value inside of a property, just like the MSFT targets files do. For example your DeltaAfterCompileSolution (after being renamed) would look like this:

<PropertyGroup>

<DeltaAfterCompileSolution>

$(DeltaAfterCompileSolution);

SafeCleanBuildResult;

GetLatestVersion;

CollectIncrementalBuildResult;

CreateDeltaBuildResult

</DeltaAfterCompileSolution>

</PropertyGroup>

<Target Name="DeltaAfterCompileSolution"

DependsOnTargets="$(DeltaAfterCompileSolution)">

</Target>

This is because you want users to be able to extend this process similar to how users extend the built-in build process. Without this they may need to modify your file, which is ill-advised because you may make a new release at some point.
Also notice the usage of the $(DeltaAfterCompileSolution) in the declaration of the DeltaAfterCompileSolution property. This is to
preserve any previous values that the user may have defined.

 

On a side note, if you are looking for more detailed information regarding Team Build, there will be three chapters of my new book Inside the Microsoft® Build Engine: Mastering MSBuild and Team Build which will be published in January 2009. Sample chapters will be available at that link shortly.

Thanks,

Sayed Ibrahim Hashimi

Team Build | Team Build | Visual Studio 2008 Monday, November 10, 2008 4:43:46 AM (GMT Standard Time, UTC+00:00)  #     | 
Friday, October 10, 2008

Speaking at the Tallahassee Code Camp

I will be speaking at the Tallahassee Code Camp on Saturday 11, 2008. I will be presenting MSBuild there. I think I should have posted this blog earlier but I've been too busy writing my new book!

Sayed Ibrahim Hashimi

Friday, October 10, 2008 5:06:42 AM (GMT Daylight Time, UTC+01:00)  #     | 
Monday, September 08, 2008

MSBuild: Exec Task

I was looking at the documentation for the Exec task (yes I'm writing a new MSBuild book!) and discovered that it is lacking. So I decided to post the complete list of properties here. So here it is for those of you using it.

Name

Description 

Command 

The command which is to be executed. This is the only required parameter.

CustomErrorRegularExpression *

If provided this will be the regex used to determine if an error occurred.

CustomWarningRegularExpression *

If provided this will be the regex used to determine that a warning occurred.

ExitCode

Output property containing the exit code provided by the executed command.

IgnoreExitCode

If true then the Exec task will not fail the build based on the exit code. Otherwise the build is failed for any non-zero exit code.

IgnoreStandardErrorWarningFormat *

If true the output is not examined for errors and warnings.

Outputs

An input/output parameter that contains the output items from the task. This is not set by the Exec task itself but made available to be set by the consumer.

StdErrEncoding

An input/output parameter that specifies the encoding that is used for the standard error stream.

StdOutEncoding

An input/output parameter that specifies the encoding that is used for the standard output stream.

Timeout

Specifies the timout, in milliseconds for the command. After the specified amount of time has passed the command will be terminated. By default there is no timeout

ToolPath

Specifies the location of the tool.

WorkingDirectory 

Specifies the working directory.

* Denotes new properties in MSBuild 3.5

There is a slightly new behavior in this version of the task relating to detecting errors & warnings from the output of the command. Take a look at the forum entry Exec task and "error :" in output.

More to come on the new book later keep an eye here soon. If you have ideas about specific examples that should be demonstrated let me know, for example; how to zip a set of file, how to ftp files to a server, your example here, etc.

Sayed Ibrahim Hashimi

msbuild | Visual Studio 2008 Monday, September 08, 2008 5:23:19 AM (GMT Daylight Time, UTC+01:00)  #     | 
Wednesday, July 30, 2008

IList Randomize Extension Method

I looked around for an extension method that would just randomize a list. I found a couple but they either didn't seem to work right or the modified the collection itself instead of creating a new collection and returning that. So I created one, it is pretty simple anywayz. The definition for it is shown below.

public static class IListExtensions
{
    public static IList<T> Randomize<T>(this IList<T> input)
    {
        if (input == null)
        { throw new ArgumentException("input"); }

        var test = (from p in input
                    select new { Id = rand.Next(), ListObject = p }).OrderBy(t => t.Id);

        IList<T> randomList = new List<T>();
        foreach (var item in test)
        {
            randomList.Add(item.ListObject);
        }

        return randomList;
    }

    static Random rand = new Random();
}

From here we use this method just like any other IList method, an example is shown below.

public void SampleRandomize()
{
    int numElemnets = 10;
    IList<int> numList = new List<int>();
    for (int i = 0; i < numElemnets; i++)
    {
        numList.Add(i);
    }

    IList<int> radnomList = numList.Randomize();

    for (int i = 0; i < randomList.Count; i++)
    {
        System.Diagnostics.Debug.WriteLine(string.Format("i: {0}", randomList[i]));
    }
}

I think it's pretty cool how you can create methods that can be soo easily used thanks to extension methods.


Sayed Ibrahim Hashimi

Visual Studio 2008 | CSharp3 Wednesday, July 30, 2008 6:31:15 AM (GMT Daylight Time, UTC+01:00)  #     | 
Friday, June 27, 2008

MSBuild Conditions on Targets

This post is related to my  previous post MSBuild RE: Enforcing the Build Agent in a Team Build which is a response on the post by Michael Ruminer at http://manicprogrammer.com/cs/blogs/michaelruminer/archive/2008/06/19/enforcing-the-build-agent-in-a-team-build.aspx.

Basically every MSBuild element can contain a Condtions attribute. You can read more at MSBuild Conditions. So even targets can have conditions attached to them! Despite the fact that you can do this, you should not. I recommend that you do not use conditions on targets. Conditions on targets seem straight forward but after you take a closer look they are more complicated. We can take a look at some of the items that come to mind here.

Conditions on targets and DependsOnTargets don’t play well

Take a look at this simple project file

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="2.0"
         xmlns="
http://schemas.microsoft.com/developer/msbuild/2003"
         DefaultTargets="Demo">

  <PropertyGroup>
    <AllowTarget>true</AllowTarget>
  </PropertyGroup>

  <Target Name="SupressTarget">
    <CreateProperty Value="false">
      <Output PropertyName="AllowTarget" TaskParameter="Value"/>
    </CreateProperty>
    <Message Text=" ==== SupressTarget ==== " Importance="high"/>
    <Message Text="AllowTarget: $(AllowTarget)"/>
  </Target>
 
 
  <Target Name="Demo" Condition="'$(AllowTarget)'=='true'"
          DependsOnTargets="SupressTarget">
    <Message Text=" ===== Demo ===== " Importance="high" />

    <Message Text="AllowTarget: $(AllowTarget)"/>
  </Target>
 
</Project>

In this project the main target is Demo and it depends on a target SupressTarget which actually disables the Demo target based on its condition. If you execute the command msbuild /t:Demo you get the results shown below.

Most users would expect that the target SupressTarget target would execute which sets the AllowTarget value to false, and then the Demo target is skipped. But what is happening here is that by the time DependsOnTargets is evaluated the condition has already been evaluated and has passed! The even more interesting thing here is if you execute msbuild /t:SupressTarget;Demo the results are shown below.

 

So this time it was skipped, because SupressTarget was called before the Demo target was invoked so the condition evaluated to false.

 

Conditions and target batching doesn’t work well either

If you are batching a target and you want to execute the target for some batches but not others, this cannot be achieved with target conditions, for a few reasons but the simplest is: Either a target is or is not defined. When the target is going to be executed for the first time the condition is evaluated. If the condition is true it will exist, otherwise it will not.

I thought of some other issues but they are not coming to me at this time, but I think this is enough to deter you from using target dependencies. Instead of target dependencies you should take a look at other way of achieving the same results.

 

Sayed Ibrahim Hashimi

msbuild | Team Build | TFS Friday, June 27, 2008 7:28:35 AM (GMT Daylight Time, UTC+01:00)  #     | 
Friday, June 20, 2008

MSBuild RE: Enforcing the Build Agent in a Team Build

This is a post that responds to a post by Michael Ruminer at Enforcing the Build Agent in a Team Build. I hope I correctly understand his situation. Here is my summary of it.

My solution to this problem is to create a property, AllowedBuildAgents, which will contain a semi-colon separated list of the allowed build agent names. Then this is converted into an item, AllowedBuildAgentsItem, so batching can be preformed over it. If you are not familiar with MSBuild batching you can see my previous postings at:

The main objective here is to create an item that contains all the allowed names, AllowedBuildAgentsItem, and batch over them. If the value for BuildAgentName is equal to any value in that item then we want to allow the build. I create a property BuildAgentAllowed which defaults to false, and if that condition is true then I set BuildAgentAllowed to true. So I created a target DetermineIfAuthorizedBuildAgent that depends will throw an error if BuildAgentAllowed is false. Also this target depends on the target that will actually populate that value, which is the GetBuildAgentAllowed target. The build script is placed below. I added a few elements that were for demo only. Those are; value for BuildAgentName and BeforeEndToEndIteration target. See comments in the file (which can be downloaded at the end of this post).

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="2.0"
         xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
         DefaultTargets="BeforeEndToEndIteration">

  <!--
  Assume that this value has been set already.
  I'm declaring it here for this demonstration.
  -->
  <PropertyGroup>
    <BuildAgentName>Sayed_001</BuildAgentName>
  </PropertyGroup>

 
 
  <PropertyGroup>
    <BeforeEndToEndIterationDependsOn>
      $(BeforeEndToEndIterationDependsOn);
      DetermineIfAuthorizedBuildAgent;
    </BeforeEndToEndIterationDependsOn>
  </PropertyGroup>

  <!--
  Define this here as a property so it can be passed
  via Properties from various callers.
  -->
  <PropertyGroup>
    <AllowedBuildAgents>Sayed_001;Sayed_003;Sayed_005</AllowedBuildAgents>
  </PropertyGroup>

  <!--
  Convert the property into an item so we can batch over it.
  -->
  <ItemGroup>
    <AllowedBuildAgentsItem Include="$(AllowedBuildAgents)"/>
  </ItemGroup>
  <!--
  Specify this value to false. If allowed it will be set to true.
  -->
  <PropertyGroup>
    <BuildAgentAllowed>false</BuildAgentAllowed>
  </PropertyGroup>
 
 

  <Target Name="PrintInfo">
    <Message Text="AllowedBuildAgentsItem: @(AllowedBuildAgentsItem,'%0a%0d')"/>
  </Target>

  <!-- Executing this target will make the GetBuildAgentAllowed target execute first -->
  <Target Name="DetermineIfAuthorizedBuildAgent"
          DependsOnTargets="GetBuildAgentAllowed">
    <Message Text="BuildAgentAllowed: $(BuildAgentAllowed)"/>
    <Error Text="This build can only be run on one of the following build agents: @(AllowedBuildAgentsItem)" 
           Condition="'$(BuildAgentAllowed)'=='false'" />
  </Target>
 
  <!--
  This target will be executed for each value in the AllowedBuildAgentsItem.
  If the BuildAgentName is equal to any value in AllowedBuildAgentsItem then the
  property BuildAgentAllowed will be set to true.
  -->
  <Target Name="GetBuildAgentAllowed" Outputs="%(AllowedBuildAgentsItem.Identity)">
    <Message Text="GetBuildAgentAllowed %25(AllowedBuildAgentsItem.Identity): %(AllowedBuildAgentsItem.Identity)"/>
   
    <CreateProperty Value="true" Condition="'$(BuildAgentName)'=='%(AllowedBuildAgentsItem.Identity)'">
      <Output PropertyName="BuildAgentAllowed" TaskParameter="Value"/>
    </CreateProperty>
   
  </Target>


 
  <!--
  This target is really executed by TeamBuild but I will
  put it here for demonstration. If this target executes then the build
  was allowed otherwise an error will be shown.
  -->
  <Target Name="BeforeEndToEndIteration" DependsOnTargets="$(BeforeEndToEndIterationDependsOn)">
    <Message Text="EndToEndIteration starting"/>
  </Target>
 
</Project>

The only reason that I have defined the allowed build agents in a property (AllowedBuildAgents) is because I want to allow external sources to specify it. You can specify properties through the command line or when using the MSBuild Task. Then the script converts this to an item. If I execute this project I would expect it to succeed because the defined value for BuildAgentName is contained in the list of AllowedBuildAgents. The results of executing this project are shown below.

Now we can change the value for BuildAgentName, by using the command msbuild.exe BuildAgent01.proj /p:BuildAgentName=Sayed_010. We would expect the build to fail. The results of this are below.

   

So the build failed as expected so we are good. Any questions?

   

BuildAgent01.proj

Sayed Ibrahim Hashimi

Friday, June 20, 2008 5:22:57 AM (GMT Daylight Time, UTC+01:00)  #     | 
Monday, June 16, 2008

Changing Build Verbosity in Visual Studio

If you are customizing your build process you may need to increase the verbosity that Visual Studio uses when building your projects. It is pretty easy to change this value, you just go to Tools->Options then find the Project and Solutions->Build and Run node. The dialog is shown here

The area where the verbosity setting lies is highlighted. I've got mine set to Detailed, which produces a lot of output. If you set it to Diagnostic, then you should be ready for a lot of output. Most like much more then you need!


Sayed Ibrahim Hashimi

msbuild | Visual Studio Monday, June 16, 2008 6:50:26 AM (GMT Daylight Time, UTC+01:00)  #     | 
Monday, June 09, 2008

MSBuild Reserved Properties

If you take a look the MSDN documentation for the reserved MSBuild Reserved Properties you will see many properties listed. For one reason or another there are actually several reserved properties that are missing from that list. Here is the list of all the reserved properties, the ones missing from that page are presented here in bold. For those that are listed on that page the description is taken from the MSDN. Also this is the list for MSBuild 3.5.

 

 

Take a look at this project file that prints out these values.

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
DefaultTargets="PrintProperties"
ToolsVersion="3.5">

<Target Name="PrintProperties">
<Message Text="MSBuildNodeCount: $(MSBuildNodeCount)"/>
<Message Text="MSBuildExtensionsPath32: $(MSBuildExtensionsPath32)"/>
<Message Text="MSBuildProjectDirectoryNoRoot: $(MSBuildProjectDirectoryNoRoot)"/>
<Message Text="MSBuildToolsPath: $(MSBuildToolsPath)"/>
<Message Text="MSBuildToolsVersion: $(MSBuildToolsVersion)"/>
<Message Text="MSBuildBinPath: $(MSBuildBinPath)"/>
<Message Text="MSBuildExtensionsPath: $(MSBuildExtensionsPath)"/>
<Message Text="MSBuildProjectDefaultTargets: $(MSBuildProjectDefaultTargets)"/>
<Message Text="MSBuildProjectDirectory: $(MSBuildProjectDirectory)"/>
<Message Text="MSBuildProjectExtension: $(MSBuildProjectExtension)"/>
<Message Text="MSBuildProjectFile: $(MSBuildProjectFile)"/>
<Message Text="MSBuildProjectFullPath: $(MSBuildProjectFullPath)"/>
<Message Text="MSBuildProjectName: $(MSBuildProjectName)"/>
<Message Text="MSBuildStartupDirectory: $(MSBuildStartupDirectory)"/>

</Target>
</Project>

If you execute this you will get something like what's shown here.

 

I'm not sure how important this, but you may need to know one day.

ReservedProperties.proj

Sayed Ibrahim Hashimi

msbuild Monday, June 09, 2008 6:52:31 AM (GMT Daylight Time, UTC+01:00)  #     |