Introducing GitFlow for Visual Studio

Update: The exension is now also available for Visual Studio 2015 Preview: https://visualstudiogallery.msdn.microsoft.com/f5ae0a1d-005f-4a09-a19c-3f46ff30400a

 

GitFlow is a popular workflow that provides a consistent naming convention to your branches as well as clear guidance on how your code should flow through these branches.
GitFlow was introduced by Vincent Driessen in this post back in 2010, and quickly caught a lot of attention in the community. Since GitFlow by nature is very prescriptive it made a lot of
sense to implement tooling support for the workflow, which Vincent added shortly after. His repo is available at https://github.com/nvie/gitflow, although it hasn’t been updated since 2012.
However, several forks has been made, one of the most active is being developed by Peter van der Does at https://github.com/petervanderdoes/gitflow

To make GitFlow more approachable I decided to integrate the GitFlow toolset into Visual Studio, by extending Team Explorer. This makes it very easy to access the commands and lowers the learning
curve a bit by making it available as a UI. Note that the extension includes the GitFlow scripts from Peter van der Does fork of GitFlow and uses them for every command, so it provides the exact same
functionality as the GitFlow scripts does.

 

Installation

Note: The extension requires Visual Studio 2013 Update 3 or higher

You’ll find the extension over at the Visual Studio Gallery, just search for GitFlow in the Extension and Updates Window.
Or, download it from https://visualstudiogallery.msdn.microsoft.com/27f6d087-9b6f-46b0-b236-d72907b54683:

image

Install it and restart Visual Studio, as usual.

 

Using the extension

When you connect to a Git repo in Visual Studio (either local or remote), you will see a new icon show up on the home page in Team Explorer:

image

 
Now, if GitFlow is not installed on your machine you will be presented with the following message:

image

By clicking Install, the extension will copy the necessary files into the Git for Windows directory, and run the install script for GitFlow.
You can check the installation details for GitFlow here https://github.com/nvie/gitflow/wiki/Windows

(Note: Since copying files into the %ProgramFiles(x86)%Gitbin directory requires elevated priveledges, this is done by running this as a elevated Powershell script.
You will see this flash by during the installation
)

 

Initialize

Now, you are ready to start use the extension! The first thing you will have to do is to initialize the repo for GitFlow. What this means is that you
should create your permanent development and master branches, and set the naming conventions for future feature, release and hotfix branches:

 

image

You can also set the Tag prefix, which will be used when you tag a release or hotfix branch as part of finishing up those branches.

Note that all output from all GitFlow operations are sent to a separate output window pane in Visual Studio, which is activated when the command start.
Here you can which gitflow command that were used and the output from it:

 

image

 

Working with features

From now on, the extension will show the recommended actions based on which branch you are currently in. After initializing the repo, you will be in the develop
branch, so from here you would typically either start a new feature, release or hotfix branch.

 

image

Clicking Start Feature will let you define a name for the branch. GitFlow will add the feature branch prefix for you so don’t include that.

Here I have created a feature branch called SingleSignOn:

image

 

As you can see, the extension will now suggest Finish Feature as the recommended action:

image

Note that all other actions are still available from the Other menu.

 

In the GitFlow world, you are allowed to have multiple feature branches but only one release and hotfix branch at any single time.
In fact, if you try to create multiple release branches, you will get an error.

Keeping track of multiple feature branches can be cumbersome, so the extension lists all active feature branches is a separate section:

image       image

As you can see, if you hover over a feature will get some more details on it, and if you right-click on it you can (depending on the state), checkout, track or publish the feature branch.
I will be looking at adding more functionality here in the future to make is even easier to use this workflow.

 

I hope you will find this extension useful. Please report any bugs or feedback over at the GitHub site for this extenstion, over at  https://github.com/jakobehn/GitFlow.VS

Trigger Releases in Visual Studio Release Management

In my previous post, I showed how you can trigger a release in Visual Studio Release Management from a TeamCity build step.

When Visual Studio Release Management 2013 RTM’ed, it came with customized TFS build templates that made it easy to trigger a release from a TFVC or Git build in TFS. These build templates relied on the ReleaseManagementBuild command line client, so it required the VSRM client being installed on the build server.

Then, with the update train of Visual Studio 2013, new functionality such as vNext deployments, support for Powershell DSC etc was added. Together with this a new REST API was introduced that removes the need for a command line application to trigger a release. However, this REST API _only_ works for vNext deployments, and it will most likely never be implemented for agent based deployments. Basically all new functionality in the release management area only works for vNext deployements, so you should be looking to move in that direction.

Also, in VS 2013 Update 4 support was added for connecting to the Release Management service running in Visual Studio Online. With this option, another way of triggering release was added, in which the Release Management service listens for build completion events in TFS which will kick off a release. It is still possible to use the API however, in cases where you don’t run TFS Build.

 

So, since this is rather confusing at the moment and causes a lot of questions, I decided to summarize the currently available combinations and the options that you have when it comes to triggering a release in VSRM:

 

Source

Release Management

Deployment Type

Options

VSO Build

VSO

vNext

Automatically (through build completed event)

VSO Build

VSO

Agent-Based

N/A

TFS Build

On-Premise (Update 3)

vNext

REST API

TFS Build

On-Premise (Update 3)

Agent-Based

ReleaseBuildTemplate

3rd party/share

VSO

vNext

REST API

3rd party/share

VSO

Agent-Based

N/A

3rd party/share

On-Premise (Update 3)

vNext

REST API

3rd party/share

On-Premise (Update 3)

Agent-Based

ReleaseManagementBuild.exe

Note that some of these combinations are not supported at the moment, those are marked with N/A.

Hope that helps

Copy TFS Build Definitions between Projects and Collections

The last couple of years it has become apparent that using multiple team projects in TFS is generally a bad idea. There are of course exceptions to this, but there are a lot ot things that becomes much easier to do when you put all of your projects and team in the same team project.

Fellow ALM MVP Martin Hinshelwood has blogged about this several times, as well as other people in the community. In particular, using the backlog and portfolio management tools makes much more sense when everything is located in the same team project.

Consolidating multiple team projects into one is not that easy unfortunately, it involves migrating source code, work items, reports etc.  Another thing that also need to be migrated is build definitions. It is possible to clone build definitions within the same team project using the TFS power tools.

The Community TFS Build Manager also lets you clone build definitions to other team projects. But there is no tool that allows you to clone/copy a build definition to another collection. So, I whipped up a simple console application that let you do this.

The tool can be downloaded from

https://onedrive.live.com/redir?resid=EE034C9F620CD58D!8162&authkey=!ACTr56v1QVowzuE&ithint=file%2c.zip

 

Using CopyTFSBuildDefinitions

You use the tool like this:

CopyTFSBuildDefinitions  SourceCollectionUrl  SourceTeamProject  BuildDefinitionName  DestinationCollectionUrl  DestinationTeamProject [NewDefinitionName]


Arguments

  • SourceCollectionUrl
    The URL to the TFS collection that contains the team project with the build definition that you want to copy
  • SourceTeamProject
    The name of the team project that contains the build definition
  • BuildDefinitionName
    Name of the build definition
  • DestinationCollectionUrl
    The URL to the TFS collection that contains the team project that you want to copy your build definition to
  • DestinationTeamProject
    The name of the team project in the destination collection
  • NewDefinitionName (Optional)
    Use this to override the name of the new build definition. If you don’t specify this, the name will the same as the original one
  • Example:

    CopyTFSBuildDefinitions  https://jakob.visualstudio.com DemoProject  WebApplication.CI https://anotheraccount.visualstudio.com
     
     

    Notes

    • Since we are (potentially) create a build definition in a new collection, there is no guarantee that the various paths that are defined in the build definition exist in the new collection. For example, a build definition refers to server paths in TFVC or repos + branches in TFGit. It also refers to build controllers that definitely don’t exist in the new collection. So there will be some cleanup to do after you copy your build definitions. You can fix some of these using the Community TFS Build Manager, for example it is very easy to apply the correct build controller to a set of build definitions

    • The problem stated above also applies to build process templates. However, the tool tries to find a build process template in the new team project with the same file name as the one that existed in the old team project. If it finds one, it will be used for the new build definition. Otherwise is will use the default build template

    • If you want to run the tool for many build definitions, you can use this SQL scripts, compliments of Mr. Scrum/ALM MVP Richard Hundhausen to generate the necessary commands:

      USE Tfs_Collection

      GO

      SELECT ‘CopyTFSBuildDefinitions.exe http://SERVER:8080/tfs/collection “‘ + P.ProjectName + ‘” “‘ + REPLACE(BD.DefinitionName,”,”) + ‘” http://NEWSERVER:8080/tfs/COLLECTION TEAMPROJECT’

        FROM tbl_Project P

             INNER JOIN tbl_BuildGroup BG on BG.TeamProject = P.ProjectUri

             INNER JOIN tbl_BuildDefinition BD on BD.GroupId = BG.GroupId

        ORDER BY P.ProjectName, BD.DefinitionName

     

    Hope that helps, let me know if you have any problems with the tool or if you find it useful

TFS Build: NuGet.exe was not found in the expected location

Problem

One of our customers recently had a problem with NuGet restore when they created a new build template, based on the standard TfvcTemplate.12.xaml template. In TFS 2013, package restore is done automatically by the default build templates.

It is configured as part of the RunMSBuild activity, where you can enable and disable this by setting the EnableNuGetPackageRestore property:

image

 

However, when we were executing the builds we got the following warning in the build log:

Unable to restore NuGet packages. Details: NuGet.exe was not found in the expected location: C:UsersBuildAppDataLocalTempBuildAgent18Assembliesnuget.exe

This error puzzled us quite a bit. NuGet.exe is installed as part of TFS Build and is located in the %ProgramFiles%/Microsoft Team Foundation Server 12.0/Tools folder. Why was Team Build looking in the build agent custom assembly folder?

It turns out that the reason for this was that the customer had not only checked in the custom activity assemblies in TFVC, they had also checked in all the references TFS assemblies (such as Microsoft.TeamFoundation.Build.Workflow.dll for example). This is not necessary, but had until now never caused any problems. But now, since this assembly was used during the build, it looked in the current path of the assembly for NuGet.exe which resolved to the path from the error message above.

Solution

After removing all the TFS assemblies from version control NuGet package restore started working again.

Creating a Build Definition using the TFS 2013 API

Almost four years ago I wrote a post on how to create a build definition programmatically using the TFS 2010 API. The code is partyl still valid, but since a lot of the information in a build definition is dependent on the build process template, the code in the blog
does not work properly for the TFS 2013 default build templates. In addition, since the introduction of Git in TFS 2013, there are some other differences in how you create a build definition for a Git team project compared to a TFVC team project.

So, in this post I will show an updated version of the code for creating a build defintion. I will actually show two samples, one for the GitTemplate.12.xaml and one for the TfvcTemplate.xaml which are the default template used in TFS 2013.

 

Creating a Git Build definition (GitTemplate.12.xaml)

Here is the code for creating a build definition using the GitTemplate.12.xaml build process template
//Create build definition and give it a name and desription
IBuildDefinition buildDef = buildServer.CreateBuildDefinition(tp);
buildDef.Name = "ATestBuild";
buildDef.Description = "A description for this build defintion";
buildDef.ContinuousIntegrationType = ContinuousIntegrationType.Individual; //CI

//Controller and default build process template
buildDef.BuildController = buildServer.GetBuildController("Hosted Build Controller");
var defaultTemplate = buildServer.QueryProcessTemplates(tp).First(p => p.TemplateType == ProcessTemplateType.Default);
buildDef.Process = defaultTemplate;

//Drop location
buildDef.DefaultDropLocation = "#/";    //set to server drop

//Source Settings
var provider = buildDef.CreateInitialSourceProvider("TFGIT");
provider.Fields["RepositoryName"] = "Git";
provider.Fields["DefaultBranch"] = "refs/heads/master";
provider.Fields["CIBranches"] = "refs/heads/master";
provider.Fields["RepositoryUrl"] = url + "/_git/Git";
buildDef.SetSourceProvider(provider);

//Process params
var process = WorkflowHelpers.DeserializeProcessParameters(buildDef.ProcessParameters);

//What to build
process.Add("ProjectsToBuild", new[]{"Test.sln"});
process.Add("ConfigurationsToBuild", new[]{"Mixed Platforms|Debug"});

//Advanced build settings
var buildParams = new Dictionary<string, string>();
buildParams.Add("PreActionScriptPath", "/prebuild.ps1");
buildParams.Add("PostActionScriptPath", "/postbuild.ps1");
var param = new BuildParameter(buildParams);
process.Add("AdvancedBuildSettings", param);

//test settings
var testParams = new Dictionary<string, object>
                                 {
                                     { "AssemblyFileSpec", "*.exe" },
                                     { "HasRunSettingsFile", true },
                                     { "ExecutionPlatform", "X86" },
                                     { "FailBuildOnFailure", true },
                                     { "RunName", "MyTestRunName" },
                                     { "HasTestCaseFilter", false },
                                     { "TestCaseFilter", null }
                                 };

var runSettingsForTestRun = new Dictionary<string, object>
                                            {
                                                { "HasRunSettingsFile", true },
                                                { "ServerRunSettingsFile", "" },
                                                { "TypeRunSettings", "CodeCoverageEnabled" }
                                            };
testParams.Add("RunSettingsForTestRun", runSettingsForTestRun);

process.Add("AutomatedTests", new[]{ new BuildParameter(testParams)});
            
//Symbol settings
process.Add("SymbolStorePath", @"\serversymbolssomepath");

buildDef.ProcessParameters = WorkflowHelpers.SerializeProcessParameters(process);

//Retention policy
buildDef.RetentionPolicyList.Clear();
buildDef.AddRetentionPolicy(BuildReason.Triggered, BuildStatus.Succeeded, 10, DeleteOptions.All);
buildDef.AddRetentionPolicy(BuildReason.Triggered, BuildStatus.Failed, 10, DeleteOptions.All);
buildDef.AddRetentionPolicy(BuildReason.Triggered, BuildStatus.Stopped, 1, DeleteOptions.All);
buildDef.AddRetentionPolicy(BuildReason.Triggered, BuildStatus.PartiallySucceeded, 10, DeleteOptions.All);

//Lets save it
buildDef.Save();

 

Some things to note here:

  • The IBuildDefinitionSourceProvider interface is new in TFS 2013, and the reason for it is of course to abstract the differences between TFVC and Git source control. As you can see, we use the “TFGIT”

    to select the correct provider, and then we use the Fields property to populate it with information

  • The process parameters are created by using dictionaires, with the corresponding key and values. If you are familiar with the GitTemplate.12.xaml, you will recognize the name of these parameters.
  • As for drop locations, in TFS 2013 you can select between no drop location, a drop folder (share) or a server drop, which means the output is stored inside TFS and accessible from the web access.

    In the sample above, we specify #/ which (not that obvious) means a server drop. If you want to use a share drop location, just specify the server path for the DefaultDropLocation

 

Creating a TFVC Build definition (TfvcTemplate.12.xaml)

AS it turns out, creating a TFVC build definition using the TfvcTemplate.12.xaml is almost identical, since the build team went to great effort and abstracted away most differences. The only difference in fact, at least when it comes to the most common settings is how you define the workspace mappings. And this code is the same as it was in TFS 2010/2012. In addition, you don’t need to create a source provider, because there is nothing that needs to be configured other than the workspace.

 

Here is the full sample for TFVC:

//Create build definition and give it a name and desription
IBuildDefinition buildDef = buildServer.CreateBuildDefinition(tp);
buildDef.Name = "ATestBuild";
buildDef.Description = "A description for this build defintion";
buildDef.ContinuousIntegrationType = ContinuousIntegrationType.Individual; //CI

//Controller and default build process template
buildDef.BuildController = buildServer.GetBuildController("Hosted Build Controller");
var defaultTemplate = buildServer.QueryProcessTemplates(tp).First(p => p.TemplateType == ProcessTemplateType.Default);
buildDef.Process = defaultTemplate;

//Drop location
buildDef.DefaultDropLocation = "#/";    //set to server drop

//Source Settings
buildDef.Workspace.AddMapping("$/Path/project.sln", "$(SourceDir)", WorkspaceMappingType.Map);
buildDef.Workspace.AddMapping("$/OtherPath/", "", WorkspaceMappingType.Cloak); 

//Process params
var process = WorkflowHelpers.DeserializeProcessParameters(buildDef.ProcessParameters);

//What to build
process.Add("ProjectsToBuild", new[]{"Test.sln"});
process.Add("ConfigurationsToBuild", new[]{"Mixed Platforms|Debug"});

//Advanced build settings
var buildParams = new Dictionary<string, string>();
buildParams.Add("PreActionScriptPath", "/prebuild.ps1");
buildParams.Add("PostActionScriptPath", "/postbuild.ps1");
var param = new BuildParameter(buildParams);
process.Add("AdvancedBuildSettings", param);

//test settings
var testParams = new Dictionary<string, object>
                                 {
                                     { "AssemblyFileSpec", "*.exe" },
                                     { "HasRunSettingsFile", true },
                                     { "ExecutionPlatform", "X86" },
                                     { "FailBuildOnFailure", true },
                                     { "RunName", "MyTestRunName" },
                                     { "HasTestCaseFilter", false },
                                     { "TestCaseFilter", null }
                                 };

var runSettingsForTestRun = new Dictionary<string, object>
                                            {
                                                { "HasRunSettingsFile", true },
                                                { "ServerRunSettingsFile", "" },
                                                { "TypeRunSettings", "CodeCoverageEnabled" }
                                            };
testParams.Add("RunSettingsForTestRun", runSettingsForTestRun);

process.Add("AutomatedTests", new[]{ new BuildParameter(testParams)});
            
//Symbol settings
process.Add("SymbolStorePath", @"\serversymbolssomepath");

buildDef.ProcessParameters = WorkflowHelpers.SerializeProcessParameters(process);

//Retention policy
buildDef.RetentionPolicyList.Clear();
buildDef.AddRetentionPolicy(BuildReason.Triggered, BuildStatus.Succeeded, 10, DeleteOptions.All);
buildDef.AddRetentionPolicy(BuildReason.Triggered, BuildStatus.Failed, 10, DeleteOptions.All);
buildDef.AddRetentionPolicy(BuildReason.Triggered, BuildStatus.Stopped, 1, DeleteOptions.All);
buildDef.AddRetentionPolicy(BuildReason.Triggered, BuildStatus.PartiallySucceeded, 10, DeleteOptions.All);

//Lets save it
buildDef.Save();

 

Hope you find this useful!

Inmeta Visual Studio Extension Gallery – version 2.0

This year at the second MVP summit I presented a new solution for hosting a private extension gallery. Since then I have finished up the code and put it up on the CodePlex site so you can use it as you want to.
In this blog post I will walk through the background and how you deploy and use the solution.

Note: The sourcecode is available at http://inmetavsgallery.codeplex.com/ as a new 2.0 release. I have branched the original source code so that it is still available.

Background

Little more than a year ago, I blogged about how to host your own private gallery for hosting Visual Studio extensions. The solution that I put up on CodePlex (http://inmetavsgallery.codeplex.com/) was a ASP.NET web service that scans a folder or share and generates the corresponding Atom Feed XML that Visual Studio expects when browsing extensions, using the Extension Manager. See the blog post for details on how this works.

Although this solution works fine (we are using it internally at Inmeta) there are some things that have been nagging me:

  • There is no easy way to upload or update extensions.
  • Since the file system is the data storage, the service rescanned the whole structure on every request, which could become a bottleneck when the number of clients and/or extensions increase
  • I miss some of the features that are available in the “real” Visual Studio Gallery, such as showing the number of downloads and the average rating of each extension

The last bullet is what made start looking at how this works in Visual Studio. As you know Visual Studio comes with two extension galleries by default, the Visual Studio Gallery and the Samples Gallery:

image
The standard Visual Studio Gallery

When selecting an extension here, Visual Studio shows among other things how many downloads this extension has, and the average rating together with the number of votes. Also it shows icons for the extension and a small preview image when selected.
It is also possible to search on different metadata, such as popularity, number of downloads or most recent for example. All in all, this is a much nicer experience than what the was possible using the official private extension gallery mechanism.

When I dug into the details of how this works, it turns out that Visual Studio internally uses a completely different protocol for communicating with these two galleries. It uses a standard (but completely undocumented) WCF SOAP service with the following interface:

 

image 
The WCF SOAP interface that Visual Studio communicates with

 

So basically, there are methods available for displaying the category tree (GetRootCategories(2) and GetCategoryTree(2)), checking for updates (GetCurrentVersionsForVsixList) and for searching available extensions (SearchReleases(2)).
You can see how these methods matches to how the Visual Studio Extension Manager works when you browse, search and update your extensions.

So, with a (lot of) help from Fiddler I decrypted the protocol that was used and managed to implement a service that works in the same way that the Visual Studio Gallery does.

 

Solution
The new version of the Inmeta Gallery is a ASP.NET web application that consists of three parts:

  • A WCF service implementing the IVsIdeService interface
  • An ASP.NET web application where you can upload and rate visual studio extensions
  • A SQL database for storing the extensions.

image
Inmeta Visual Studio Gallery overview

 

This makes it easy to deploy, it is just one web application that contains both the service that VS communicates with and the web application where you can browse and upload the extensions.

The web application is simple, it shows the 10 most downloaded extensions together with the same information that you see in Visual Studio, and you can search extension by name or description. 

Here is a screenshot:

image
Screenshot of the Inmeta Visual Studio Extension Gallery

When select an extension you will see the full details of the extension, as shown below. Here you can download the extension, give it a rating and if desired delete it completely.

 

image
Extension details page

Note that if you rate it you need to press Update to store the new value.

 

Deployment

  • Server
    The CodePlex release for this solution is a simple web deploy package, that you can deploy to a local or remote IIS web server. I’ve attached the standard files from the Visual Studio publising wizard, so you’ll get the command files that simplifies the deployment, See http://msdn.microsoft.com/en-us/library/dd465323(v=vs.110).aspx for information on creating and deploying a Web Deploy Package using Visual Studio.

    Note that the web application is using Entitiy Framework Code First which means that it will try to create the database the first time the code is executed. In order to do so, it must have proper permission on the target SQL server of course. If you need to deploy the database in any other manner, just download the source code take it from there.

  • Client
    It is not possible to add a private extension gallery of this type using Visual Studio, it will always create a Atom Feed gallery extension point. Since these settings are stored in the registry, it is easy to do this using a .reg file.
    The registry settings for a Visual Studio Gallery looks like this:

    image

    Note the VSGallery string that is highlighted in te image above. This is the “secret” setting that causes Visual Studio to use the WCF protocol instead of the simple Atom Feed protocol
    There is a .reg file available on the CodePlex site that you can use for registering the gallery for every client.

 

Hopefully you wil find this new version of the Inmeta Visual Studio Gallery service usable, please post any issues and/or suggestions to the CodePlex site!

Inmeta Visual Studio 2013 Community Day

Yesterday, on September 12th, we arranged a Visual Studio Community Day 2013 at Mesh in central Oslo. The agenda was in two parts, first we talked about how you can improve your delivery cadence by using Visual Studio ALM.
We went through all stages including planning, developing, testing and deployment. In the second part, we showed some of the new goodies in Visual Studio 2013, where we focused mostly on Git and InRelease which are the two major additions in Visual Studio 2013 ALM. Unfortunately we didn’t have the time to go through everything that we wanted, but we have put up links and some more information on our public  GitHub site, at https://github.com/Inmeta/public/wiki/VS2013-Community-Day

We had a lot of fun presenting and we got some great feedback during and after the event.

Here is a picture showing me, Terje Sandstrom and (in the foreground) Lars Nilsson who hosted the event.

VSCommunityDay2013

Thanks to Microsoft Norway for arranging this event!

Getting started with InRelease and TFS 2013 Preview

As you probably already know, Microsoft recently acquired InRelease, a release management product build by InCycle software that integrates tightly with Team Foundation Server. This acquisition fills a huge gap in the Visual Studio ALM suite, letting customers handle the release management and automatic deployment of their solution. This is a crucial feature for enabling Continuous Deployment.

In this post I will show you how to get started with using InRelease, by installing it and setting up your first release including automatic deployment to a staging server. I expect to blog some more about InRelease in the near future, looking at the nitty gritty details of release automation and deployment using InRelease.

Note: Both TFS 2013 and this edition of InRelease are still in preview and details can change in time for the RTM version.

InRelease Overview

A deployment of InRelease typically looks like this:

image

 

So we have three main components here:

  • InRelease Server
    The server consists of both a windows and a web service that the deployers and clients communicates with (using HTTP/HTTPS).
  • InRelease Deployer
    The Deployer is a windows service that is installed on each target server where you want to deploy your applications. Like Visual Studio Lab Management, you can define environments that consist of several servers (physical or virtual). But each servers needs to have a deployer agent installed to be able to carry out the actual deployment.
  • InRelease Client
    There are in fact two clients. There is a WPF application that is the main interface for managing all release information. In addition there is a web application where users can act on approval requests, that is sent out using email.

InRelease Concepts

There are several concepts in InRelease that you need to understand in order to fully utilize it. These concepts are related to each other as well, and it can be a bit tricky in the beginning to understand how they relate to each other.

  • Stage Type
    This corresponds to a set of logical steps that are required to move your application build from development all the way to production. Typically you will have stages for Development, QA, User Acceptance Test, Production etc.
  • Technology Type
    These are basically tags that allow you to specify what kind of technologies that are used on your target servers and environments. These tags are used by InRelease for anything, they are merely informational values.
  • Environment
    As mentioned above, an environment consist of one or more servers. 
  • Server
    In order to deploy your application, you need to register your target servers in InRelease. Add the servers using the DNS name and InRelease will register the IP address of the server that first time the Deployer agent on that machine communicates with the Server.
  • Release Path
    A Release Path is how you distribute a release in a certain scenario. Even though you will often use the same release path every time for your application, you might for example define one release path for major releases and another release path for minor/hotfix releases, since these might have different pre- or post validation steps.
  • Release Template
    A Release Template is the workflow that is used for releasing an application. Users that are familiar with TFS Build will find themselves at home here, since InRelease also uses Windows Workflow for create the deployment orchestration, by using a sequence predefined Workflow Activities.
  • Release
    Defines a specific release of an application or system. A release is defined by associating it with a Release Template, a Stage Type and a Build. You want to use TFS Build here and associate the Release Template with a corresponding TFS Build, but it is also possible to use a UNC path as the source of deployment items, in case you for example use Team City as your build automation tool.
  • Tool
    Represents an executable piece of code, for example a PowerShell or a batch file, or an executable. The only real important thing here is that it is possible to execute the tool silently from command line. A tool is always used by either an Action or a Component
  • Action
    An object in InRelease that can be used in a deployment sequence. Often this is a tool with the corresponding command and parameters, such as MSI Deployer or Windows Process.
  • Component
    Part of an application that needs to be installed. For example a database, web site or  a windows service. A component has a source, which often is fetched from the TFS Build drop folder

 

Installing InRelease

The installation procedure is pretty straight forward except some minor issues that should be improved by RTM. Martin Hinshelwood has posted some of these issues herehere and here.

The InRelease Server uses SQL Server to store all its information, this can be basically any version, and can be hosted remotely. In addition, the InRelease server has the following prerequirements, so make sure that you install/enabled these features before:

image_thumb[9]

Note that it is possible to run on IIS 6 as well, check the installation manual

After you have installed everything, you first need to add users. Start the InRelease Client and go to Administration –> Users:

SNAGHTML1f1578f9_thumb[1]

Select the windows account by browsing your AD directory. This will automatically fill out the name and email address for you, as long as this information is available in AD.
Also mark if the user is a Release Manager and/or a Service User. Release Managers have access to everything, and Service Users are used for deployer accounts and TFS build service account.
These users won’t show up in any lists where you select users.

SNAGHTML1f1915f3_thumb[1]

 

Next up, you need to register the connection to TFS. Enter the name of your TFS server, and the credentials that should be used for accessing it.

SNAGHTML2013a2ad

Verify that the TFS connection works properly, after this you should be good to go and start creating releases!

 

Creating and deploying a Release

Lest walk through how to get started quickly, by creating a new release and deployment sequence for an application. In this case, I am reusing our existing release build for this application, but will manage and deploy it using InRelease. This build already produces an MSI (using Wix) so we will use an existing InRelease tool called MSI Deployer, that is capable of executing a MSI with custom parameters as part of the deployment.

These are the steps that we will walk through:

  1. Define the Stage Types
  2. Create an Environment for the test server
  3. Register the test server
  4. Create a Release Path for our release
  5. Setup a component that installs our MSI
  6. Create a Release Template that uses the component
  7. Create a Release

Define the Stage Types

We will setup to stage types here, one for Test and one for Production. Go to Administration –> Pick List and select Stage Types. Create two Stage Types, called Test and Production:

SNAGHTML1f7a177b

Define the staging server in InRelease

Now we will register our existing test server used for staging the application. This is the server where we have installed the InRelease Deployer agent, which is used for running the deployment sequence on that machine. Note that a release can of course reference many servers, and each server has its own steps in the deployment sequence.

SNAGHTML1f86c797

Here I have registered the customer test server, running on our lab network. I have assigned myself as the owner of this server, and added a short description. In addition I have used the default option of how the InRelease Deployer should access the build drop location, namely directly through the UNC path. If this is a problem, which it can be due to security restrictions, you can use the other option in which the InRelease Server accesses the drop location and the InRelease Deployer agents gets the files from the IR Server using HTTP(S). This is slower, especially if you have large files.

Note the error that is shown. This means that the InRelease Deployer on the server have not yet communicated with the server. As soon as it does, the error will disappear and the IP Address will be filled out.

Create an Environment for the test servers

We also need to create environments for each stage type. In this case, each environment will only consist of one server, but often you will have several servers, such as web servers, database server, application servers and so on.

SNAGHTML1fe9abd0

Here I have created a Test environment that includes the test server. I will also create a Production environment for the production server(s).

Create a Release Path for our release

Now lets define how the release should flow through the different stages. We will define how each stage should be handled, if the deployment is automatic or not, and if the different steps should be validated and approved by someone.

SNAGHTML1f92e323

 

As you can see I have added both stages here, but the different steps are a bit different for each step. On the test server I want to automate the acceptance and validation step, and I will approve the deployment afterwards myself. In the production environment, the release first have to be accepted (by my colleague Terje in this case Ler ) before the deployment proceeds. Also, Terje will be validating and approving the release in the production environment.

Setup a component that installs our MSI

Before create the release template, we need to create a component that will install our MSI. As mentioned before, components can be reused in multiple release template, by using arguments. So first we give the component a name and then point to where the package that belongs this component can be retrieved:

SNAGHTML1fa8b012

In my case, all the MSI’s from the TFS build is located at the drop folder root. In this case, I must add a ‘’ in the Build Drop Location to have InRelease understand that.

Note the the build definition will be defined in the Release Template. We could also choose to select an independent build, basically any build that has already been executed. We could also point to a UNC share, which would allow us to use InRelease without TFS Build, for example is you use TeamCity.

Next we select the Deployment tab, in which we specify how this component is actually installed. Here we can select from a list of predefined tools, in this case we select the MSI Deployer tool. Each tool has its own set of commands, arguments and parameters. A sample argument will be created when selecting the tool, so all you need to do is to change the parameter values to match your packages.

image

The MSI Deployer tool, like many other InRelease tools, uses Powershell as implementation.
Here I have referenced my installer and added the specific MSI argument that is needed in order to deploy it on the test server, such as web site name, port, app pool and install directory.

 

Create a Release Template that uses the component

Now lets create a Release Template that utilizes this component. Go to Configure Apps –> Release Template and create a new template. Fill out a name and description, and select the Release Path that we just created. Also, we can select which build definition that belongs to this release template. This is where the component will fetch its packages from, and it also allows us to later on automatically trigger a release from a build, as I will show in a later post.

SNAGHTML1fb789be

 

Next up we define the Deployment sequence for each stage of the corresponding Release Path, which in our case is Test and Production. You will that in addition to the existing predefined tools the servers and components that you have defined show up in the toolbox.

SNAGHTML1fbae7f4

Here I have first dragged the server onto the workflow surface, and then added the Customer Web Site MSI installer inside the Server activity. This signals that the component shall be executed on that server. I could very well have multiple servers here, and tools/components are always placed within a server node.

Of course there are a lot more things that you can do here, there are tools for creating and configuring web sites, SQL databases, Windows Services and starting and stopping Azure VMs. In my case, I already had an MSI from before, so all I need to do here is to make sure that it is executed with the correct parameters.

 

Create a Release

Finally, it is time to actually release something Ler 

By selecting the Release Template, we can click on New Release to create a new Release for this release path. Here we select which Target Stage that we should release to, and which build that should be deployed.

SNAGHTML1fc62ca2

 

Here I have clicked on Latest, which automatically finds the latest build for my associated build definition, but it is also possible to select a previous build.

Now I can select Create in Draft which allows me to postpone the release for later, or I can be bold and click in Start immediately.

SNAGHTML1fca5beb

Here we can see that the Release is in progress, and the first three steps are already done. Remember that we set the Accept Deployment step and the Validate Deployment step to automatic for the Test stage. The Deploy step has executed in about 3 seconds, and we can view the log by clicking the button in the Details column.

Finally, the release has stopped in the Approve Release step. This step is manual, and is waiting for me to approve the release. To make this workflow happen, I have received the following email from the InRelease Server:

 

image

 

After I have surface tested the deployment and verified if it meets the quality gates defined for the release or not, I can click the View Request link which will redirect me to the InRelease web application where I can select to Approve or Reject the release.

 

Conclusion

This post has shown how you quickly can get started with InRelease and TFS 2013. As mentioned before, this is still prerelease software, so there are still some know bugs in the software.

Automatically Merging Work Items in TFS 2013

** Source available at http://mergeworkitems.codeplex.com/ **

Half a year ago I wrote about about Merging Work Items with a custom check-in policy. The policy evaluated the pending changes and for all pending merges, it traversed the merge history to find the associated work items and let the user add them to the current changeset.

I promised to post the source to the check-in policy (and I’ve got a lot of requests for it), but I never did. This was primary for two reasons:

  1. The technical solution turned out to be a bit complicated. The problem was/is that it is not possible to modify the list of associated work items in the current pending changes using the API. This was a show stopper and the only way around it was to add another component that was executed on the server after the check-in that did the actual association. The information about the selected work items was temporarily stored in the comments of the changeset. This worked, but complicated the deployment.
  2. The feedback internally at Inmeta was that why should the developer be allowed to select which work items that should be associated? If a work item was associated with a changeset in a Main branch, it should always be associated with the merge changeset when merging to a Release branch. So the association should be done automatically.

For these reasons I changed the implementation and converted the check-in policy to a TFS server side event handler instead (for more info on work with these event handlers, check out my post about them here: Server Side Event Handlers in TFS 2010)

By having the association done server side, the process is very smooth for the developer. When a changeset that contains merges is checked in, the event handler evaluates all merges and associates the work items. If a work item has already been associated by the developer, it is of course not associated again. Since it is implemented with a server side event handler, it runs instantly without the user ever really noticing it.

Let’s look at how this works. Lets say that we have the following branch hierarchy:

image

Now, one of our finest developers have both fixed a bug and added a new user story in the Main branch. That was two changesets, each changeset was associated with a corresponding work item:

imageimage

Now, we want to push these changes to the 2.0 Release branch. So the developer performs a merge from Main to the 2.0 branch.

image

At this point, instead of manually adding the work items, the developer just checks in the changes. After this, lets take a look at the source history

image

Double-clicking on the latest changeset, we can see the following information on the work items tab:

image

The work items associated with the original changesets that was merged to the R2.0 branch, have been associated with the new changeset. Also, double-clicking on one of the work items, we can see that the server event handler has added a link to the changeset for this work item:

image

Note the following:

  • The changeset has been linked in the same way as when you associate a work item manually.
  • The change was done by the developer account (myself in this sample), and not the TFS service account. This is because the event handler uses the new TFS Impersonation API to impersonate the user who committed the check-in.
  • The history comment is a bit different than the usual (“Associated with changeset XXX”), just to highlight the reason for the change.
  • If the changeset would contain both merges and other types of pending changes, the merges would still be traversed, the other changes are just ignored.

 

Deployment
Deploying the server side event handler couldn’t be easier, just drop the Inmeta.TFS.MergeWorkItemsEventHandler.dll assembly into the plugin directory of the TFS AT server. This path is usually %PROGRAMFILES%Microsoft Team Foundation Server 12.0Application TierWeb ServicesbinPlugins. Note: This will cause TFS to recycle to load the new assembly, so in production you might want to schedule this to minimize problems for your users.
See my post more details on this.

image

Implementation
I have uploaded the source code to CodePlex at: http://mergeworkitems.codeplex.com/ so you can check out the details there. One thing that is worth mentioning is that I had to resort to the TFS Client API to access and modify the associated work items. The TFS Server Side object model is not very documented, and according to Grant Holiday (in this post) the server object mode for work item tracking is not very useful. So instead of going down that road, I used the client object model to do the work Not as efficient, but it gets the job done.

Note that the event handler hooks into the Notification decision point, which is executed asynchronously after the check-in has been done, and therefor it doesn’t have a negative impact on the overall check-in process.

Hope that you find the event handler useful, contact me either through this blog or via the CodePlex site if you have any questions and/or feature requests.