BM-Bloggers

The blogs of Black Marble staff

Free Book

Yes that's right Microsoft Press are celebrating 25 years and giving away free books, this months is Joseph Davies’s book on IPV6

Get it Here

the offer runs out in a few days so get downloading if you want it.

b.

Running TypeMock based test in Team Build

If you have TypeMock Isolator based MSTests in a solution you will want them to be run as part of any CI build process.

To get this to work with Team Build you have to make sure Isolator is started in the build box at the right time (something that is done automagically behind the scenes by Visual Studio during developer testing). This is not actually that difficult as TypeMock provide some tasks for just this purpose.

Firstly you have to install Isolator on the build box (and of course license it). Then edit your tfsbuild.proj build script to include the overrides for the beforetest and aftertest targets

<!-- Import the Typemock list of tasks --> 
<PropertyGroup>
    <TypeMockLocation>C:\Program Files\Typemock\Isolator\5.1</TypeMockLocation>
</PropertyGroup>
<Import Project ="$(TypeMockLocation)\TypeMock.MSBuild.Tasks"/>

<!-- Before the tests are run start TypeMock -->
<Target Name="BeforeTest">
    <TypeMockStart/>
</Target>

<!-- And stop it when the are finished -->
<Target Name="AfterTest">
    <TypeMockStop/>
</Target>

Once this is done your test should run OK

My problems with Live Messenger inside Visual Studio are fixed.

One of the cool feature of the last October 08 release of TFS Power Tools has been that the members of a Team Project are shown inside Team Explorer.

One of the ideas of this is that you can use Live Messenger from inside Team Explorer to see team members status, but I and many other were seeing the error shown below as Team Explorer refreshed

clip_image002

There had been much talk of it being settings in the registry, UAC being used etc. but none of the fixes detailed worked for me.

However, today it has all started working after I updated to the new version of Live Messenger released in the past few days, Version 2009 (Build 14.0.8050.1202). I suspect the problem in my case was that I was using a beta version of Live Messenger

Update on using StyleCop in TFS Team Build

I posted a while ago about trying to wire in the results from StyleCop into a Team Build, the problem I had was that I could not get the StyleCop violations into the build summary.

Well I still can’t, after much checking and asking around I was reliably informed that the build summary is not editable and there are no immediate plans for it to be in the future versions of TFS.

However, Martin Woodward, another Team System MVP, made the suggestion to add the violation information into the build information object. This would not allow the information to be seen in  the build summary in Visual Studio, but it would allow me to programmatically recover it from the IBuildInformation object inside my build wallboard application – which shows the current state of all our current CI Team Builds, it shows a scrolling list row as below

image

Where the key items are:

  • Big graphic showing Building, Success, Partial Success or Failure
  • The name of the build and the time it finished
  • CE – Compiler errors
  • CW – Compiler warnings
  • FW – FXCop warnings
  • SW – StyleCop violations
  • TP – Tests passed
  • TF – Test failed
  • and the rabbit shows if the build status is reported by a NazBazTag Build Bunny

So to do this I had to write an MSBuild Task, but the code fairly simple as Martin had suggested

//-----------------------------------------------------------------------
// <copyright file="StyleCopResultsMerge.cs" company="Black Marble">
//     Black Marble Copyright 2008
// </copyright>
//-----------------------------------------------------------------------
namespace BlackMarble.MSBuild.CodeQuality
{
    using System;
    using Microsoft.Build.Framework;
    using Microsoft.Build.Utilities;
    using Microsoft.TeamFoundation.Build.Client;
    using Microsoft.TeamFoundation.Client;
    
    /// <summary>
    /// Merges the Stylecop results into the build results for TFS
    /// </summary>
    public class StyleCopResultsMerge : Task
    {
        /// <summary>
        /// The tfs server to report to
        /// </summary>
        private TeamFoundationServer tfs;

        /// <summary>
        /// The build server doing the work
        /// </summary>
        private IBuildServer buildServer;

        /// <summary>
        /// The current build
        /// </summary>
        private IBuildDetail build;
                
        /// <summary>
        /// Gets or sets the Url of the Team Foundation Server.
        /// </summary>
        [Required]
        public string TeamFoundationServerUrl
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the Uri of the Build for which this task is executing.
        /// </summary>
        [Required]
        public string BuildUri
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the number of stylecop violations found.
        /// </summary>
        [Required]
        public int Violations
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the number of files stylecop failed to parser.
        /// </summary>
        [Required]
        public int Failures
        {
            get;
            set;
        }

        /// <summary>
        /// Gets the lazy init property that gives access to the TF Server specified by TeamFoundationServerUrl.
        /// </summary>
        protected TeamFoundationServer Tfs
        {
            get
            {
                if (this.tfs == null)
                {
                    if (String.IsNullOrEmpty(this.TeamFoundationServerUrl))
                    {
                        // Throw some exception.
                    }

                    this.tfs = TeamFoundationServerFactory.GetServer(this.TeamFoundationServerUrl);
                }

                return this.tfs;
            }
        }

        /// <summary>
        /// Gets the lazy init property that gives access to the BuildServer service of the TF Server.
        /// </summary>
        protected IBuildServer BuildServer
        {
            get
            {
                if (this.buildServer == null)
                {
                   this.buildServer = (IBuildServer)this.Tfs.GetService(typeof(IBuildServer));
                }

                return this.buildServer;
            }
        }

        /// <summary>
        /// Gets the lazy init property that gives access to the Build specified by BuildUri.
        /// </summary>
        protected IBuildDetail Build
        {
            get
            {
                if (this.build == null)
                {
                    this.build = (IBuildDetail)this.BuildServer.GetBuild(new Uri(this.BuildUri), null, QueryOptions.None);
                }

                return this.build;
            }
        }

        /// <summary>
        /// ITask implementation - Execute method.
        /// </summary>
        /// <returns>
        /// True if the task succeeded, false otherwise.
        /// </returns>
        public override bool Execute()
        {
            try
            {
                IBuildInformation info = this.Build.Information;

                Log.LogMessage("StyleCopResultsMerge for build {0} with {1} violations ", this.Build.Uri.ToString(), this.Violations.ToString());

                IBuildInformationNode infoNode = info.CreateNode();
                infoNode.Type = "org.stylecop";
                infoNode.Fields.Add("total-violations", this.Violations.ToString());
                info.Save();

                return true;
            }
            catch (Exception ex)
            {
                Log.LogError(ex.Message);
                return false;
            }
        }
    }
}

This can then wired into the build process I detailed in the older post and have repeated below with the new additions. The choice you have to make is if StyleCop violations will cause the build to fail or not – both are detailed below.

<!-- the imports needed -->
<Import Project="$(MSBuildExtensionsPath)\ExtensionPack\MSBuild.ExtensionPack.tasks"/>
<!-- this could be a task file if you wanted -->
<UsingTask AssemblyFile="$(BMTasksPath)BlackMarble.MSBuild.CodeQuality.StyleCopResultsMerge.dll" TaskName="BlackMarble.MSBuild.CodeQuality.StyleCopResultsMerge"/>

<!-- All the other Target go here -->

<Target Name="AfterCompile">

    <!-- Create a build step to say we are starting StyleCop -->
    <BuildStep TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
        BuildUri="$(BuildUri)"
             Name="StyleCopStep"
              Message="StyleCop step is executing.">
      <Output TaskParameter="Id" PropertyName="StyleCopStep" />
    </BuildStep>

    <!-- Create a collection of files to scan, ** means and sub directories -->
    <CreateItem Include="$(SolutionRoot)\My Project\**\*.cs">
      <Output TaskParameter="Include" ItemName="StyleCopFiles"/>
    </CreateItem>

    <!-- Run the StyleCop MSBuild Extensions task using the setting file in the same directory as sln file and also stored in TFS -->
    <MSBuild.ExtensionPack.CodeQuality.StyleCop
        TaskAction="Scan"
        SourceFiles="@(StyleCopFiles)"
        ShowOutput="true"
        ForceFullAnalysis="true"
        CacheResults="false"
        logFile="$(DropLocation)\$(BuildNumber)\StyleCopLog.txt"
        SettingsFile="$(SolutionRoot)\My Project\Settings.StyleCop"
        ContinueOnError="false">
      <Output TaskParameter="Succeeded" PropertyName="AllPassed"/>
      <Output TaskParameter="ViolationCount" PropertyName="Violations"/>
      <Output TaskParameter="FailedFiles" ItemName="Failures"/>
    </MSBuild.ExtensionPack.CodeQuality.StyleCop>

    <!-- Run the new results merge task -->
    <BlackMarble.MSBuild.CodeQuality.StyleCopResultsMerge
      TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
      BuildUri="$(BuildUri)"
      Violations="$(Violations)"
      Failures ="0"
     />
 
    <!-- Put up a message in the build log to show results irrespective of what we do next -->
    <Message Text="StyleCop Succeeded: $(AllPassed), Violations: $(Violations)"/>

    <!-- FailedFile format is:
        <ItemGroup>
            <FailedFile Include="filename">
                <CheckId>SA Rule Number</CheckId>
                <RuleDescription>Rule Description</RuleDescription>
                <RuleName>Rule Name</RuleName>
                <LineNumber>Line the violation appears on</LineNumber>
                <Message>SA violation message</Message>
            </FailedFile>
        </ItemGroup>-->

    <Warning Text="%(Failures.Identity) - Failed on Line %(Failures.LineNumber). %(Failures.CheckId): %(Failures.Message)"/>

    <!-- The StyleCop task does not throw an error if the analysis failed, 
         so we need to check the return value and if we choose to treat errors as warnngs 
         we need to set the error state -->
    <Error Text="StyleCop analysis warnings occured" Condition="'$(AllPassed)' == 'False'"  />

    <!-- List out the issues, you only need this if we are not forcing the error above -->
    <!--<BuildStep TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
            BuildUri="$(BuildUri)"
            Message="%(Failures.Identity) - Failed on Line %(Failures.LineNumber). %(Failures.CheckId): %(Failures.Message)"/>-->

    <!-- Log the fact that we have finished the StyleCop build step, as we had no error  -->
    <BuildStep TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
                  BuildUri="$(BuildUri)"
                  Id="$(StyleCopStep)"
                  Status="Succeeded"
                  Message="StyleCop Succeeded: $(AllPassed), Violations: $(Violations)"/>

    <!-- If an error has been raised we call this target 
         You might have thought you could so the same as the error line above and this followng
         OnError line by adding a condition as shown below. However this does not work
         as the OnError condition is not evaluated unless an error as previously occured-->
    <OnError ExecuteTargets="FailTheBuild" />
    <!--<OnError ExecuteTargets="FailTheBuild" Condition="'$(AllPassed)' == 'False'"  />-->

  </Target>

  <Target Name="FailTheBuild">
    <!-- We are failing the build due to stylecop issues -->
    <BuildStep TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
            BuildUri="$(BuildUri)"
            Id="$(StyleCopStep)"
            Status="Failed"
            Message="StyleCop Failed: $(AllPassed), Violations: $(Violations) [See $(DropLocation)\$(BuildNumber)\StyleCopLog.txt]"/>

    <!-- List out the issues-->
    <BuildStep TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
            BuildUri="$(BuildUri)"
            Message="%(Failures.Identity) - Failed on Line %(Failures.LineNumber). %(Failures.CheckId): %(Failures.Message)"/>

  </Target>

Finally to get the new in formation out of the build and into the build wallboard

public void UpdateStatus(IBuildDetail detail)
{
    // any other results fields updates
 
    // and now the custom nodes
    IBuildInformation info = detail.Information;
    foreach (IBuildInformationNode infoNode in info.Nodes)
    {
        if (infoNode.Type == "org.stylecop")
        {
            // we have the correct node
            this.SetStyleCopWarnings(infoNode.Fields["total-violations"]);
            break;
        }
    }
}

So not a perfect solution, but but does everything I need at present.

MSB3155 errors in Team build when publishing to click once

If your team build project uses the Publish Target option (to create a ClickOnce deploy) you may see the error

BuildWallboard.csproj" (Publish target) (3:5) ->
(_DeploymentGenerateBootstrapper target) ->
MSB3155: Item 'Microsoft.Net.Framework.3.5.SP1' could not be located in BuildWallboard'.
MSB3155: Item 'Microsoft.Windows.Installer.3.1' could not be located in BuildWallboard'.

This is because on the build server needs a ‘default installation’ of Visual Studio Developer (or Suite). The publish function, like the MSTest function is not something the Team Build server can do bit itself it needs Visual Studio to do the heavy lifting.

Should my TFS Build Server be 32bit or 64bit?

I would say at this time unless you need 64Bit specific assemblies built you are best staying on a 32bit operating system. This will happily build MSIL .NET assemblies which I guess for most of us is the bulk of our work. OK you loose a bit of performance if you have 64bit hardware (or virtual hardware in our case), but I doubt this will be critical, shaving a few seconds of an automated build is not normally important.

My main reason for saying this is what as you extend your build process you will no doubt started to use community developed build activities, some of these seem to get a bit confused if you are on a 64bit OS. The issue seems to be that they cannot easily find the TFS Client assemblies in C:\Program File (x86) as opposed to C:\Program File. For example we have a build that automatically updates version numbers and deploys via ClickOnce; it works fine on a 32bit W2k8 build server, but on an identically configured 64bt W2K8 build server it gives the error:

error MSB4018: The "MSBuild.Community.Tasks.Tfs.TfsVersion" task failed unexpectedly.
error MSB4018: System.IO.FileNotFoundException: Could not load file or assembly 'file:///C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\Microsoft.TeamFoundation.Client.dll' or one of its dependencies. The system cannot find the file specified.

So what appears to be just a simple path issue, that is probably fixable in an XML configuration file or with search paths – but is it worth the effort? I would say not in general. I want to keep my installation as near default as possible, which I can with 32bit.

Getting MSB6006 errors for MSTest under TFS Team Build 2008

I have been rebuilding our TFS build systems on Hyper-V based virtualised hardware. The long term plan being to hold a configured build server as as Hyper-V template to we could prevision extra ones quickly, or rebuild all of them if we need to upgrade some library or tool; in effect to give us revision control over our build servers.

All seemed to be going OK, initially existing builds seemed to be running OK when targeted at the new server. However I soon saw that tests were failing with the error

MSBUILD : warning MSB6006: "MSTest.exe" exited with code 1

Further digging into the build log showed the tests were being run but the copy to the drop location was failing.

Side note: if you read older TFS documentations and many blogs it says to add the flag

/v:diagnostic

to the TFSbuild.rsp file to get more logging – this is wrong with MSBuild 3.5 as used by TFS 2008. This now defaults to the highest level of logging, so to reduced it you must use

/fileLoggerParameters:verbosity=normal

so no help in debugging. Anyway back to the plot……

In the past our single build server used a share on its own disk as the file drop, but now as we intend multiple build servers I decided to have a central build share on main data store server. This had been setup with read/write access to the folder and the share associated for the tfsbuild domain user that the Team Build service runs as.

Turns out this is not enough. You also have to give read/write access to the tfsservice domain user as well. It seems the publish of the test results comes from the TFS server  not the build process. hence needing the extra rights. Once the change is made all work fine

TFS TeamBuild and Sharepoint WSP deployment (and any post build events for that matter)

We use the SharePoint Visual Studio Project Template on CodePlex to create WSP deployment packages for our SharePoint features. I tend to think of this WSP creation project in the same way as a MSI installer; so we don’t put SharePoint components into the WSP solution itself, it is an extra project in the solution that assembles the components from a variety of other solutions (e.g. web parts, workflows, event receivers, shared libraries for the GAC etc) and builds a single deployable WSP file.

Running locally on a developers PC inside Visual Studio this template has worked well, the only change I make from the default is to alter the WSP projects pre-build event script to xcopy all the files into the correct directories to allow the VBScript files to create the WSP.

In our drive to automation and automatic testing I have been looking at getting the WSP created as part of our TFS Team Build process. It turns out you get a few problems because Visual Studio and Team Build do macro expansion differently.

So my Pre-build event becomes

echo PREBUILD STARTED

rem Check if we running in VS or Teambuild
if not exist "..\..\..\CLIENTLIBRARY\SharedLibProject\bin\$(ConfigurationName)\SharedLibProject.dll" goto tfsbuild

echo Copy from VS locations, in this sample we assume a shared library, a webpart and some javascript
xcopy "..\..\..\CLIENTLIBRARY\SharedLibProject\bin\$(ConfigurationName)\SharedLibProject.dll"  "$(ProjectDir)DLLS\GAC\"  /F /R /Y
xcopy "..\..\..\Web Part\bin\$(ConfigurationName)\*.dll"  "$(ProjectDir)DLLS\GAC\"  /F /R /Y
xcopy "$(SolutionDir)HOST\bin\HOST.dll"  "$(ProjectDir)DLLS\GAC\"  /F /R /Y
xcopy "$(SolutionDir)HOST\json*"  "$(ProjectDir)TEMPLATE\LAYOUTS"  /F /R /Y
xcopy "$(SolutionDir)HOST\*.js"  "$(ProjectDir)TEMPLATE\LAYOUTS"  /F /R /Y

goto end

:tfsbuild
echo Copy from TFS build locations

xcopy "$(outdir)\SharedLibproject.dll"  "$(ProjectDir)DLLS\GAC\"  /F /R /Y

xcopy "$(outdir)\WebPart.Core.dll"  "$(ProjectDir)DLLS\GAC\"   /F /R /Y
xcopy "$(outdir)\WebPart.UI.dll"  "$(ProjectDir)DLLS\GAC\"   /F /R /Y
xcopy "$(outdir)\Host.dll"  "$(ProjectDir)DLLS\GAC\"   /F /R /Y
xcopy "$(SolutionDir)HOST\json*"  "$(ProjectDir)TEMPLATE\LAYOUTS\json*"  /F /R /Y
xcopy "$(SolutionDir)HOST\*.js"  "$(ProjectDir)TEMPLATE\LAYOUTS\*.js"   /F /R /Y

:end

echo PREBUILD COMPLETE

Key points to note here are

  • For Visual Studio you can use Xcopy /s it makes no difference as there are no sub-directories (so you might ask why use it it all, I guess in some cases a generic copy all is easier than specifying a fixed file and directory). This is not the case for Team Build, if you use /s you can get multiple copies of DLLs in sub-directories created. This is because of the way Team Build structures it’s directories. The $(outdir)  is not a subdirectory of the $(solutiondir) as it is in Visual Studio, it is an absolute path defined for the build agents settings where all the outputs for all the projects in the build are assembled. So, depending on the project type, you seem to get sub directories. So it is best to be very specific as to what to copy, avoid wildcards and recursion.
  • When doing a wildcard xcopy as with json* files on Team Build you must specify the copy to file name i.e. json*, if you don’t you get the question ‘is the target a file or a directory’ message which obviously kills the build. This does not occur within Visual Studio.

It is also worth altering the post build event, by default the WSP is created in the project root, but if it is copied to the $(outdir) it ends up in the Team build drop location, so can be picked up by anyone, just like a DLL.

echo POSTBUILD STARTED
rem commented out as the build box does not have SharePoint installed
rem this could be wrappered in the chheck to see if the directory is present if we are on tema build or not
rem XCOPY "$(ProjectDir)TEMPLATE\*" "C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE" /S /F /R /Y

echo Run the VBscripts to create the XML files
"$(ProjectDir)CreateManifest.vbs" "$(ProjectDir)" "$(ProjectName)"
"$(ProjectDir)CreateCabDDF.vbs" "$(ProjectDir)" "$(ProjectName)"

echo Build the WSP
cd "$(ProjectDir)"
makecab.exe /F cab.ddf

echo Copy it to the out directory
xcopy *.wsp "$(TargetDir)\*.wsp" /y

echo POSTBUILD COMPLETE

However your problems do not end here. If you build this WSP project locally on a development PC all is fine. However (depending upon you project) it may fail on Team Build, well actually not fail just pause forever. This due to the way that Team Build checks out folders. The WSP project has a folder structure you drop files in that the VBScript files scan to create the manifest and then the WSP. If one of these directories is empty then it is not created on the build box and the VBScript stalls.

The solution is simply just add an extra folder exists check in the CreateCabDDF.vbs file’s EnumFolder method

sub EnumFolder(sFolder, sRelativePath)
    dim oFolder, oFolders, oSub, oFile
    
    rem this is the extra line
    If oFS.FolderExists(sFolder) Then

        set oFolder = oFS.GetFolder(sFolder)
    
        if (sRelativePath = "TEMPLATE") then sRelativePath = ""
        if (sRelativePath = "FEATURES") then sRelativePath = ""
    
        if (sRelativePath <> "") then sRelativePath = sRelativePath + "\"
    
        for each oFile in oFolder.Files
            oDDF.WriteLine """" + oFile.Path + """" + vbTab + """" + sRelativePath + oFile.Name + """"
        next

        if (sRelativePath <> "" and InStr(1, sFolder, "FEATURES") > 0) then
            sRelativePath = "FEATURES\" + sRelativePath
        end if

       for each oSub in oFolder.SubFolders
            EnumFolder oSub.Path, sRelativePath + oSub.Name
       next
    
      end if
    
end sub

Once this is all one the you can build the project in the Team Build

We Just Keep on Giving at Xmas …

Update – just needed to correct myself … it is a Kringle-O-Tron not a Robot Santa! D’oh!

In case you missed it … we are providing cut out and keep Santa and Kringle-O-Tron with our online Xmas cards this year.  They make up wonderful little models, with just folding and cutting!  As we can testify to by the number dotted around our offices.  Graphics Girl has done us proud.

Click on the picture for a bigger view … but visit the site to print them out next to ‘Cut Out and Fold Projects’.

foldsanta_robot

She has also provided the entire Senior Management Team at Black Marble with their own little models … if there is a demand, I can make these available too!

BizTalk 2009 and ESB 2.0

BizTalk 2009 CTP is now out along side ESB 2.0 CTP and RFID(Mobile)

BizTalk 2009 supports visual studio 2008 , SQL Server 2008 AND TFS with some great new tooling for development and application lifecycle management.

BizTalk RFID Mobile enhances BizTalk Server RFID by offering device management and offline processing capabilities using Windows CE based machines. BizTalk RFID Mobile is free to all BizTalk Server with Microsoft Software Assurance. With 2009 BizTalk RFID Mobile will be available as part of the  license.

The BizTalk 2009 CTP is available from Here.

The Enterprise Service Bus (ESB) Guidance 2.0 is available at Here.

b.