alkampfer on July 3rd, 2009

At this point I explained how to setup a build, and how to fully customize it editing the msbuild file to execute some tasks, like open an issue when one or more test fail.

Another interesting stuff to explain is how to execute custom code during the build, to demonstrate this concept I’ll show how to tweet a warning message when test phase fails. To execute custom code you simply need to create a custom msbuild task that does everything you want, then you simply need to call this custom task in the build script. The first step is creating the task.

public class TweetTask : Task
{
    [Required]
    public String Username { get; set; }
    [Required]
    public String Password { get; set; }
    [Required]
    public String Tweet { get; set; }

    public override bool Execute()
    {
        TwitterService service = new TwitterService();
        String tweet = Tweet.Substring(0, Math.Min(Tweet.Length, 140));
        return service.SendMessage(Username, Password, tweet);
    }
}

As you can see, creating a custom task is really simple, you should inherit from the Task base class and override the Execute() method. In this example everything is done in the TwitterService class that I took from this post. To pass parameters to this task you can simply create public properties in the task class, and use the [Required] attribute to specify that the caller absolutely needs to specify these properties to use the task.

Now you only need to compile this class into a dll, and make it avaliable to the build process. This is probably the most interesting part, because the build engine must be able to locate this dll in order to execute your custom action. Another requirement I want, is that you must be able to use your custom task without the need to physically go to tfs server and copy the dll into some directory. This because you must be able to fully configure the build with the same set of permission you have in tfs. I do not want to ask someone “Hey copy this dll into the tfs server”, I simply want to configure everything in visual studio.

This is a well known problem for everyone that works with Continuous integration machines, and the solution I like is inserting everything is needed for the build in a specific folder into the source control system of the project.

 image

As you can see I created a folder called BuildTools, inside it another folder called MsBuildCustomTasks and inside the compiled dll with my actino. Now I’m sure that the dll with my custom task is included into the source control system, and I can refer to it inside the TFSBuild.proj build file.

<UsingTask
        TaskName="DotNetMarche.MsBuildExtensions.Twitter.TweetTask"
         AssemblyFile="..\sources\BuildTools\MsBuildCustomTasks\DotNetMarche.MsBuildExtensions.dll"/>

to import the custom task you simply need to specify the task name and the assemblyFile in a <UsingTask> directive, as you can see the path of the dll is ..\sources\xxx where xxx is the path of the dll relative to the root of the source control system. Now if you do a check-in the next build will comprehend your custom task. This technique is useful, because you can be sure that each build always do a “Get Latest” to build the latest version of the source, thus getting also every tool it need to do the build.

Now you can use this task wherever you want:

<TweetTask
    Condition="'$(IsDesktopBuild)' != 'true' and '$(TestSuccess)' != 'true'"
    Username="alkampfer"
    Password="xxxxxxxxxxx"
    Tweet="Unit Test Failure in build number: $(BuildNumber)" />

As for the previous post, I’m asking to tweet a message to my twitter account when test phase fails during the build, I made a test fails, commit everything and after integration machine finished to build I can see this in my twitterDesk

image

WOW :D you can have your CI machine tweet whenever you want with less than 20 lines of code. You can now create a dedicated twitter account for every project you have, and you can follow status of the build in every device that supports twitter :D.

Alk.

Tags:



kick it on DotNetKicks.com

alkampfer on July 2nd, 2009

In last post I show how to configure test run in a team foundation build, simply editing the msbuild file. The aim of the post was showing how to make the entire build fail when a single test fails. To achieve this result I simply override a target and set some properties values.

In this post I’ll show how to automatically open an issue in TFS when a test fails. This is a standard requirement, because in such a way you are immediately aware when some test are failing.

<Target Name="AfterTest">

    <!-- Refresh the build properties. -->
    <GetBuildProperties TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
                                 BuildUri="$(BuildUri)"
                                 Condition=" '$(IsDesktopBuild)' != 'true' ">
        <Output TaskParameter="TestSuccess" PropertyName="TestSuccess" />
    </GetBuildProperties>

To execute some task after tests are run, you can simply override the target AfterTest then insert inside it all the tasks you like. To know result of tests we need to refresh some properties of the build, this is simply done with the GetBuildProperties task, you need to insert the serverUri, the BuildUri and ask to know the value of the TestSuccess parameter. Now you can know if some tests failed during test run, and you can create an issue if TestSuccess property is false.

<CreateNewWorkItem
    Condition="'$(IsDesktopBuild)' != 'true' and '$(TestSuccess)' != 'true'"
     TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
     BuildUri="$(BuildUri)"
     BuildNumber="$(BuildNumber)"
     Description="Test run failure in build"
     TeamProject="$(TeamProject)"
     Title="Unit Test Failure in build number: $(BuildNumber)"
     WorkItemFieldValues="$(WorkItemFieldValues)"
     WorkItemType="$(WorkItemType)"
     ContinueOnError="true" />
</Target>

The condition property is used to create the item only if the DesktopBuild is false and TestSuccess is also false, this means that issue are created only when the build is executed by the server and at least one test failed. You can configure every parameters but the most important one is the WorkItemFieldValues that can be specified in this way.

<PropertyGroup>
    <WorkItemFieldValues>
        priority =2; severity=3; rank =4; triage =Investigate
    </WorkItemFieldValues>
</PropertyGroup>

It must contains a list of issue properties that you want to set when you create the new work item. Now I reset back the TreatTestFailureAsBuildFailure to false, so the build will partially succeed even when some tests fails, but for each build that fails unit testing task an issue is automatically generated, with the desidered properties.

image

image

Configuring the build adding msbuild tasks is quite simple and permits you to fully configure your build.

alk.

Tags:



kick it on DotNetKicks.com

alkampfer on July 1st, 2009

Today I installed Tfs 2010 beta to look at new features; installation process of Tfs can be a complex operation but I must admit that in the 2010 version, the installer is more friendly. I installed sharepoint and sql server 2008 then I fired the installation of tfs. The main difference from the 2008 version is that it does not ask you anything, it just install, postponing the configuration after the installation is ok. When you access the Team Foundation Administration console, it presents you a configuration wizard.

image 

If you select “custom Configuration” you can fine tuning the configuration, you can choose as example the database you want to use.

image

Since I already configured sharepoint services and created sites I can specify them in the next configuration step.

image

You can configure almost anything with simple wizards, the overall process can be complicated if you are not familiar with the tecnologies involved, since you have to configure reporting services, integration with sharepoint etc. etc. When you finished configuring everything the wizard runs a check that tells you what is wrong and what is good.

image

From this simple list of errors and warning you can easily address every problem you can have, in this example I forgot to set the Database Agent in automatic execution, so I started it and do again a check.

During the whole installation I had only a little problem with error TF255275 that states

The following Web service for SQL Server Reporting Services could not be accessed: http://tfsd2010/ReportServer/ReportService2005.asmx

This is caused by a wrong configuration of reporting services, actually I completely forgot to create databases for Reporting services :), but the error is somewhat misleading me to wrong cause. you can find a detailed discussion of this error here.

I must admit that the installation process is more friendly and improved respect Tfs 2008.

Alk.

Tags:



kick it on DotNetKicks.com

alkampfer on July 1st, 2009

I start to got this error from my Continuous integration machine, after I setup a project for deploy with clickonce the build begins to fail. I’m using CC.net with msbuild scripts and in detailed error I see a message like

The "ResolveKeySource" task failed unexpectedly.

System.InvalidOperationException: Showing a modal dialog box or form when the application is not running in UserInteractive mode is not a valid operation. Specify the ServiceNotification or DefaultDesktopOnly style to display a notification from a service application.

This error happens because when the project has a certificate used by click once, you need to import that certificate in order to compile, and since my certificate is password protected the system need to show a form that ask for password to import certificate. Since cc.net runs as service it tries to shows the dialog, but it cannot gain access to a user interface and fail miserably.

The solution is to create a specific user to use for cc.net service (a good practice that you should always do), open a command prompt with credentials of that user, run your build script and wait for the form that ask you the password of the certificate. Once you give the password to msbuild script it installs into appropriate location and subsequent builds will run just ok.

Alk.

Tags:



kick it on DotNetKicks.com

alkampfer on June 29th, 2009

In previous post I showed how to setup a build in tfs that not only builds the solution, but also runs all the tests. The next step is to configure how tests are run and reacting to test result. The first thing I want is the ability to make the entire build fail if one of the test fails. As you see in the previous post, the default behavior of the build, is to partially fail if one or more tests fail.

This kind of option is not present in the wizard, and it is time to make your hands dirty. To unleash the full power of team builds, you need to know msbuild, in order to configure the build editing the msbuild file of the team build. First of all go to the team explorer, open the source control node (step 1), here you will find a folder named "TeamBuildTypes (step2) that contains a subfolder for each build definition, in the BuildWithTests folder there are a couple of file, the one named TFSBuild.proj (Step 3) is the one that contains all operations of the build.

image

In order to edit that file, you first need to grab a copy from the source control to your local folder, simply right click in the teamBuildTypes folder to “Get the latest version”

image

Ok now you can double click the tfsbuild.proj file to edit it. This is a simple msbuild file, and in the first lines you find this instruction

<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\TeamBuild\Microsoft.TeamFoundation.Build.targets" />

it imports a file called Microsoft.TeamFoundation.Build.targets that contains base targets for a build definition. This file permits you to override some specific target to execute custom code in specific moments of the build process. You can find a list of overridable targets here. From that list you can verify that there is a target called BeforeTestConfiguration that can be used to specify some custom configuration for test execution.

To fully understand how overriding works, you can open the Microsoft.TeamFoundation.Build.Targets file and look at the BeforeTestConfiguration target.

  <!-- Override this target to execute custom tasks before the testing of an individual configuration -->
  <Target Name="BeforeTestConfiguration" />

Since its only purpose is running your own code, it contains no task. Then you can verify on how it is used by the basic test runner task.

  <PropertyGroup>
    <TestConfigurationDependsOn>
      BeforeTestConfiguration;
      CoreTestConfiguration;
      AfterTestConfiguration;
    </TestConfigurationDependsOn>
  </PropertyGroup>
  <!-- Batch target for individual configuration testing -->
  <Target Name="TestConfiguration"
          DependsOnTargets="$(TestConfigurationDependsOn)"
          Outputs="@(TestOutputs)" />

...

From that code you can verify that test configuration depends on BeforeTestconfiguration, CoreTestConfiguration, AfterTEstConfiguration.Of these three targets, only CoreTestConfiguration contains real actions, the other two are there only to insert own task into the build process. If you look at the CoreTestConfiguration you can find this code.

    <PropertyGroup>
      <ContinueOnTestError Condition=" '$(StopOnTestFailure)' != 'true' ">true</ContinueOnTestError>
      <ContinueOnTestError Condition=" '$(StopOnTestFailure)' == 'true' ">false</ContinueOnTestError>
    </PropertyGroup>

Ok this is exactly what we need, the Continue on test property is set to true or false depending on the StopOnTestFailure variable. Another interesting piece of code is this one

  <Target Name="RunTest"
          DependsOnTargets="$(RunTestDependsOn)"
          Outputs="@(TestOutputs)">

    <MakeDir
          Directories="$(TestResultsRoot)"
          Condition="!Exists('$(TestResultsRoot)')" />

    <MSBuild Projects="@(ConfigurationList)"
             Properties="TreatTestFailureAsBuildFailure=$(TreatTestFailureAsBuildFailure)"
             Targets="TestConfiguration"
             StopOnFirstFailure="$(StopOnFirstFailure)">

That shows you an interesting property called TreatTestFailureAsBuildFailure, that is initially set to false. Now you have every information needed to solve the original problem, you can simply edit TFSBuild.proj file inside the definition of your build, and add this code, after the import statement of the file Microsoft.TeamFoundation.Build.Targets.

<Target Name="BeforeTestConfiguration">
    <Message Text="Configure test runner to make the entire build fails if a single test fails" />
    <PropertyGroup>
        <StopOnTestFailure>True</StopOnTestFailure>
        <TreatTestFailureAsBuildFailure>True</TreatTestFailureAsBuildFailure>
    </PropertyGroup>
</Target> 

As you can see, overriding a target is done simply redefining it in the build file. With this simple addition, the msbuild engine will call your BeforeTestConfiguration task that sets the StopOnTestFailure property to True and the TreatTestFailureAsBuildFailure also to true, thus asking to msbuild to make the entire build fails when the test task fails. Now if I fire a build with a failing test I see.

image

As you can see the entire build is considered to be failed, because we override the BeforeTestConfiguration. If you click on the Log file you can find the Message that confirms that your override task was really called.

Building with tools version "3.5".
Target "CanonicalizePaths" skipped. Previously built successfully.
Target "BeforeTestConfiguration" in file "C:\Users\tfsservice\AppData\Local\Temp\FluentMsTest\BuildWithTests\BuildType\TFSBuild.proj" from project "C:\Users\tfsservice\AppData\Local\Temp\FluentMsTest\BuildWithTests\BuildType\TFSBuild.proj":
Task "Message"
  Configure test runner to make the entire build fails if a single test fails
Done executing task "Message".

Configuring Tfs build is quite simple, it is only a matter of overriding certain specific targets to insert custom msbuild code in the main build process.

Alk.

Tags:



kick it on DotNetKicks.com