msbuild

Continuous Integration and Delivery with Visual Studio Team Services (Part 1)

How easy it is to use TFS online (aka Visual Studio Team Services) to build, run unit tests and deploy a simple.Net MVC website into Azure websites? This post is part 1 – building, running tests and creating the artifacts. Part 2 will look at using MS Release Management (part of VSTS too) to take the build output and deploy it to Azure websites. The goal is that when I check in my code, Visual Studio Team Services will compile it, test it and then deploy.

Recently I used the Visual Studio Team Services tooling to achieve CI and CD, and to my surprise it was quick and actually, reasonably pain free to setup. I was so pleased, I thought I’d write a couple of blog posts about it.

I created a simple .Net solution, that consisted of 3 projects.

  1. MVC Website
  2. Test Project
  3. Class Library

The website is a simple implementation of Binet’s formula to calculate the nth item in the Fibonacci sequence. Not important right now and I’ll go into the website side of things more in a subsequent post. I hooked it into a github repository, got it working and committed it.

Now the interesting part begins, of getting Visual Studio Online Visual Studio Team Services to create the build.

Step 1 – Go to Visual Studio Team Services, sign in/create a free account and create a new project, calling it Binet, selecting GIT as the source control.

step1

 

 

Hit Create. Next we need to connect it to our GIT repsoitory.  As our code is already hosted at GitHub, choose setup build.

step2

Next – we’re creating a build definition, online. Exciting times. From the options available we want to use the Visual Studio template.

step3

Hit Next. Now we need to connect the build definition to our github repository. All other defaults remain.

step4

 

For me, this popped out a new tab asking me to connect my VS online account to my GitHub account.

step5
Small gotcha for me – hitting the authorize button tried to create a popup that chrome blocked, so had to allow this popup).

Allow VS Online access to my github account

step6

I then selected my Binet respository, came back to VS Online and hit save, and we’re done! We have a complete build definition using virtually all the default settings.

Well, not quite. It won’t create the website in the artifacts folder. What the duce…
Yes, the most important part of building a website, is, well the website! By default it was creating just the test and class library project.

There is a solution though. This blog, details it.
The gist is we need to get msbuild to create the infamous _PublishedWebsites  folder, which contains all the files the website needs. This is achieved by passing these magic commands to msbuild:

/p:OutDir=$(build.stagingDirectory) /p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true

Navigate to the build definition, and change the msbuild arguments passed into the ‘Build Solution step.

step7

We want to make sure we publish all files to the artifacts directory, so we need to make a small change to the Copy files step. This is changing the contents to **\*

step8

Nearly there. As we have a moved the output slightly, we need to update the test step to be able to locate the test assemblies now. That involves changing the entry for test assembly from

**\$(BuildConfiguration)\*test*.dll;-:**\obj\**

to:

$(Build.StagingDirectory)\*test*.dll;-:**\obj\**

Which looks like this

step9

Now we are ready to try it. Hit the Queue new build button. I just accepted the default options and hit ok.

step10

and we’re off and waiting for a build agent. For me this didn’t take very long at all.

step11

Then the build starts

step12

…and succeeds!

 

step13

We can also look at the stats of the build, in the build summary. From here you can also view the artifacts to verify what was built.

step14

We now have an active build definition set up in Visual Studio team services. Every time a checkin is detected on our Github repository a new build is triggered.

In my next post I’ll show how to setup continuous delivery to Azure websites using the online Release Management tooling.

My Application.targets

This post sets out a way to enable TFS to copy and group applications files as well as web project files.

Problem

I have a Visual Studio solution with multiple projects. In particular I have a website, a web service (WCF) and a console application. I have TFS running onsite and a build definition associated with my solution. On check in, units tests are run and the build produces build output into a defined drop folder. TFS handily packages the website and web service into their own folders, living inside the _PublishedWebsites folder. The output of the console app is just dumped into the root of the drop folder. Ideally, we want it to be in its own folder and ideally in a folder like _PublishedApps. From here it can easily be picked up by our continuous delivery tooling to be deployed.

Distributed Solution

There are a couple of solutions out there on the web, lurking inside stackoverflow answers and suggesting themselves in other peoples’ blogs.  None answered it as clearly as I want and I’ve since lost the links to them, so this post is here to help me remember how to do it.

This Solution

I suspect there may be other ways of solving this problem. Please do let me know yours in the comments section.The crux of this solution lies in understanding how your web project files get copied to the PublishedWebsites folder in the first place.

The answer lies in the webproject .csproj file. Near the bottom of the file there is a line:

<Import Project=”$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets” Condition=”false” />

It turns out that WebApplication.targets file (comes with Visual Studio install I think) does all the fun stuff.

Find that file on your pc, on mine it’s here:

C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\WebApplications

At this point I confess my knowledge about msbuild scripts comes largely from google. I understand that it’s copying files needed for the website to a directory; this directory is defined near the top:

<WebProjectOutputDir Condition=”!$(WebProjectOutputDirInsideProject)”>$(OutDir)_PublishedWebsites\$(MSBuildProjectName)</WebProjectOutputDir>

TargetYou need a new targets file         

In order for our console application to copy its files to its own output folder, I wanted a .targets file for applications, not web sites.

There isn’t one out of the box, like there is for websites. So we need to create it. Fortunately there’s a shortcut; I call it Ctrl C, Ctrl V. seriously… make a copy of the WebApplication.targets file. Place it inside your solution file structure and name it something different, like Application.targets, for instance.

Next make two amends:

In the file find, <WebProjectOutputDir Condition=”!$(WebProjectOutputDirInsideProject)”>$(OutDir)_PublishedWebsites\$(MSBuildProjectName)</WebProjectOutputDir>

Change the name of the output folder, to _PublishedApps, for instance:

Find <WebProjectOutputDir Condition=”!$(WebProjectOutputDirInsideProject)”>$(OutDir)_PublishedApps\$(MSBuildProjectName)</WebProjectOutputDir>.

Inside <Target Name=”_CopyWebApplication”>, add: <Copy SourceFiles=”$(OutDir)$(TargetFileName).config” DestinationFolder=”$(WebProjectOutputDir)\bin” SkipUnchangedFiles=”true” />

The first is just a change to the directory name where files should be output too.
The second is a change to help it copy and rename the app.config file.

The final part of the puzzle is to amend your console app project to use the new .targets file.
Open the project file and immediately before the <target name=”beforebuild”> section add:

<Import Project=”..\build\Application.targets” />

Getting the relative path to your targets file correct. Save it all, check it all in (inc. the .targets file) and you should get a new output folder in your drop location, specifically for your console application’s files.

Written in August 2015, using TFS 2013 and Visual Studio 2013.

Image credit: Flood G