Mike's profileFreeToDevBlogLists Tools Help

Blog


    November 10

    Introducing MSBuild Explorer

    image I work a lot with MSBuild files, mostly to automate numerous processes in the development lifecycle. I wrote a tool to help me work with MSBuild and today I’ve uploaded it to the web in the hope that it will make the lives of those who use MSBuild every day a little bit easier.

    image

    The tool is called MSBuild Explorer and it provides the following features:

    • Explore the makeup of your MSBuild files.
    • Save Favourites to quickly execute your pre-configured MSBuild Scripts.
    • Quickly run a snippet of MSBuild.
    • Quickly create a new MSBuild file.

    The quickest way to see what the tool really does is to spend a minute or two reading the Example Usage Walkthrough.

     

    You can download Version 1 of MSBuild Explorer here. You will need .Net 3.5.

    Version 2 will Require .Net 4.0 and will be available in H1 2010.

    Mike

    November 07

    Versioning Code in TFS - Revised

    This is a revised and combined post covering the two previous posts, Versioning Code in TFS Part 1 & Part 2. If you haven’t read those two posts, then this revised post is all you need to read. If you have read the two previous posts, then although similar, I recommend you read this revised post as it contains important corrections, updates and clarifications. Note that this post mostly relates to TFS 2008, though the concepts implied are not tied to a specific version of TFS.

    ____________________________________________________________________________________

    The Problem

    I’ve lost count of the number of blog posts, forum questions and internal emails that I have seen regarding problems with versioning assemblies in TFS.

    I believe the root cause of the problem is that many users have tried to migrate their existing versioning logic and code to work with TFS, blinded by the wealth of functionality that TFS has brought to the development process.

    The Truth

    • TFS provides the basic fundamentals of iterative versioning out the box.

    Some Basics

    What is Versioning?

    Versioning refers to the process whereby code is compiled and ‘stamped’ with a version number that can distinguish it from previous or future builds of that code.

    What is a version number?

    There are two version numbers in .Net, the AssemblyVersion and the AssemblyFileVersion. Both follow the same format:

    • <major version>.<minor version>.<build number>.<revision>

    My first piece of advice is that you don’t keep the two in sync. The AssemblyVersion should rather be of the format:

    • <major version>.<minor version>.0.0

    The reason for this is that strong name signatures include the AssemblyVersion, which means that if you release an updated assembly, the code that references it will need to be updated too (unless you go the publisher policy route, but let’s try keeping things simple).

    The AssemblyFileVersion is the attribute that should be updated with every build you perform, and therein lays the problem. How?

    I would estimate that in 99% of builds, the format of the build number will be

    • <Static major version>.<Static minor version>.< Calculated build number>.<Iterative revision>

    The Static parts are easy and they will most likely equate to those used in the AssemblyVersion. The calculated part is really up to you. It could be a date format e.g. mmdd or possibly the number of days since a given milestone date etc. The iterative part is where the trouble lies.

    All versioning tasks need to provide the same essential logic. They need to calculate your build number and provide a unique incremental value for every build. To ensure that the incremental value is unique, most versioning solutions check out a file, alter it and check the file back in.

    Lots of people including myself first used the AssemblyInfo task (which has now been included in the MSBuild Extension Pack), and encountered numerous painful ‘cannot determine the workspace’ errors, or you were likely to be caught by check-in policies or duplicate attributes. All issues can be resolved, but too many people have had a hard time using this task for versioning. It’s a great task, but not for versioning.

    If you managed to get around the AssemblyInfo task issues, or your own problems with creating a task that checked out a file, incremented the value and then checked it in again, well done... and welcome to continuous merging issues! TFS 2005 / 2008 don’t support multiple pending merge entries for a single file, so you have to perform continuous merging. This isn’t a big issue with versioning tasks, however the problem with continuously checking out and in the versioning file(s) is that you get loads of noise on the pending merges table and if you do merge multiple version files, you will likely have to manually resolve the final version.

    My second piece of advice is don’t check your versioning files in and out during the build process. As discussed above, it creates noise and merge hassles. As long as you’re versioning logic can be related to the TFS Build Number, I see no benefit in having this source control operation take place.

    The Solution

    TFS provides a build number for every build it initiates. The format is

    • <build name>_<year><month><day>.<revision>

    e.g.

    • MSSDCDaily_20080402.1

    To accomplish versioning, use the <revision> part of the build number. TFS will provide an incremented revision for every build, whether the previous build succeeded or not. All you need to do is provide a task that takes the build number as input, then emits your version number as output. The logic within the task is up to you.

    Because your build is based on the build number, you can easily locate the label associated with the build.

    In summary
    • Don’t increment the AssemblyVersion
    • Don’t perform source control operations for versioning
    • Do increment the AssemblyFileVersion
    • Do base your build number iteration on the TFS Build Number
    • Do base your build number calculation on the TFS Build Number

    Implementing the Solution

    If you don’t want to write your own task to implement versioning, the MSBuild Extension Pack provides various tasks to assist you with versioning.

    AssemblyInfo Task [MSBuild.ExtensionPack.Framework.AssemblyInfo]

    The original AssemblyInfo task has been added to the MSBuild Extension Pack and received various small tweaks. As mentioned, I’m not a fan of using this for versioning, but if you must, then below is an abbreviated sample:

    <Project DefaultTargets="DesktopBuild" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
        <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\TeamBuild\Microsoft.TeamFoundation.Build.targets" />
        <!-- ADD THIS LINE -->
        <Import Project="$(MSBuildExtensionsPath)\ExtensionPack\MSBuild.ExtensionPack.VersionNumber.targets"/>

        <!-- ADD AND CONFIGURE THIS PROPERTY GROUP -->
        <PropertyGroup>
            <!-- ASSEMBLY VERSION PROPERTIES.-->
            <AssemblyMajorVersion>1</AssemblyMajorVersion>
            <AssemblyFileMajorVersion>0</AssemblyFileMajorVersion>
            <!-- TF.EXE -->
            <TF>&quot;$(TeamBuildRefPath)\..\tf.exe&quot;</TF>
            <!-- ASSEMBLYINFO FILE SPEC -->
            <AssemblyInfoSpec>AssemblyInfo.cs</AssemblyInfoSpec>
        </PropertyGroup>

        <!-- SET THIS TO NON-EXISTENT FILE TO FORCE REBUILD. -->
        <ItemGroup>
            <IntermediateAssembly Include="$(SolutionRoot)\foobar.dll"/>
        </ItemGroup>

        <!-- OVERRIDE AFTERGET-->
        <Target Name="AfterGet" Condition="'$(IsDesktopBuild)'!='true'">

            <!-- SET THE ASSEMBLYINFOFILES ITEMS DYNAMICALLY -->
            <CreateItem Include="$(SolutionRoot)\**\$(AssemblyInfoSpec)">
                <Output ItemName="AssemblyInfoFiles" TaskParameter="Include" />
            </CreateItem>

            <Exec WorkingDirectory="$(SolutionRoot)" Command="$(TF) checkout /recursive &quot;@(AssemblyInfoFiles)&quot;"/>
        </Target>

        <!-- OVERRIDE AFTERCOMPILE-->
        <Target Name="AfterCompile" Condition="'$(IsDesktopBuild)'!='true'">
            <Exec WorkingDirectory="$(SolutionRoot)" Command="$(TF) checkin /comment:&quot;Auto-Build: Version Update&quot; /noprompt /override:&quot;Auto-Build: Version Update&quot; /recursive &quot;@(AssemblyInfoFiles)&quot;" />
        </Target>


        <!-- IN CASE OF BUILD FAILURE, THE AFTERCOMPILE TARGET IS NOT EXECUTED. UNDO THE CHANGES -->
        <Target Name="BeforeOnBuildBreak" Condition="'$(IsDesktopBuild)'!='true'">
            <Exec WorkingDirectory="$(SolutionRoot)" Command="$(TF) undo /noprompt /recursive &quot;@(AssemblyInfoFiles)&quot;" />
        </Target>
    </Project>

    TFSVersion Task [MSBuild.ExtensionPack.VisualStudio.TfsVersion]

    The TFSVersion task provides the more lightweight versioning that I have described and is what I use on all projects. Please Note: The output of GetVersion should not be used to change the $(BuildNumber).

    <Project DefaultTargets="DesktopBuild" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
        <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\TeamBuild\Microsoft.TeamFoundation.Build.targets" />
        <!-- ADD THIS LINE -->
        <Import Project="$(MSBuildExtensionsPath)\ExtensionPack\MSBuild.ExtensionPack.tasks"/>

        <!-- DEFINE WHICH FILES TO VERSION -->
        <ItemGroup>
            <FilesToVersion Include="$(SolutionRoot)\Source\Common\VersionInfo.cs" />
        </ItemGroup>

        <!-- OVERRIDE BUILDNUMBEROVERRIDETARGET -->
        <Target Name="BuildNumberOverrideTarget" Condition="'$(IsDesktopBuild)'!='true'">
            <MSBuild.ExtensionPack.VisualStudio.TfsVersion TaskAction="GetVersion" UseUtcDate="true" BuildName="$(BuildDefinition)" TfsBuildNumber="$(BuildNumber)" VersionFormat="Elapsed" StartDate="1 Jan 2009" VersionTemplateFormat="0.0.1000.0" Major="3" Minor="1">
                <Output TaskParameter="Version" PropertyName="CodeBuildNumber" />
            </MSBuild.ExtensionPack.VisualStudio.TfsVersion>
        </Target>

        <!-- OVERRIDE AFTERGET -->
        <Target Name="AfterGet" Condition="'$(IsDesktopBuild)'!='true' ">
            <MSBuild.ExtensionPack.VisualStudio.TfsVersion TaskAction="SetVersion" Files="%(FilesToVersion.Identity)" Version="$(CodeBuildNumber)"/>
        </Target>
    </Project>

    SQLVersion Task [MSBuild.ExtensionPack.SqlServer.SqlVersion]

    The SqlVersion task provides the ability to manage multiple build versions in a simple database table. Please Note: The output of GetVersion should not be used to change the $(BuildNumber).

    <Project DefaultTargets="DesktopBuild" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
        <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\TeamBuild\Microsoft.TeamFoundation.Build.targets" />
        <!-- ADD THIS LINE -->
        <Import Project="$(MSBuildExtensionsPath)\ExtensionPack\MSBuild.ExtensionPack.tasks"/>

        <!-- DEFINE WHICH FILES TO VERSION -->
        <ItemGroup>
            <FilesToVersion Include="$(SolutionRoot)\Source\Common\VersionInfo.cs" />
        </ItemGroup>

        <!-- OVERRIDE BUILDNUMBEROVERRIDETARGET -->
        <Target Name="BuildNumberOverrideTarget">
            <PropertyGroup>
                <FieldToIncrement Condition=" '$(IncrementalBuild)'=='true' ">4</FieldToIncrement>
                <FieldToIncrement Condition=" '$(IncrementalBuild)'!='true' ">3</FieldToIncrement>
            </PropertyGroup>

            <!-- Get the latest build number and increment as necessary -->
            <MSBuild.ExtensionPack.SqlServer.SqlVersion Taskaction="GetVersion" BuildName="V9 Production Build" FieldToIncrement="$(FieldToIncrement)" DatabaseName="Mike">
                <Output TaskParameter="Major" PropertyName="BuildMajor" />
                <Output TaskParameter="Minor" PropertyName="BuildMinor" />
                <Output TaskParameter="Build" PropertyName="BuildBuild" />
                <Output TaskParameter="Revision" PropertyName="BuildRevision" />
            </MSBuild.ExtensionPack.SqlServer.SqlVersion>
            <PropertyGroup>
                <CodeBuildNumber>$(BuildMajor).$(BuildMinor).$(BuildBuild).$(BuildRevision)</CodeBuildNumber>
            </PropertyGroup>
        </Target>

        <!-- OVERRIDE AFTERGET -->
        <Target Name="AfterGet" Condition="'$(IsDesktopBuild)'!='true' ">
            <MSBuild.ExtensionPack.VisualStudio.TfsVersion TaskAction="SetVersion" Files="%(FilesToVersion.Identity)" Version="$(CodeBuildNumber)"/>
        </Target>
    </Project>

    Version 3.5.5.0 of the MSBuild Extension Pack will provide an additional file based versioning task, but the above three, especially the TFSVersion task should meet most needs.

    I’ve disabled comments on this blog as the spam filters on live spaces are not sufficient. If you have any feedback, please use the feedback URL found in the MSBuild Extension Pack help.

    Mike

    November 03

    Power Commands for Visual Studio 2010

    Moving to VS2010 felt like a step backwards in some respects as it doesn’t implement many of the great productivity enhancements that the Power Commands for Visual Studio 2008 offered.

    The good news is that the PowerCommands for Visual Studio 2010 are are now available here.

    One thing to note is that after installing the Visual Studio extension, you will probably need to enable it for administrators.

    To do this,

    • Go to Tools > Options > Environment - Extension Manager and check ‘Load per user extensions when running as administrator.’
    • Restart Visual Studio

    Be sure to check out the Gallery for other useful extensions: logo

    Visual Studio 2010 Beta2 Feedback Survey

    If you’re using VS2010 Beta 2, the team would really appreciate your feedback. Take a few minutes to go through their survey and help make the final product what you want it to be!

    image001

    October 31

    Automating Testing Using Windows Virtual PC

    Guy Smith-Ferrier gave a talk covering testing with Windows Virtual PC at the UK & Ireland MVP Open day yesterday. He’s posted his slides and source code online now. He also highlighted the upcoming support for Windows Virtual PC in the MSBuild Extension Pack

    IMAG0005 (640x364)

    Take a look at his post, it’s straightforward and a worthwhile read.

    October 06

    MSBuild Extension Pack – One Year On

    balloons Twelve months ago today the first release of the MSBuild Extension Pack was released on CodePlex. It’s been an amazing twelve months! A big highlight has been the day to day dealing with contributors from around the globe. Without the feedback and contributions, we wouldn’t be where we are today.

    It continues to encourage me when I see the weird and wonderful ways that people adopt both MSBuild as a technology and the building blocks that the Extension Pack provides. Other highlights of the last twelve months have to include the relatively low bug count and the consistent stream of downloads.

    Looking at the past year from a statistics point of view we have

    Releases 4
    Change Sets 221
    Official Developers 17
    Downloads 26800+
    Lines 35000+ (up 23000+)
    Tasks 300+ (up 150+)
    Visits 46800+
    Page Views 118900+

     

    The next release on our radar is 3.5.5.0 which should ship in early to mid December 2009. As a product, we haven’t seen any change to MSBuild, however the ‘big’ 4.0 release is on its way and in the Beta 2 timeframe you can expect to see a beta of the 4.0 Extension Pack.

    I’d like to thank all those who have made contact over the last year and helped make the product better for all of us. I encourage you to continue with the feedback, be it good or bad.

    Thank you!

    Mike

    October 05

    MSBuild Extension Pack 3.5.4.0 --- Available now

    We’ve just shipped the latest release of the MSBuild Extension Pack! This release contains numerous bug fixes, enhancements and new tasks. You can view the significant changes here.

    Download

    Mike

    October 01

    3.5.4.0, almost there….

    Another update to the draft online help for the MSBuild Extension Pack has been posted. We’re looking good for a release of 3.5.4.0 some time over the weekend.

    If you are sitting on any issues, please get them in now!

    Thanks

    Mike

    August 11

    StyleCop 4.3.2.1 has snuck out…

    More info here

    July 25

    DynamicExecute Task - Update

    Stephen Cleary has made various enhancements to this great task which will ship in version 3.5.4.0 of the MSBuild Extension Pack

    Documentation for the task has just been refreshed and is temporarily provided here

    Download the beta code now…

    ReSharper 4.5.1 Released

    ScreenShot025 This tool just keeps getting better. Get the update here http://www.jetbrains.com/resharper/

    June 24

    MSBuild 4.0 BeforeTargets and AfterTargets

    Visual Studio 2010 Beta 1 gives the wider community their first look at what is on offer in MSBuild 4.0. In this post I’ll briefly cover the new BeforeTargets and AfterTargets features.

    These targets sit in the new MSBuild.Construction namespace and on initial inspection, they provide you with the ability to plug in targets to alter the execution path of a MSBuild file.

    Lets cover this with a basic example. Running the following sample,

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

      <Target Name="Default">
        <Message Text="Hello from Default"/>
      </Target>

    </Project>

    we get the expected:

    Project "C:\Users\administrator.DEV\Desktop\MSBuild Samples\BeforeAfter.proj" on node 1 (default targets).
      Hello from Default
    Done Building Project "C:\Users\administrator.DEV\Desktop\MSBuild Samples\BeforeAfter.proj" (default targets).

    Now suppose you wanted to run a target before the Default target. In .NET 3.5 you would use DependsOnTargets as shown with the following:

     

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

      <Target Name="Default" DependsOnTargets="DefaultDependsOn">
        <Message Text="Hello from Default"/>
      </Target>

      <Target Name="DefaultDependsOn">
        <Message Text="Hello from DefaultDependsOn"/>
      </Target>

    </Project>

    which would result in:

    Project "C:\Users\administrator.DEV\Desktop\MSBuild Samples\BeforeAfter.proj" on node 1 (default targets).
      Hello from DefaultDependsOn
    Default:
      Hello from Default
    Done Building Project "C:\Users\administrator.DEV\Desktop\MSBuild Samples\BeforeAfter.proj" (default targets).

    So what’s wrong with DependsOnTargets? Well, not a lot, however the above implementation does create an explicit bind between the targets and may reduce your ability to reuse the default target efficiently.

     

    Enter BeforeTargets

    In MSBuild 4.0 you can achieve the same result by using the following

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

      <Target Name="Default">
        <Message Text="Hello from Default"/>
      </Target>

      <Target Name="DefaultBeforeTarget" BeforeTargets="Default">
        <Message Text="Hello from DefaultBeforeTarget"/>
      </Target>

    </Project>

    which results in:

    Project "C:\Users\administrator.DEV\Desktop\MSBuild Samples\BeforeAfter.proj" on node 1 (default targets).
      Hello from DefaultBeforeTarget
    Default:
      Hello from Default
    Done Building Project "C:\Users\administrator.DEV\Desktop\MSBuild Samples\BeforeAfter.proj" (default targets).

    So we get the same functionality, but our targets are arguably more reusable. I don’t think there is a need to go and re-write all your code, but remember that you have this feature in your tool belt in 4.0.

    Now it may be that I’ve used it a lot, but DependsOnTargets makes a lot of sense to me. It does ‘as it reads’, i.e. the Default target depends on Targets xyz… A minor concern I have with this new feature is that it doesn’t do ‘as it reads’. The first time i saw a sample with this I expected that all the BeforeTargets would run before the named target. Perhaps a better name would be RunBeforeTargets, which makes it clear that the named target will run before all the targets listed. The same logic could be applied to AfterTargets (or perhaps a better named RunAfterTargets)

     

    Enter AfterTargets

    In a very similar light, the new AfterTargets feature allows us to run a target after a given target. Running the following sample:

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

      <Target Name="Default">
        <Message Text="Hello from Default"/>
      </Target>

      <Target Name="DefaultBeforeTarget" BeforeTargets="Default">
        <Message Text="Hello from DefaultBeforeTarget"/>
      </Target>

      <Target Name="DefaultAfterTarget" AfterTargets="Default">
        <Message Text="Hello from DefaultAfterTarget"/>
      </Target>
    </Project>

    we get:

    Project "C:\Users\administrator.DEV\Desktop\MSBuild Samples\BeforeAfter.proj" on node 1 (default targets).
      Hello from DefaultBeforeTarget
    Default:
      Hello from Default
    DefaultAfterTarget:
      Hello from DefaultAfterTarget
    Done Building Project "C:\Users\administrator.DEV\Desktop\MSBuild Samples\BeforeAfter.proj" (default targets).

     

    But DependsonTargets Rules!

    So you can see how these two new features provide the ability to easily tweak execution. You can also plug into existing target frameworks without affecting other users. Now what of the DependsOnTargets in 4.0? It still lives on of course and its important to understand the order of execution.

    Take the following example:

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

      <Target Name="Default" DependsOnTargets="DefaultDependsOn">
        <Message Text="Hello from Default"/>
      </Target>

      <Target Name="DefaultDependsOn">
        <Message Text="Hello from DefaultDependsOn"/>
      </Target>

      <Target Name="DefaultBeforeTarget" BeforeTargets="Default">
        <Message Text="Hello from DefaultBeforeTarget"/>
      </Target>

      <Target Name="DefaultAfterTarget" AfterTargets="Default">
        <Message Text="Hello from DefaultAfterTarget"/>
      </Target>
    </Project>

    Would you expect to see DefaultBeforeTarget or DefaultDependsOn execute first? Below is the result:

    Project "C:\Users\administrator.DEV\Desktop\MSBuild Samples\BeforeAfter.proj" on node 1 (default targets).
      Hello from DefaultDependsOn
    DefaultBeforeTarget:
      Hello from DefaultBeforeTarget
    Default:
      Hello from Default
    DefaultAfterTarget:
      Hello from DefaultAfterTarget
    Done Building Project "C:\Users\administrator.DEV\Desktop\MSBuild Samples\BeforeAfter.proj" (default targets).

    So as you can see, order of execution is DependsOnTargets, BeforeTargets, [NamedTarget], AfterTargets.

    What do you think of this new feature? Can you think of better names or do they make sense to you?

    --- Mike

    Are you ready for .NET 4.0?

    Check out the .NET Framework Compatibility Blog for all the latest information regarding compatibility.

    You can also follow a walkthrough here

    June 11

    Inline coding in MSBuild 3.5

    Stephen Cleary has just checked in the first version of the DynamicExecute task. This will ship in version 3.5.4.0 of the MSBuild Extension Pack, but if you compile the code yourself, you can start using it now.

    We’d appreciate any feedback you have. Download

    Documentation for the task is provided here

    June 07

    MSBuild Extension Pack 3.5.3.0 --- Available now

    We’ve just shipped the latest release of the MSBuild Extension Pack! This release slipped in schedule a tiny bit but includes over 40 new tasks and represents a 20% increase in our code base.

    ScreenShot004

    Thanks to all those who have contributed to making this significant release. Download here

    PS, you can catch the latest updates on Twitter: http://twitter.com/msbep

    Mike

    May 06

    Planning for TFS 2010

    Brian Harry has posted a few more details concerning system requirements and more here.

    I’ve updated my previous diagrammatic overview to include this new information.

    Download

    ScreenShot015

    April 08

    Team System 2010 --- Start Your Engines…

    Visual Studio Team system will soon be going into Beta and I look forward to getting closely acquainted with it and posting some helpful blog posts.

    Brian Harry has just posted a great overview of what to expect: Team System 2010 Overview

    Remember, if you are planning on adopting 2010, see this post: Planning for Team Foundation Server 2010

    Mike

    April 06

    MSBuild Extension Pack Interview

    I recently did an interview with Derek Hatchard covering the MSBuild Extension Pack. You can hear about how it started, what it is and what we have in store for future releases… listen here.

    Team System MVP

    image002(2) Last week I received a notification from Microsoft that I had been awarded the 2009 Microsoft® Team System MVP Award!

    I’d like to thank those involved in my nomination and look forward to a successful year working more closely with the Team System family.

    Mike