Using Web Deploy in Visual Studio Team Services Release Management

This post does not really cover something new, but since I find myself explain this to people now and then, I thought that I’d write a quick post on the subject.

So, we want to create a web deploy package as part of our automated build, and then take this package and deploy it to multiple environments, where each environment can have different configuration settings, using VSTS Release Management. Since we only want to build our package once, we have to apply the environment specific settings at deployment time, which means we will use Web Deploy parameters.

 

Here are the overall steps needed:

  1. – Create a parameters.xml file in your web project
  2. – Create a publish profile for the web deploy package
  3. – Set up a VSTS build creates the web deploy package, and uploads the package to the server
  4. – Create a Release definition in VSTS that consumes the web deploy package
  5. – In each RM environment, replaces the tokens in the SetParameters file

Let’s run through these steps in detail:

Create a parameters.xml file

As you will see later on, a publish profile contains configurable settings for the web site name and any connection strings,that will end up in the *.SetParameters.xml file that is used when at deployment time. But in order for other configuration settings, like appSettings, to end up in this file, you need to define these settings. This is done by creating a file called parameters.xml in the root of your web application.

Tip: A fellow MVP, Richard Fennell,  has created a nifty Visual Studio extension that simplifies the process of creating the parameters.xml file. It will look at your web.config file and the create a parameters.xml file with all the settings that it finds.

image

 

In this case, I have three application settings in the web.config file, so I end up with this parameters.xml file. Note that I have set the defaultvalue attribute for all parameters to __TOKEN__. These are the configuration values that will end up in the MyApp.SetParameters.xml file, together with the web deployment package. We will replaced these values at deployment time, by a task in our release definition.

<parameters> <parameter name="IsDevelopment" description="Description for IsDevelopment" defaultvalue="__ISDEVELOPMENT__" tags=""> <parameterentry kind="XmlFile" scope="\\web.config$" match="/configuration/applicationSettings/MyApp.Properties.Settings/setting[@name='IsDevelopment']/value/text()" /> </parameter> <parameter name="WebApiBaseUrl" description="Description for WebApiBaseUrl" defaultvalue="__WEBAPIBASEURL__" tags=""> <parameterentry kind="XmlFile" scope="\\web.config$" match="/configuration/applicationSettings/MyApp.Properties.Settings/setting[@name='WebApiBaseUrl']/value/text()" /> </parameter> <parameter name="SearchFilterDelta" description="Description for SearchFilterDelta" defaultvalue="__SEARCHFILTERDELTA__" tags=""> <parameterentry kind="XmlFile" scope="\\web.config$" match="/configuration/applicationSettings/MyApp.Properties.Settings/setting[@name='SearchFilterDelta']/value/text()" /> </parameter> </parameters>

Creating a Publish Profile

Now, let’s create a publish profile that define how the web deployment package should be created. Right-click on the web application project and then select Publish. Then select the Custom option:

image

 

Since the publish profile will be used to create a web deployment package, I like to call it CreatePackage (but you are of course free to call it whatever you want)

image

On the Connection tab, select Web Deploy Package as the publish method, then give the generated package a name (including .zip).

As the Web Site name, we enter a tokenized value __WEBSITE__. This token will also end up in the MyApp.SetParameters.xml file.

image

Save the publish profile and commit and push your changes. Now it’s time to create a build definition.

 

Create a Build Definition that generates a web deploy package

I won’t go through all the details of creating a build definition in VSTS, but just focus on the relevant parts for this blog post.

To generate a web deploy package, we need to pass some magic MSBuild parameters as part of the Visual Studio build task. Since we have a publish profile that contains our settings, we need to refer to this file. We also want to specify where the resulting files should be placed.

Enter the following string in the MSBuild Arguments field:

/p:DeployOnBuild=true /p:PublishProfile=CreatePackage /p:PackageLocation=$(build.stagingDirectory)

image

 

DeployOnBuild=true is required to trigger the web deployment publishing process, and the we use the PackageLocation property to specify that the output should be places in the staging directory of the build. This will make it easy to upload the artifacts at the end of the build, like so:

image

 

This will generate an artifact called drop in the build that contains all files needed to deploy this application using MSDeploy:

image

As you can see, we have all the generated web deploy files here. We will use three of them:

MyApp.zip – The web deploy package

MyApp.SetParameters.xml – The parameterization file that contains our tokenized parameters

MyApp.Deploy.cmd – A command file that simplifies running MSDeploy with the correct parameters

 

Creating a Release Definition

Finally, we will create a release definition that deploys this web deploy package to two different environments, let’s call them Test and Prod. In each environment we need to apply the correct configuration values. To do this, we have to replace the token variables in our MyApp.SetParameters.xml file.

There is no out of the box task to do this currently, but there are already several of them in the Visual Studio Marketplace. Here, I will use the Replace Tokens task from Guillaume Rochon, available at https://marketplace.visualstudio.com/items?itemName=qetza.replacetokens. Install it to your Visual Studio Team Services account, and then the task will be available in the build/release task catalog, in the Utility category:

 

image

 

Each environment in the release definition will just contain two tasks, the first one for the token replacement and the other one for deploying the web deploy package. To do this, we just run the MyApp.deploy.cmd file that was generated by the build. Since the parameters have already been set with the correct values, we can just run this without any extra arguments.

image

 

Also, we must specify the values for each variable in the environment. Right click on the environment and the add these variables:

image

 

Tip: Create the Test environment first with all variables and tasks. Once it’s done, use the Clone environment feature to create a Prod environment, and then just replace the configuration values

 

That’s it, now you can run the release and it will deploy your web application with the correct configuration to each environment.

 

image

 

 

 

 

Generate custom build numbers in TFS Build vNext

By now, many of you should have had the chance to at least play with the new build system that was released in TFS 2015 and Visual Studio Online. Here is an introductory post I wrote about it when it entered public preview back in January.

Doing the basic stuff is very easy using the new build system, especially if you compare it with the old one, which is now referred to as XAML builds. Creating and customizing build definitions is just a matter of adding the tasks that you want to use and configure them properly, everything is done using the web interface that is part of the TFS Web Access.

Build Number Format

There are (of course) still some things that are not completely obvious how to do. One of these things is how to generate a custom build number for a build. Every build definition has a build number format field where you can use some macros to dictate what the resulting build number should look like.

image

The build number format can contain a mix of text and macros, in the above example I have used some of the date macros to generate a build number that uses todays date plus an increment at the end.

Generating a custom build number

Sometimes though you will have the requirement to generate a completely custom build number, based on some external criteria that is not available using these macros.

This can be done, but as I mentioned before, it is not obvious! TFS Build contains a set of logging commands that can be used to generate output from a task /typically a script) that is generated in a way so that TFS Build will interpret this as a command and perform the corresponding action. Let’s look at some examples:

##vso[task.logissue type=error;sourcepath=someproject/controller.cs;linenumber=165;columnumber=14;code=150;]some error text here

This logging command can be used to log an error or a warning that will be added to the timeline of the current task. To generate this command, you can for exampleuse the following ‘PowerShell script:

Write-Verbose –Verbose “##vso[task.logissue type=error;sourcepath=someproject/controller.cs;linenumber=165;columnumber=14;code=150;]some error text here”

As you can see, there is a special format that is used for these commands:  ##vso[command parameters]text. This format allows the build agent to pick up this command and process it.

Now, to generate a build number, we can use the task.setvariable command and set the build number, like so:

##vso[task.setvariable variable=build.buildnumber;]1.2.3.4

 

This will change the build number of the current build to 1.2.3.4. Of course, you would typically generate this value from some other source combined with some logic to end up with a unique build number.

image

 

You can find the full list of logging commands at https://github.com/Microsoft/vso-agent-tasks/blob/master/docs/authoring/commands.md

Building GitHub repositories in TFS Build vNext

In the brave new world of Microsoft where a lot of the frameworks and languages that they build now are open sourced over at GitHub, it comes as no surprise that GitHub is nicely integrated into both
Visual Studio and TFS Build vNext. This makes it very easy to setup builds that gets the source code from your GitHub repo but uses TFS Build vNext to build it. It also allows you to setup CI builds, that is 
builds that trigger automatically when someone does a commit in the corresponding Git repo.

 

Let’s see how this work:

  1. First, you’ll need a GitHub repo of course.

    Note: If you haven’t checked out the GitHub for VisualStudio extension yet, try it out. Makes it easy to clone your existing repos as well as creating new
    ones, right inside Visual Studio.

    image      image 
    Clone existing repos                                                                                       Create a new GitHub repo

  2. Here, I create a FabrikamFiberTFS repo on GitHub where I’ll upload the code to
  3. Now, to enable the TFS Build vNext integration, you need to create a Personal Access Token in GitHub. To do this, click the Settings link below your profile image in
    GitHub, and then click on the Personal Access Token link:

    image         image
     

  4. Give the access token a name that you will remember(!), and then give it these permissions:

    image

    NOTE: In order to configure triggering CI builds, you must have admin permissions on the GitHub repo.

  5. Save it, and the copy the access token that is displayed.

    NOTE: Store this token somewhere safely, you will not be able to view it again. You probably want to setup a personal access token that works
    for all your GitHub repos, if so you need to remember this access token.

  6. Now, create a new build definition in your Visual Studio Online/TFS team project. Head over to the Repository tab, and select GitHub as your repository tab:

    image

  7. Paste your token in the Access Token field. This will populate the Repository drop down and let you select amongst your existing GitHub repositories:

    image

    You will also be able to select which branch that should be the default branch.

  8. To enable continuous integration for your build definition, go to the Trigger tab and check the Continuous Integration checkbox. When saved, this build
    definition will now use the repo_hook permission against your GitHub repository to respond to commit events.
  9. Save you build definition, and commit a change to your GitHub repository. A new build should be queued almost immediately.
  10. When the build completes, you will see the associated commit as usual in the build summary. However, this commit link now points to the GitHub commit page instead:

    image

    Clicking the link shows the commit in GitHub:

    image

  11. To round this up, we will add a Build Badge to our Welcome page to get an indication of the current status of the build. Go to the General tab, check
    the Badge enabled checkbox and save the build definition. This will expose a link that shows you the public URL to a dynamically generated icon that
    shows the status of the latest build for this particular build definition:

    image

  12. Go to the home page and then to the Welcome page tab. If you haven’t created a welcome page yet, do so. Then add the following markdown to the page:

    # FabrikamFiberTFS Build Status
    ![](URL_FROM_BUILD_BADGE_LINK)

    In my case, the link looks like this:

    # FabrikamFiberTFS Build Status
    ![](https://jakob.visualstudio.com/DefaultCollection/_apis/public/build/definitions/488c3645-8921-4753-af50-4a9569fc2d27/116/badge)

  13. Save it and you will see a nice little badge showing the status of the latest build:

    image

Deploying an Azure Web Site using TFS Build vNext

TFS 2015 is around the corner, and with it comes a whole new build system. All the biggest pain points from the existing build system (now called “XAML builds”) are gone and instead we get a light weight build system with a web UI that makes it very easy to customize our build processes and that doesn’t perform a lot of magic such as redirecting your build output for example.

In this post, I will show you just how easy it is to setup a build that builds a standard ASP.NET web application, generates a web deploy package as part of the build and then pick up this package and deploys it to a Azure web site.
As part of this, you will also see how smooth the integration with Azure is when it comes to connecting your subscription.

 
Sample Application

For this blog post I will use the common FabrikamFiber sample application, the full source for this is available at https://fabrikam.codeplex.com/

I have created a new team project called FabrikamFiber on my local TFS 2015 instance, and pushed the source to the default Git repo in this team project:

image

So, let’s see how we can build, test and deploy this application to Azure.

Register your Azure subscription in TFS

First of all, you need to add your Azure Subscription to TFS. You only need to this once of course (or at least one per subscription in case you have several).

This is done on the collection level, by using the Services tab:

image

Click the Add new Azure Subscription link on the top left. Now you need to enter the Subscription Id and the subscription certificate (you can use credential as well, but using the certificate option is more secure). 
To get this information, follow these steps:

  • Open a Windows PowerShell windows in administrative mode
  • Type  Get-AzurePublishSettingsFile
  • This will open a web browser and automatically download your subscription file
  • Open the subscription file (named <SubscriptionName>-<Date>-credentials.publishsettings
  • In this file, locate the Subscription Id and the ManagementCertificate fields

Now, copy these values into the Add Azure Subscription dialog:

image

Press OK. After it is saved, you should see your subscription to the left and some general information:

image

That’s it, now we can crate a build definition for our application.

 

Create a Build Definition

Go to the team project where the source is located and click on the Build Preview tab. Click on the + button to create a new vNext definition:
Now you can select a definition template for your build definition. Go to the Deployment tab and select the Azure Website template:

 

image

 

This will create a build definition with three steps, one for build the solution, one for running all the tests and one for deploying a web site to Azure.
Note: For this post, I disabled the test step since not all tests pass in the default FabrikamFiber solution.

 

image

 

If you take a look at the Visual Studio Build step, you can see the arguments that are passed to MSBuild

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

These are standard MSBuild parameters for triggering and configuration web deploy during compilation. These specific settings will create a web deploy package and put it in the staging directory of the build definition.

 

Now, over to the deployment step. Here you can see that you can select your Azure subscription that we registered before. In addition we give the web site a unique name, this name is what the public web site will be called,in this case
it will be http://fabrikamfibervnext.azurewebsites.net.  We also need to specify the Web Site Location for this web site.

The final parameter that we need to specify is the Package. By default it will fetch all zip files located in the staging directory. I want to deploy the FabrikamFiber.Web application, so I change this to $(build.stagingDirectory)FabrikamFiber.Web.zip.

image

That’s it! Save the build definition and queue a new build.After it has completed, you should see a log that looks something like this and you should have a web sites published in Azure.
As you can see, all steps in the process are shown to the left and you can easily see the output from each step.

 

image

 

Deploying Multiple Web Sites

If you’re familiar with the FabrikamFiber sample solution, you know that it actually has two web applications in the same solution, FabrikamFiber.Web and Fabrikamfiber.Extranet.Web.

So, how do we go about to deploy both web sites as part of our build? Well, it couldn’t be easier really, just add a new Azure Web Site Deployment build step and reference the other web deploy package:

 

image

This will now first build the solution and then publish both web sites to Azure.

 

Summary

Now you have seen how easy it is to build and deploy web applications using TFS Build vNext.

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!

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.

TFS Build: Running Static Code Analysis for Specific Configuration

Running Static Code Analysis (SCA) is something that you should be doing regularly to verify your code base against a large set of rules that will check your code for potential problems and how it comply with standard patterns such as naming conventions for example. Microsoft include several different rule sets that you can use for starters, but you can build your own rule sets as well, that contain the rule that you want to use, In addition, you can write your own custom rules and add these to your rule sets.

What you will notice quickly when you start running SCA for larger solutions is that it can take a lot of time. Therefore, you normally don’t want to run this on your local build but instead run it as part of your automated builds. It is recommended to set up a specific build for your projects that measures code quality, by running for example SCA, Code Metrics and Code Coverage. All these things take time to complete, so don’t put these in your Check-In builds, but in a Quality Assurance (QA) build.


Configuring Static Code Analysis

With Team Foundation Build, it is easy to run Static Code Analysis as part of the build, just modify the Perform Code Analysis process parameter in your build definition:

image

 

There are three possible values that you can use here:

  • Never – Never run Static Code Analysis
  • As Configured – If the project is configured to run Static Code Analysis for the current configuration, then SCA will be executed
  • Always – Always run Static Code Analysis, independent of how the projects are configured

If you select As Configured, you need to make sure that you have configured your projects correctly. This is done by opening the Properties window for your project and select the Code Analysis tab:

image 

As you can see, the Code Analysis settings are specific to the Configuration and Platform for the project. This means that you can, for example, run code analysis only on Debug builds and not on Release builds.

Now, while using project specific settings like this to control when SCA is executed works, it has some drawbacks. When the solutions start to grow in size, it can be hard to make sure that the settings in every project is correctly configured. Also, as mentioned before, you typically don’t want to run SCA at all on your local builds, since it makes your build times longer. This can be solved by for example making sure that only the Release configuration has the Enable Code Analysis on Build property set to true, and then you only build the Debug configuration locally.

A better way to solve this is to control this completely from the build definition instead. You do this by setting the Perform Code Analysis process parameter to Always, as shown above. This will make sure that SCA are run for all projects, no matter how they are configured.

Running SCA for specific configurations

A problem that we faced recently at a customer that are running big builds (1+ hours) is that they are building both the and Debug and Release configurations as part of their builds. We wanted to run SCA on these builds, and we don’t want to configure each project (the solutions has 150+ projects in it). But, setting Perform Code Analysis to Always, this will result in SCA being run for both Debug and Release builds resulting in a considerable increase in build time.

So, how can we make sure that SCA is executed on all projects, but only on on (or several) configurations? One way of doing this is to customize your build template and add a parameter that specifies these configurations.

Here are the steps to accomplish this:

  1. If creating a new build template from scratch, branch the DefaultTemplate.11.1.xaml build process template.
  2. Open the template in Visual Studio
  3. Select the top Sequence activity and expand the Arguments tab
  4. At the bottom of the list, add a new parameter called RunSCAForTheseConfigurations with StringList as type

      image

  5. Locate the MetaData process parameter and click on the browse button on the very right
  6. Add a new entry for the new parameter

    image

  7. Inside the workflow, locate the MSBuild activity that is used for compiling the projects. It is right at the end of the Compile the Project sequence:

    image

  8. Right-click the MSBuild activity and select Properties

  9. Locate the RunCodeAnalysis property and open the expression editor

  10. Enter the following expression

    image 

    The expression evaluates if the current configuration (platformConfiguration.Configuration) is specified in our new property.

  11. Save the workflow and check it in

Now you can create a new build definition and enter one or more configurations in the new property:

 

Since this is a property of type StringList, you can add multiple configurations here if you want to.

You can see from this build summary that SCA has only been performed on the Debug configuration, and not for Release.

image

 

Conclusion

I have shown one way to implement automatically running Static Code Analysis on a subset of configurations for a build that builds multiple solutions. This is very useful when you have large builds that compile multiple configurations.

Hope you found this post useful.

Get Started using Build-Deploy-Test Workflow with TFS 2012

TFS 2012 introduces a new type of Lab environment called Standard Environment. This allows you to setup a full Build Deploy Test (BDT) workflow that will build your application, deploy it to your target machine(s) and then run a set of tests on that server to verify the deployment. In TFS 2010, you had to use System Center Virtual Machine Manager and involve half of your IT department to get going. Now all you need is a server (virtual or physical) where you want to deploy and test your application. You don’t even have to install a test agent on the machine, TFS 2012 will do this for you!

Although each step is rather simple, the entire process of setting it up consists of a bunch of steps. So I thought that it could be useful to run through a typical setup.I will also link to some good guidance from MSDN on each topic.

High Level Steps

  1. Install and configure Visual Studio 2012 Test Controller on Target Server
  2. Create Standard Environment
  3. Create Test Plan with Test Case
  4. Run Test Case
  5. Create Coded UI Test from Test Case
  6. Associate Coded UI Test with Test Case
  7. Create Build Definition using LabDefaultTemplate


1. Install and Configure Visual Studio 2012 Test Controller on Target Server

First of all, note that you do not have to have the Test Controller running on the target server. It can be running on another server, as long as the Test Agent can communicate with the test controller and the test controller can communicate with the TFS server. If you have several machines in your environment (web server, database server etc..), the test controller can be installed either on one of those machines or on a dedicated machine.

To install the test controller, simply mount the Visual Studio Agents media on the server and browse to the vstf_controller.exe file located in the TestController folder.
Run through the installation, you might need to reboot the server since it installs .NET 4.5.

When the test controller is installed, the Test Controller configuration tool will launch automatically (if it doesn’t, you can start it from the Start menu). Here you will supply the credentials of the account running the test controller service. Note that this account will be given the necessary permissions in TFS during the configuration. Make sure that you have entered a valid account by pressing the Test link.

Also, you have to register the test controller with the TFS collection where your test plan is located (and usually the code base of course)

image

When you press Apply Settings, all the configuration will be done. You might get some warnings at the end, that might or might not cause a problem later. Be sure to read them carefully.

image

 

For more information about configuring your test controllers, see Setting Up Test Controllers and Test Agents to Manage Tests with Visual Studio

2. Create Standard Environment

Now you need to create a Lab environment in Microsoft Test Manager. Since we are using an existing physical or virtual machine we will create a Standard Environment.

  1. Open MTM and go to Lab Center.
  2. Click New to create a new environment
  3. Enter a name for the environment. Since this environment will only contain one machine, we will use the machine name for the environment (TargetServer in this case)

    image

  4. On the next page, click Add to add a machine to the environment. Enter the name of the machine (TargetServer.Domain.Com), and give it the Web Server role. The name must be reachable both from your machine during configuration and from the TFS app tier server.

    You also need to supply an account that is a local administration on the target server. This is needed in order to automatically install a test agent later on the machine.

    image

  5. On the next page, you can add tags to the machine. This is not needed in this scenario so go to the next page.
  6. Here you will specify which test controller to use and that you want to run UI tests on this environment. This will in result in a Test Agent being automatically installed and configured on the target server.

    image

    The name of the machine where you installed the test controller should be available on the drop down list (TargetServer in this sample). If you can’t see it, you might have selected a different TFS project collection.

  7. Press Next twice and then Verify to verify all the settings:

    image

  8. Press finish. This will now create and prepare the environment, which means that it will remote install a test agent on the machine. As part of this installation, the remote server will be restarted.

3-5. Create Test Plan, Run Test Case, Create Coded UI Test

I will not cover step 3-5 here, there are plenty of information on how you create test plans and test cases and automate them using Coded UI Tests.

In this example I have a test plan called My Application and it contains among other things a test suite called Automated Tests where I plan to put test cases that should be automated and executed as part of the BDT workflow.

image

For more information about Coded UI Tests, see Verifying Code by Using Coded User Interface Tests

 

6. Associate Coded UI Test with Test Case

OK, so now we want to automate our Coded UI Test and have it run as part of the BDT workflow. You might think that you coded UI test already is automated, but the meaning of the term here is that you link your coded UI Test to an existing Test Case, thereby making the Test Case automated. And the test case should be part of the test suite that we will run during the BDT.

  1. Open the solution that contains the coded UI test method.
  2. Open the Test Case work item that you want to automate.
  3. Go to the Associated Automation tab and click on the “…” button.
  4. Select the coded UI test that you corresponds to the test case:

    image

  5. Press OK and the save the test case

For more information about associating an automated test case with a test case, see How to: Associate an Automated Test with a Test Case

7. Create Build Definition using LabDefaultTemplate

Now we are ready to create a build definition that will implement the full BDT workflow. For this purpose we will use the LabDefaultTemplate.11.xaml that comes out of the box in TFS 2012. This build process template lets you take the output of another build and deploy it to each target machine. Since the deployment process will be running on the target server, you will have less problem with permissions and firewalls than if you were to remote deploy your solution.

So, before creating a BDT workflow build definition, make sure that you have an existing build definition that produces a release build of your application.

  1. Go to the Builds hub in Team Explorer and select New Build Definition
  2. Give the build definition a meaningful name, here I called it MyApplication.Deploy

    image

  3. Set the trigger to Manual

    image

  4. Define a workspace for the build definition. Note that a BDT build doesn’t really need a workspace, since all it does is to launch another build definition and deploy the output of that build.
    But TFS doesn’t allow you to save a build definition without adding at least one mapping.
  5. On Build Defaults, select the build controller. Since this build actually won’t produce any output, you can select the “This build does not copy output files to a drop folder” option.

    image

  6. On the process tab, select the LabDefaultTemplate.11.xaml. This is usually located at $/TeamProject/BuildProcessTemplates/LabDefaultTemplate.11.xaml. To configure it, press the … button on the Lab Process Settings property
  7. First, select the environment that you created before:

    image

  8. Select which build that you want to deploy and test. The “Select an existing build” option is very useful when developing the BDT workflow, because you do not have to run through the target build every time, instead it will basically just run through the deployment and test steps which speeds up the process.

    Here I have selected to queue a new build of the MyApplication.Test build definition

    image

  9. On the deploy tab, you need to specify how the application should be installed on the target server. You can supply a list of deployment scripts with arguments that will be executed on the target server. In this example I execute the generated web deploy command file to deploy the solution. If you for example have databases you can use sqlpackage.exe to deploy the database. If you are producing MSI installers in your build, you can run them using msiexec.exe and so on.

    A good practice is to create a batch file that contain the entire deployment that you can run both locally and on the target server. Then you would just execute the deployment batch file here in one single step.

    image

    The workflow defines some variables that are useful when running the deployments. These variables are:

    $(BuildLocation)
    The full path to where your build files are located

    $(InternalComputerName_<VM Name>)
    The computer name for a virtual machine in a SCVMM environment

    $(ComputerName_<VM Name>)
    The fully qualified domain name of the virtual machine

    As you can see, I specify the path to the myapplication.deploy.cmd file using the $(BuildLocation) variable, which is the drop folder of the MyApplication.Test build.
    Note: The test agent account must have read permission in this drop location.

    You can find more information here on Building your Deployment Scripts

  10. On the last tab, we specify which tests to run after deployment. Here I select the test plan and the Automated Tests test suite that we saw before:

    image

    Note that I also selected the automated test settings (called TargetServer in this case) that I have defined for my test plan. In here I define what data that should be collected as part of the test run.

    For more information about test settings, see Specifying Test Settings for Microsoft Test Manager Tests

We are done! Queue your BDT build and wait for it to finish. If the build succeeds, your build summary should look something like this:

image