VSoft Technologies Blogs


VSoft Technologies Blogs - posts about our products and software development.

FinalBuilder offers you tight integration into TFS with an easy to understand IDE. In this post I will go into how to integrate FinalBuilder into your TFS build process. The post will cover;

To make sure this post doesn't rival "war and peace" in size, I will assume a few things during the post. Namely that you have used TFS in some fashion, and/or have gotten a solution building under TFS with the default TFS template. For more information on getting up and running with TFS and common issues with TFS I suggest taking a look at the TFS ranger books and blog.


To follow along with this post you will need the following installed:

The Team Foundation Server can be of any configuration as long as it has at least one agent and a reporting service. FinalBuilder 7 is required on the agent machine, and could also be installed on the developer’s machine for editing of scripts. Agents for Microsoft Visual Studio 2013 will provide access to VSTest.Console which we require for testing on the build agent. Lastly, Team Explorer is required for interaction with source control from FinalBuilder’s IDE. Without this installed source control will need to be done manually.

Adding a TFS build process

To start I have a solution under source control on a TFS 2013 collection. The solution I will be using is under a team project called VSoftSFTPLibrary  under the collection “TFS2013\DefaultCollection”.  The layouts of the team project looks like the following:

Define Report

I have a directory for the SFTP projects source, library files and its tests. The layout of your source control may vary from mine, however the main point to note here is that separating out directories isn’t an issue. With the solution, all related files, and binaries under source control I now add a build definition to the team project.

Build Name

Next the folders to be used in the FinalBuilder script need to be mapped from the server to an agent location. It’s important to map all folders which contain files required for the build process. At this stage we only really know of the Source directory we are going to be build and the Library folder which the source relies on. Note that if your solution relies on a certain structure of folders this structure should be the same when it arrives on the agent. In the example the source and library paths are at the same folder depth, therefore this is reflected on the agent side.

Define Report

When the build is finished usually we want them “dropped” somewhere on the network. A FinalBuilder script can use this drop location, which we will go into later on in the artcile. For now I set this to a server location accessible by the build agent service user.

Drop Folder

Using FinalBuilder build process templates

By default the build process is set to the default build process which comes with TFS2013. The template is called “TfvcTemplate.12.xaml”. When used the default template will enable the building, testing, impact testing, and deployment of a solution and its projects. Our aim is to perform all the same build activities with the additon of a FinalBuilder project. 

To this end, the build process template needs to be changed over to one of the two supplied with FinalBuilder. In the [%ProgramFiles(x86)%\FinalBuilder  7\TFS Templates\2013] folder there are two TFS 2013 build workflow templates. “FinalBuilderTFS2013Build.xaml” performs all the same steps as the default build workflow and adds a FinalBuilder step just after the MSBuild activity and just before the optional “after MSBuild script”. This script is typically used by those looking to convert current default script builds to FinalBuilder in a simple and piece-meal fashion. 

Define Report

The “FinalBuilderOnlyTFS2013Build.xaml” template is used when the FinalBuilder script is to take over the entire build process. For the moment I will use the “FinalBuilderTFS2013Build.xaml” script. Add these two scripts to the team project, typically under a BuildTemplates folder to separate them from the source and library code. 

Add FB Template

Copy these templates into the local mapped location for this team project, and check them into source control. Now the “FinalBuilderTFS2013Build.xaml” template can be selected as the build process template. To do this add a new new build in the process section of the build definition. Navigate to the source control location where the template is stored and select it.

New Template For Build

Configuration of the FinalBuilder template

The next step is to fill in the parameters for the build process. The majority of these are the exact same as the default TFS 2013 template with the addition of some FinalBuilder specific settings. The FinalBuilder section of settings allow for the specification of the project file, and custom arguments for the FinalBuilder project. Note that the “2. Build | Projects”, and the “6. FinalBuilder | Project File” are both required by the build template. These are used to determine what should be built and what FinalBuilder project should be run. 

Define Report

To run a FinalBuilder project we need to create one. Therefore create a FinalBuilder project with just an [Action Group] action for the moment. Save this project to the team projects FinalBuilderScripts folder and check it into source control.

Project Added To Source Control

Once the FinalBuilder project is in source control select it in the build process using the file selector provided through the ellipse selector. You should end up with something reading like this “$/VSoftSFTPLibrary/FinalBuilderScripts/BuildVSoftSFTPLibrary.fbp7”

Now that we have included the FinalBuilder project into our build process we need to make sure its folder is mapped to the agent. Open the source settings section, and add a mapping for the folder in which the FinalBuilder project resides. Something like the following should be what results. 

Define Report

Queue the build and the log should read like the following excerpt. The [Action Group] line is the action group you added in the FinalBuilder project. 

Successful Run With Just an Action Group

So now we have a TFS build process which is able to call a FinalBuilder script. In the next section we will delve more into how to extract information from TFS about the build inside our FinalBuilder script. 

Retrieving information from TFS in a FinalBuilder Script

For the FinalBuilder script to be of use in the TFS build process, it requires information about the TFS build currently running. To provide this we offer a number of actions that can extract this information during the TFS build run. To get you started, there is an example project in <FinalBuilderInstallDir>\TFS Templates called TFSExample.fbp7. This sample project contains examples of the actions to use during a TFS build process.  

Define Report

The [Get Team Foundataion Build Parameters] action is a special action that is only useful when a project is launched from TFS. It assigns TFS data to the specified project variables. 

Foundation Build Params

Each of the variables in the [Get Team Foundation Build Parameters] action are as follows:

  • Team Server URL: This is the URL of the team foundation server that queued the build.
  • Team Project: Is the name of the team project the build belongs to.
  • Build Id: Is the unique number allocated to this build.
  • Platform/Flavor: These are the build parameters for the compilation of the solution to be built.
  • Default Solution File: The solution file listed as the primary for the team project.
  • Solution File List: The list of solutions to be built by the build process.
  • Deployment Folder: The drop folder configured for the build process. It is blank if it is not set.
  • Source Root: The first listed solutions root folder.
  • Working Directory: A working directory on the agent for the current build definition. Typically space which is shared between builds made on the same agent.

On the Custom Arguments tab is a list of ten variables which can be passed from the TFS build process to FinalBuilder. These are passed as plain text and converted to the variable types used to read them in the FinalBuilder script.

For my script I only wanted to get the Team Foundation Build Parameters, and the variables that it used. So first I checked out the “BuildVSoftSFTPLibrary.fbp7” project using the built in source control features of FinalBuilder.

First I need to make sure that it is indeed added to source control. If it hasn’t detected that it is part of the TFS source control at this stage I add it to source control. I make sure to select the “Microsoft Team Foundation Server MSSCCI provider” which will use the Team Explorer 2013 installed on the machine. I select the TFS 2013 server and collection I am working with, also making sure the team project is correct. Once this is done I am then able to use the file menu to check the project out ready for editing. 

Next I copy all the variables I want from the TFSExample project, and paste them into my BuildVSoftSFTPLibrary.fbp7 project. To paste the variables I open the Variables Editor, right click and select paste.

Define Report

Last I copy over the [Get Team Foundation Build Parameters] and [Trigger Files Iterator] actions. These use the variables we just copied over and will hook themselves up as they appeared in the example project. 

Now we can check in these changes and queue the build. 

In the log for the build you will see the following:

By default the [Get Team Foundation Build Parameters] action will write what it has retrieved from TFS to the build log. Something to keep in mind when debugging a FinalBuilder script in TFS.

Creating a FinalBuilder Only build process

So now we want to make the FinalBuilder process take over the build completely. The first thing to do here is to stop the TFS build process from building, testing, and publishing results of the build. This requires changing the build workflow to remove the activities which do this (otherwise we would be doing things twice), and updating the FinalBuilder script to perform these tasks. 

Instead of working out which activities to remove from the build template we provide a build template with all the build and testing activities removed. The “FinalBuilderOnlyTFS2013Build.xaml” template which was copied into the BuildTemplates folder is this template. 

In the process section of the build definition, create a new build process using the “FinalBuilderOnlyTFS2013Build.xaml” file. You will notice that nearly everything in the build parameters is the same except now the before and after script events have been removed. Also the testing section is no longer present. All of this will be handled by the FinalBuilder script.

Once again open your FinalBuilder project for this build and check it out. Also open up the TFSExample.fbp7 project and take a look at the [Build VS.Net Solution] action. Copy this action to the project used to build your solution. 

The [Build VS.NET Solution] action builds a Visual Studio.NET solution. On the [Solution] tab you will see that the Solution File is set to “%SourceRoot%\<YourSolution>.sln”. Replace <YourSolution> with the name of the solution that you wish to build. Note that “%SourceRoot%” will be the directory of only the first solution in the list of projects to build. In my project I ended up with a Solution File value of “%SourceRoot%\VSoftSFTPLibrary.sln” for the [Build VS.NET Solution] action.

On the [Paths] tab you will see that the Output Directory is set to %SourceRoot%\Binaries. You may change this if you wish, but it's it not necessary. Note because the drop location may be on a different server to the build agent, it is important that VSTest runs on files located on the build agent machine. Unless you explicitly set up the trust relationship, .NET will not allow executing of assemblies on remote machines. This is why we build and test in a directory under %SourcesRoot% and then move the files to the drop location after testing. This will be covered more in the next section. 

On the agent the TFS agent the FinalBuilder options for Visual Studio will need to be set. If not and DEVENV.COM is required, the build will fail about the build tool location being unknown.

Now we are ready to run the build with using just FinalBuilder. Queue the build again and the project will build, not from a template activity but from the FinalBuilder script it is running. 

Adding running and publishing of tests

To perform testing we need to add a [Run VSTest.Console] action to the FinalBuilder project. The [Run VSTest.Console] uses VSTest.Console to run your test assemblies. On the [Settings] tab add the name of your test assembly to the list. You should end up with something along the lines of “%SourceRoot%\Binaries\<YourTestAssembly>.dll”. On the [Publish Results] tab the action should be set to automatically publish the results to the TFS server. This means that after the tests are run they will automatically be stored with the build on the TFS Server.

Note that the [Ignore Failure] option, located on the [Options] tab, is important. If any unit tests fail, the [Run VSTest.Console] action will fail, and setting [Ignore Failure] allows the FinalBuilder and TFS builds to continue. Un-check [Ignore Failure] if you would prefer the build to stop on failed tests. In either case, test failures will appear in the TFS build log and in TFS reports.

On the agent the TFS agent the FinalBuilder options for VSTest.Console will need to be set. If not, the build will fail with an error about the VSTest.Console location being unknown.

Moving files to the drop location

The last step to complete the process is to move all the files from the agent to your drop location. The simplest way to achieve this is by a [Move File(s)] action. We already have the drop folder location stored in the %DropShare% variable. It is this value which we then use in the [Move File(s)] action.

Once this is run we will have a built solution, with tests run, and the binaries copied into the specified drop folder. 

Roy Osherove posted an interesting video on youtube recently, talking about the difference between Automated Builds and Continuous Integration.

This is a subject that comes up often in emails from existing and potential customers. Why do I need FinalBuilder if I have Continua CI, or, why haven't we added all the functionality of FinalBuilder to Continua CI?

Roy sums up the differences and reasoning in this video quite nicely.

Roy goes into more detail in his "newish" book , Beautiful Builds. Lots of interesting food for thought. Lets face it, most developers probably don't spend too much time "deep thinking" how the build side of things should be done. Roy's book is full of "deep thinking", but Roy sums it all up quite nicely! It's not a long book, around 40 pages and definitely worth a read.

FinalBuilder and Continua CI

The workflow functionality in Continua CI is inspired by FinalBuilder (which is probably stating the obvious to FinalBuilder users), but the functionality that is there is fairly high level. Your Continua CI Stage workflow can be as simple as a single action (for example a FinalBuilder Action or MSBuild, or Rake or Powershell....), or you can make use of the flow control, logic, file operation actions etc and keep your build scripts as simple as your .sln file (or .dproj for delphi developers). That's for you to decide. Of course our recommendation is to use FinalBuilder (and I say "of course" because I have wages to pay!) but there are obvious benefits to using FinalBuilder for your automated build scripts.

Develop and debug your build scripts on your machine

Using FinalBuilder, you can develop and debug your build script on your machine. FinalBuilder allows you to step through the build, set breakpoints, see what is happening, how variables are changing etc. The value of this shouldn't be underestimated; developing a FinalBuilder script is fast, easy and provides immediate feedback. No Web based CI Server (is there any other kind?) can give you this level of immediate feedback. 

This also has the added benefit in that the FinalBuilder project will be runnable on other developers machines (assuming they have the required tools installed)

All of your build script is versioned with your source code.

If all of your build script functionality is in a FinalBuilder script, and that script is checked into version control (alongside your source code), then if the structure of your source code changes, so can your FinalBuilder script. The CI server will checkout the correct version of the build script for the version of source code it's checking out. 

Better Integration

We're currently working on better integration between Continua CI and FinalBuilder. Some of our FinalBuilder Server customers have complained that they lose functionality when moving to Continua CI. We understand that, FinalBuilder Server and FinalBuilder are tightly coupled. When we started working on Continua CI, we made a conscious decision to not do that. That means Continua CI doesn't know about the internals of a FinalBuilder project, doesn't know what variables are declared. I still stand by that decision; it made Continua CI a better product. That said, there is more we can do to improve how the two products work together. This work will show up in an update over the coming weeks (when it's ready!).

DUnitX has a Wizard!

Thanks to a contribution from Robert Love, DUnitX now sports a shiny new IDE Wizard for creating Test projects and Test Units. 

Before you install and use the wizard, there is one thing I recommend you do. In your Delphi IDE, add and Environment variable DUNITX and point it at your copy of the DUnitX source. The reason for doing this, is that when the wizard creates a project, it adds $(DUNITX) to the project search path. This avoids hard coding the DUnitX folder in yhe project search path, and also avoids installing it in your global library path (I have nothing other than the defaults installed there, I always use the project search path, makes it easier to share projects with other devs). 

Once you have that done (I'm assuming you have pulled down the latest source from GitHub), open the project group (.grouproj) for your IDE version and build the project group. Then right click on the wizard project and click on install :

If the package installs successfully then we are ready to use the wizard. Close the project group, and invoke the File\New\Other dialog, you will see the DUnitX Project listed 

You might like to Customize your File\New menu, I made DUnitX prominent on mine (in part to remind myself to create unit tests first!) :

Invoking the wizard will show a simple dialog :

The options are pretty self explainatory, so I won't go into them here. The wizard generates a console application, once we have a gui runner (being worked on) we'll update the wizard to add options for that.

DUnitX is open source, get it from GitHub - contributions are welcome. We also have a Google Plus Community for DUnitX.

It's not uncommon for tools run during a build process to create log files, xml or html files etc that you might want to keep, in other words Artifacts. Continua CI already has a mechanism for registering Artifacts, which enables them to be viewed/downloaded from the Build Artifacts page. Continua CI also has another way of viewing those files, Reports. Reports are viewed in an iframe, which allows you to stay within the Continua CI UI, but still naviate within the report files. A typical use of the Report feature is showing exported FinalBuilder html logs, or Code Coverate html reports (for example those produced by OpenCover). 

Defining a Report

Defining a report is relatively simple. Just point it at a file you expect to appear in the Builds Workspace on the Server.

Define Report

In this case we're expecting our build process to place a file named FinalBuilderReport.html in the $Workspace$\Reports folder. $Workspace$ will be replaced at run time with the builds workspace path on the server. 

The next step is to make sure that the file actually gets copied to where we said it would be. We define a Workspace Rule to copy the file back to the build workspace on the server when the Stage completes. If your tool generates .css and image files then don't forget to add rules to copy those files into place too. 

Workspace Rules

The final step is to make sure that the report file is actually produced. In this example, we are using an exported  FinalBuilder Log file, which is created in $Workspace$\Output\FB7 - we tell FinalBuilder where the workspace is by setting a FinalBuilder variable (along with a buch of other stuff like version numbering etc) in the FinalBuilder Action

Passing the Workspace folder to FinalBuilder

Viewing the Report

All thats left to do now is run the build, and view the report, If everything went to plan, then when you click on the builds Report Tab, you should see something like this :

Viewing the Report

Notice the Home/Back/Forward Buttons. If your report comprises of multiple pages, and all the links in the html files are relative, then you get full history support in the iframe. FWIW, Open Cover with ReportGenerator does just that. We'll take a look at using Open Cover with Continua CI in a future post. 

GitHub makes it relatively simple to contribute to open source projects, just fork the repository, make your changes, submit a pull request. Couldn't be simpler. 

Accepting those Pull requests, is dead simple too, most of the time. But what if you want to build and test the pull request first, before accepting the request. Fortunately the nature of GitHub Pull requests (or more to the point, Git itself) makes this possible. 

Git References

Git References are a complex topic all on it's own, but lets take a quick look at a typical cloned repository. In the .git folder, open config file in notepad and take a look at the [remote "origin"] section, here's what mine looks like :

[remote "origin"]
url = https://github.com/VSoftTechnologies/playground.git
fetch = +refs/heads/*:refs/remotes/origin/*

The key entry here is the fetch. Quoting from the git documentation :

"The format of the refspec is an optional +, followed by <src>:<dst>, where <src> is the pattern for references on the remote side and <dst> is where those references will be written locally. The + tells Git to update the reference even if it isn’t a fast-forward."

The default fetch refspec will pull any branches from the original repository to our clone. But where are our pull requests?

Anatomy of a pull request

When a pull request is submitted, GitHub  make use of Git References to essentially "attach" your pull request to the original repository. But in my local clone, I won't see them because the default fetch refspec doesn't include them. You can see the pull requests by using the git ls-remote command on the origin :

$ git ls-remote origin
$ git ls-remote origin
27dfaaf83f60ac26a6fe465042f2ddb515667ff1        HEAD
654b98d6eb862e247e5c043460e9f9a64b2f0972        refs/heads/Test
27dfaaf83f60ac26a6fe465042f2ddb515667ff1        refs/heads/master
b333438310a56823f1938071af8c697b202bf855        refs/pull/1/head
95cb80af1330e73188ea32659d7744dcfe37ab43        refs/pull/2/head
90ba13b8edaab04505396dbcb1853f6f9bdaed64        refs/pull/2/merge

Notice something odd there. There are two pull requests, but pull request 2 has two entries in the list, whilst pull request 1 has only 1 entry.  refs/pull/2/head is a reference to the head commit of your pull request, whilst refs/pull/2/merge is a reference to the result of the automatic merge that GitHub does. On pull request 1, there was a merge conflict, so the the /merge reference was not created, on pull request 2, the merge succeeded. On the pull request page, you would typically see something like this if the merge succeeded : 

Getting Continua CI to see the Pull Requests

The main reason for building pull requests on your CI server is to see if they build, and to run your unit tests against that build. You can chose to build the original pull request, or the result of the automatic merge, or both. In reality, if the automatic merge failed, then the person who submitted the pull request has some more work to do, so there's really no point building/testing the original pull request. What you really want to know, is "if I accept this request, will it build and the tests pass", so it's generally best to only build the automatic merge version of the pull request. Continua CI makes this quite simple. On the Git Repository settings, check the "Fetch other Remote Refs" option. This will show the Other Refs text area, which already has a default RefSpec that will fetch the pull requests (the merged versions), and create local (to Continua CI) branches with the name pr/#number - so pull request 1 becomes branch pr/1. 

You can modify this to taste, for example if you are fetching both the merge and the head versions of the  pull requests, you might use a refespec like this :


Building the pull Requests

Now we have gotten this far (which is to say, you enabled one option and clicked on save!) we can build the pull requests (it may take a few minutes to fetch the pull requests). If you manually start a build, you can select the pull request from the branch field for the github repository using the intellsense, just start typing pr/ and you will see a list :


Now we can add a trigger to build pull requests (we are talking continuous integration after all). Using the Pattern Matched Branch feature on Continua CI Triggers you can make your trigger start builds when a pull request changeset is fetched from Github. The pattern is a regular expression, so ^pr/.* would match our pull request branches (assuming you we use the default refspec)

Adding a trigger specific to the pull requests allows you to set variables differently from other branches, and you will then be able to tailor your stages according to whether you are building a pull request or not. For example, you probably don't want to run your deploy stage when building a pull request).

Updating GitHup Pull Request Status

One last thing you might like to add, is to update the Pull Request Status. This can be done using the Update GitHub Status Action in Continua CI (In a future update this will done via build event handlers, a new feature currently in development). This is what the pull request might look like after the status is updated by Continua CI :