TFS2010 WP7 Continuous Integration

Justin Angel picture

Justin
Angel

Hi Folks,

In this blog post we’ll cover how to set up automated (nightly?) builds on a Team Foundation 2010 Build Server for Windows Phone 7 projects.
The core challenge we’ll face is not having Visual Studio, Windows Phone 7 Tools or Windows Phone 7 SDK installed on the Build Server.

Windows Phone 7 Logo  This is the VS2010 Logo. TFS2010 doesn't have a logo. Let's pretend this is the non-existing TFS2010 logo. SSSsshhh, don't tell anyone.

You can get a sample project with all the modifications discussed in this blog post at: http://JustinAngel.net/Storage/Justin.WindowsPhone.BuildFromLocalFiles.zip

 

Prerequisite Reading

 Prerequisite Reading

There’s a blog post that I highly recommend you’ll read before embarking on this quest.

Building Silverlight 3 and Silverlight 4 applications on a .NET 3.5 build machine by Jeff Wilcox 
In the linked article Jeff explains how to setup a TFS Build Server for Silverlight. 
The blog post you are currently reading is heavily influenced by Mr. Wilcox approach to setting up a build server. Mainly because the writer of this blog post was schooled in the “Wilcox School of Application Packaging and offensive driving”.
If you’d like to setup a Continuous Integration in TFS for a Silverlight project, please read Mr. Wilcox’s article. This blog post only deals with WP7 projects.

 

The Problem – We don’t have WP7 Installed on a Build Server

A Diagram of 4 Developers using 4 different WP7 versions. Asking What version will we install on the server?

Imagine this situation, you’re in a company that has multiple Windows Phone 7 projects on the same build server. Or maybe you’re hosting your TFS2010 Build server and multiple companies are using the same server.
Some project could be prototypes, and some projects could be completely different projects.

All of these projects are using different versions of the WP7 Tools.
If we were talking about Silverlight projects we would be talking about Silverlight 2, Silverlight 3 and Silverlight 4 projects.
In WP7’s case it would be different beta shipped at different months for the Windows Phone 7 developer tools.
However, since a server can only have 1 version installed at any given point in time – one project upgrading the server build version breaks all other projects.

 A diagram showing a developer upgrading to a new version breaking the build for all projects

For instance, in Vertigo we’ve got multiple Windows Phone 7 projects we’re working on for different customers.
We can’t guarantee that these multiple projects which are on different schedules with different deliverables will all upgrade together.

 

The Solution – Don’t install WP7 Tools at all, use local resources

Since the problem here is that our WP7 projects have a dependency on installed software, let’s make sure we sever all of these ties.
The ties between our projects and installed WP7 Tools are built into our MSBuild scripts. We’ll be focusing our efforts in this blog post on those MSBuild scripts.

1. Setup an “ExternalDependencies”/”ExternalTools” directory in source control.
As my own best practice, I establish a “Build” directory nested underneath that folder, and underneath it a “WP7_<Version>” folder. But these two last folders are just my own personal convention.  
 Suggest Solution Structure and Source control folder structure

2. Drag & drop the contents of the WP7 MSBuild central directory into the “ExternalDependencies/Build/WP7_<Version>” folder.
On a x64 dev machine the folder is located on: C:\Program Files (x86)\MSBuild\Microsoft\Silverlight for Phone\v4.0 

WP7 MSBuild Extensions dragged & dropped into source control

3. Create another nested folder named “Reference Assemblies” and copy the entire WP7 SDK into it.
On a x64 dev machine the WP7 SDK folder is located at: C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\Silverlight\v4.0\Profile\WindowsPhone

 WindowsPhone SDK dragged & dropped into Source Control

4. In the folder holding the default *.targets files (“ExternalDependencies/Build/MSBuild_WP7_Apri10”), add a new <companyName.WP7.Version>.Targets file.
In this example the file is named “Vertigo.WP7.April10.targets”.

Paste in the following MSBuild script:

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

  <PropertyGroup>

    <SilverlightBuildResources>$(CompileTimeSolutionDir)ExternalDependencies\Build\MSBuild_WP7_Apr10\</SilverlightBuildResources>

    <TargetFrameworkDirectory>$(SilverlightBuildResources)Reference Assemblies\</TargetFrameworkDirectory>

    <TargetFrameworkSDKDirectory>$(SilverlightBuildResources)Reference Assemblies\</TargetFrameworkSDKDirectory>

    <_TargetFrameworkSDKDirectoryItem>$(SilverlightBuildResources)Reference Assemblies\</_TargetFrameworkSDKDirectoryItem>

    <_FullFrameworkReferenceAssemblyPaths>$(SilverlightBuildResources)Reference Assemblies\;</_FullFrameworkReferenceAssemblyPaths>

    <_TargetFrameworkDirectories>$(SilverlightBuildResources)Reference Assemblies\;</_TargetFrameworkDirectories>

    <SilverlightRuntimeVersion>3.0.40624.0</SilverlightRuntimeVersion>

  </PropertyGroup>

  <Import Project="Microsoft.Silverlight.WindowsPhone.Overrides.targets" />

  <Import Project="Microsoft.Silverlight.CSharp.targets" />

</Project>

5. Open up the “Microsoft.Silverlight.Common.targets” file (from “ExternalDependencies/Build/MSBuild_WP7_Apri10”) and comment out Lines 78-92.
The reason we have to do this edit, is because the default WP7 MSBuild script from Microsoft accidently uses registry settings instead of relaying on local values.

        <!--<GetSilverlightFrameworkPath

            RegistryBase="$(FrameworkRegistryBaseWithVersion)"

            RuntimePathRegistryKey="$(RuntimePathRegistryKey)"

            RuntimeVersionRegistryKey="$(RuntimeVersionRegistryKey)"

        >

            <Output TaskParameter="SilverlightPath" PropertyName="TargetFrameworkDirectory" Condition="'$(TargetFrameworkDirectory)' == ''"/>

            <Output TaskParameter="SilverlightSDKPaths" ItemName="_TargetFrameworkSDKDirectoryItem" Condition="'$(TargetFrameworkSDKDirectory)' == ''"/>

            <Output TaskParameter="SilverlightRuntimeVersion" PropertyName="SilverlightRuntimeVersion" Condition="'$(SilverlightRuntimeVersion)' == ''"/>

        </GetSilverlightFrameworkPath>-->

 

        <!-- Reset some items from the above task. Will remove when we merge with SL build system -->

        <PropertyGroup>

            <!--<_FullFrameworkReferenceAssemblyPaths>$([Microsoft.Build.Utilities.ToolLocationHelper]::GetPathToStandardLibraries($(TargetFrameworkIdentifier), $(TargetFrameworkVersion), ''))</_FullFrameworkReferenceAssemblyPaths>-->

            <!--<TargetFrameworkDirectory>$([Microsoft.Build.Utilities.ToolLocationHelper]::GetPathToStandardLibraries($(TargetFrameworkIdentifier), $(TargetFrameworkVersion), $(TargetFrameworkProfile)))</TargetFrameworkDirectory>-->

        </PropertyGroup>

6. For every WP7 Project that needs to use local resources, we’ll have to edit the *.csproj file and replace the 2 default <Import> XML elements.

Right Click on your project and choose “Edit Project File”:

Right click Project file --> Edit Project File 

BTW, The “Edit Project file” context menu item comes from Visual Studio 2010 PowerCommands.
If you don’t have those installed, you’ll have to manually choose “Unload Project –> Edit File” on each project.
Thanks to Allen Newton who told me about PowerCommands!

In the *.csproj we’ll see the 2 default <Imports>:

<Import Project="$(MSBuildExtensionsPath)\Microsoft\Silverlight for Phone\$(TargetFrameworkVersion)\Microsoft.Silverlight.$(TargetFrameworkProfile).Overrides.targets" />

<Import Project="$(MSBuildExtensionsPath)\Microsoft\Silverlight for Phone\$(TargetFrameworkVersion)\Microsoft.Silverlight.CSharp.targets" />

We’ll comment out these <Import> elements and include our new <Import> with some flavouring to make Blend 4 RC to work with it well.

  <!-- This MSBuild script compensates for Blend Design time having the wrong SolutionDir -->

  <PropertyGroup>

    <MissingExternalDependenciesBlendDesignTimehack>false</MissingExternalDependenciesBlendDesignTimehack>

    <MissingExternalDependenciesBlendDesignTimehack Condition="!Exists('$(SolutionDir)ExternalDependencies')">true</MissingExternalDependenciesBlendDesignTimehack>

    <CompileTimeSolutionDir Condition="'$(MissingExternalDependenciesBlendDesignTimehack)'!='true'">$(SolutionDir)</CompileTimeSolutionDir>

    <CompileTimeSolutionDir Condition="'$(MissingExternalDependenciesBlendDesignTimehack)'=='true'">$(SolutionDir)..\</CompileTimeSolutionDir>

  </PropertyGroup>

  <Import Project="$(CompileTimeSolutionDir)ExternalDependencies\Build\MSBuild_WP7_Apr10\Vertigo.WP7.Apr10.targets" />

  <!--<Import Project="$(MSBuildExtensionsPath)\Microsoft\Silverlight for Phone\$(TargetFrameworkVersion)\Microsoft.Silverlight.$(TargetFrameworkProfile).Overrides.targets" />-->

  <!--<Import Project="$(MSBuildExtensionsPath)\Microsoft\Silverlight for Phone\$(TargetFrameworkVersion)\Microsoft.Silverlight.CSharp.targets" />-->

 

7. We’re done.
Checkin to the server and as long as all files are in source control and all paths are correct the project will build on a server with no Windows Phone 7 Tools.

 Success

 

Setting up a new TFS Automated Build

 Setting up a new Build Definition in VS2010

In terms of setting up a new TFS2010 Build Definition for WP7, it’ll all plain old setup and pretty easy & straightforward.

There’s one major caveat we should call out: Make sure to set the build agent to X86. 
MSBuild Platform x86, Image courtesy of Benjamin Day

If this step if not followed we’ll see a myriad of cryptic errors, like these ones:

TFS2010 Build error when Build Agent is Auto. Image courtesy of Benjamin Day.

If you’re interested in more information about this issue please read TFS2010 Build failed -- “Microsoft.Silverlight.Common.targets (104): The Silverlight 4 SDK is not installed” by  Benjamin Day.

Summary

You can get a sample project with all the modifications discussed in this blog post @ http://JustinAngel.net/Storage/Justin.WindowsPhone.BuildFromLocalFiles.zip

Here’s a summary of the changes we needed to make in order for our project to run build successfully on a WP7-less TFS2010 Build server:

image 

 

Fin

We’ve talked about why we it’s a smart move to avoid installing SDKs on our Build Server.
Additionally we’ve shown how to setup a WP7 project to run on a Build Server that doesn’t have WP7 Tools installed at all. 

Hopefully this blog post will help you on your way to Continuous Integration for Windows Phone 7.

 

Leave a comment

What are your thoughts on this topic? Was this blog post useful?

 

Sincerely,

-- Justin Angel



Comments