Jenkins: Configure CI with TFS, NSUnit – Build, Package

Today I want to tell about the way to create a C.I. with Package and Deploy with Jenkins. Jenkins is “an extendable open source continuous integration server”. There are a lot of good articles on internet which explain what is jenkins and the base configuration

http://marcofranssen.nl/ci-with-jenkins-msbuild-nuget-and-git-part-1/
http://codingcockerel.co.uk/2008/05/18/how-to-publish-a-web-site-with-msbuild/
http://jenkinsheaven.blogspot.ch/2013/08/automating-net-builds-its-not-all-about.html
http://yakiloo.com/jenkins-tfs-and-msbuild/

but it is difficult to find tutorial or article that discuss about NSUnit, configuration and Packages together. First of all we need to create a a simple MSBuild script with all steps that we need.
In this first post, we can discus about the msbuild script. Now we prepare a script to put inside our jenkins:

1 – Clean Solution

<ItemGroup>
	<Solution Include="${RootPath}\src\TestProjectComplete.sln"/>
</ItemGroup>
<Target Name="Clean">
	<Message Importance="high" Text="Cleaning folders"/>
	<RemoveDir Directories="$(BinPathUnitTests)" />
	<!-- Clean the source code projects -->
	<MSBuild Projects="@(ProjectFiles)"
	ContinueOnError="false"
	Targets="Clean"
	Properties="Configuration=$(Configuration)" />
</Target>

2 – Get packages from Nuget

<!-- The LoadNuGetPackages Target -->
<ItemGroup>
	<NuGetPackageConfigs Include="E:\workspace\TestProjectComplete\src\**\packages.config" />
</ItemGroup>
<Target Name="LoadNuGetPackages">
	<Message Importance="high" Text="Retrieving packages for %(NuGetPackageConfigs.Identity)" />
	<Exec Command="&quot;$(SrcPath)\.nuget\nuget&quot; install &quot;%(NuGetPackageConfigs.Identity)&quot; -o &quot;$(SrcPath)\packages&quot;" />
</Target>

3 – Build projects

<Target Name="Compile">
	<Message Importance="high" Text="Compiling projects"/>
	<MakeDir Directories="$(BinPathUnitTests)" />
	<MSBuild Projects="$(SrcPath)\TestProjectComplete\TestProjectComplete.csproj" Properties="Configuration=$(Configuration);Platform=$(Platform)" />
</Target>

4 – Run unit test

<!-- Running Test -->
<Target Name="NUnit">
	<ItemGroup>
		<TestAssembly Include="$(BinPathUnitTests)\*.test.dll" />
	</ItemGroup>
	<Message Text="NUnit is running on: @(TestAssembly)" />
	<Nunit ToolPath="$(NUnit-ToolPath)" Assemblies="@(TestAssembly)" OutputXmlFile="$(BinPathUnitTests)\test-results.xml"/>
</Target>

5 – Packages

<Target Name="Package">
	<MakeDir Directories="$(Publish)" />		
	<MSBuild Projects="$(SrcPath)\TestProjectComplete\TestProjectComplete.csproj"
		Properties="Configuration=Debug;WebProjectOutputDir=$(Publish);OutDir=$(Publish)\bin"
		Targets="ResolveReferences;_CopyWebApplication" />
</Target>	

In my Github repository you can find the msbuild script (here). The next post we discuss how to configure jenkins to use this script.

Annunci

TFS Event Handler for Team Foundation Server

Yesterday I needed to implement create something to update our internal application when a task on TFS is changed. After some time on scouting I found this excellent post about a new type of integration available in TFS, namely server side event handlers, that is executed within the TFS context.

In the past if you wanted to execute something whene events occurs in TFS you needed to implement a WCF service with a predefined signature and subscribed to the event using bissubscribe.exe.Now this can be done using server side events.

Before to start to development we need to install the TFS server on our dev machine because we need the follow libraries:

using Microsoft.TeamFoundation.Common;
using Microsoft.TeamFoundation.Framework.Server;
using Microsoft.TeamFoundation.WorkItemTracking.Server;

We can find these inside …Microsoft Team Foundation Server 11.0\Application Tier\Web Services\bin folder. We can install the basic setup.
Now we can run Visual Studio as admin and start to create our Event Handler project.
We create a standard C# class library.

using System;
using System.Diagnostics;
using Microsoft.TeamFoundation.Common;
using Microsoft.TeamFoundation.Framework.Server;
using Microsoft.TeamFoundation.WorkItemTracking.Server;

namespace Algraps.TestProjects.TFSServerHandler
{
    public class WorkItemChangedEventHandler : ISubscriber 
    {
        public Type[] SubscribedTypes()
        {
            return new Type[1]{typeof(WorkItemChangedEvent)};
        }

        public EventNotificationStatus ProcessEvent(TeamFoundationRequestContext requestContext, NotificationType notificationType, object notificationEventArgs, 
                                                    out int statusCode, out string statusMessage, out ExceptionPropertyCollection properties)   
        {
            statusCode = 0;
            properties = null;
            statusMessage = String.Empty;
            try
            {
                if (notificationType == NotificationType.Notification && notificationEventArgs is WorkItemChangedEvent)
                {
                    WorkItemChangedEvent ev = notificationEventArgs as WorkItemChangedEvent;
                    int workItemId = Convert.ToInt32(ev.CoreFields.IntegerFields[0].NewValue); 
                    EventLog.WriteEntry("WorkItemChangedEventHandler", "WorkItem " + ev.WorkItemTitle + " - Id " + workItemId.ToString() + " was modified");
                }

            }
            catch (Exception)
            {
            }
            return EventNotificationStatus.ActionPermitted;
        }

        public string Name
        {
            get { return "WorkItemChangedEventHandler"; }
        }

        public SubscriberPriority Priority
        {
            get { return SubscriberPriority.Normal; }
        }
    }
}

In the code every time a work item is modified on TFS, we write the Title and the id on Event log.

The Deploy is simple: Open the project properties and go to the Build tab. Modify the Output Path by browsing to the Plugins directory on TFS. This will result in a new
deployment of your event handler every time you build. The deployment of a server side event handler couldn’t be simpler, just drop the assembly containing the event handlers into the Plugins folder of TFS, which is located at ..Microsoft Team Foundation Server 2010\Application Tier\Web Services\bin\Plugins.

We can debug this handler. To do this one, we need to attach to Process w3wp process that hosts TFS. This should cause your event handler to be executed immediately.

title

In the WorkItemChangedEvent object, we have ev.CoreFields.IntegerFields and ev.CoreFields.StringFields These two array all all properties of our workitem. For every workItem we have two attributes: NewValue and OldValue.

In NewValue we have the value modified and in the OldValue there is the value before to modify.

imgnewvalue

We discussed on WorkItemChangedEvent. But you can subscribe to another events. To do that, just add more event types in SubscribedTypes method. You could find a list of available events list

TFS Integration – TF237124 – Work Item is not ready to save

With this post, I want start a new category: TFS Integration…

For a project I had to create some TFS Work Items programmatically using the TFS API. However saving the work item resulted in the following error message:

TF237124: Work Item is not ready to save

This error message doesn’t give any useful information. What’s important to know is that you can configure a lot of rules before a work item is valid. It’s important to validate the WorkItem prior to save. The validate() method will return an arraylist of invalid fields.

This will give you all the information you need to know why this workitem cannot be saved (In this case I have 3 invalid fields; in the following image, for example, U have the “Backlog Priority” field with an invalid value).

validate

Changing local path in team foundation server

application-lifecycle-managementIf you want to change the local path for the working directory of the Team Foundation Server (TFS), you need to go to File -> Source Control -> Workspaces, then select your workspace (it should match your computer name) and click Edit.

In the next dialog change the mapping for the root TFS node to the new location on your hard drive.

Important! You need to perform a “Get” on the whole TFS tree to update project associations.