Versioning assembly during TFS 2013 build with Powershell Scripts

One of the most important news in TFS Build 2010 is the introduction of Workflow Foundation that replaced standard MSBuild scripts used in TFS 2008. Workflow foundation can be really powerful, but indeed it is somewhat scaring and quite often customizing a build can be complex.

You can find some blog post of mine on the subject:

Years are passed, but I still see people scared when it is time to customize the build, especially because the Workflow can be a little bit intimidating. In TFS2013 the build is still managed by Workflow Foundation, but the new workflow basic template now supports simply customization with scripts.

image

Figure 1: Pre-build script configured in the build.

If you look at previous image I’ve setup a simple script to manage assembly versioning and I’ve configured it to run Before the Build, I specified version number thanks to script arguments: -assemblyVersion 1.2.0.0 -fileAssemblyVersion 1.2.J.B. The notation J and B is taken from a nice tool called Tfs Versioning; it is used to manage versioning of assembly with a Custom Action. If you ever used that tool since the beginning (Tfs 2010) you probably discovered that managing build customization with Custom Action is not so easy. Setting up Tfs Versioning tools is super easy if you simply use workflow included in the release, but if you already have a customized workflow, you need to modify the Workflow adding the Custom Activity in the right place with the right parameters.

When you move to TFS 2012 and then to 2012, you need to download the source of the tool and recompile against latest version of build assemblies, then you need to modify the workflow again. This is one of the most annoying problem of Custom Actions, you need to recompile again when you upgrade build servers to new version of TFS.

A script solution is surely more reusable, so I’ve decided to create a little script in Powershell to modify all assemblyinfo.cs files before the build. I’m not a Powershell expert and my solution is not surely optimal, but is a simple proof of concept on how simple is to accomplish build versioning with a script instead of direct customization of the workflow with custom actions.

To have reusable code I’ve create a script called BuildFunctions.psm1 that contains all functions that can be useful during the build. Here it is the function that takes care of versioning for C# projects.

function Update-SourceVersion
{
  Param 
  (
    [string]$SrcPath,
    [string]$assemblyVersion, 
    [string]$fileAssemblyVersion
  )
    
    $buildNumber = $env:TF_BUILD_BUILDNUMBER
    if ($buildNumber -eq $null)
    {
        $buildIncrementalNumber = 0
    }
    else
    {
        $splitted = $buildNumber.Split('.')
        $buildIncrementalNumber = $splitted[$splitted.Length - 1]
    }

    if ($fileAssemblyVersion -eq "")
    {
        $fileAssemblyVersion = $assemblyVersion
    }
    
    Write-Host "Executing Update-SourceVersion in path $SrcPath, Version is $assemblyVersion and File Version is $fileAssemblyVersion"
 

    $AllVersionFiles = Get-ChildItem $SrcPath AssemblyInfo.cs -recurse

    
    $jdate = Get-JulianDate
    $assemblyVersion = $assemblyVersion.Replace("J", $jdate).Replace("B", $buildIncrementalNumber)
    $fileAssemblyVersion = $fileAssemblyVersion.Replace("J", $jdate).Replace("B", $buildIncrementalNumber)
    
    Write-Host "Transformed Version is $assemblyVersion and Transformed File Version is $fileAssemblyVersion"
 

    foreach ($file in $AllVersionFiles) 
    { 
        Write-Host "Modifying file " + $file.FullName
        #save the file for restore
        $backFile = $file.FullName + "._ORI"
        $tempFile = $file.FullName + ".tmp"
        Copy-Item $file.FullName $backFile
        #now load all content of the original file and rewrite modified to the same file
        Get-Content $file.FullName |
        %{$_ -replace 'AssemblyVersion\("[0-9]+(\.([0-9]+|\*)){1,3}"\)', "AssemblyVersion(""$assemblyVersion"")" } |
        %{$_ -replace 'AssemblyFileVersion\("[0-9]+(\.([0-9]+|\*)){1,3}"\)', "AssemblyFileVersion(""$fileAssemblyVersion"")" }  > $tempFile
        Move-Item $tempFile $file.FullName -force
    }
 
}

If you are a powershell expert, please do not shoot the pianist :), this is my very first serious Powershell script. The cool part is that Build Subsystem stores some interesting values in Environment Variables, so I can simply found the actual build number with the code: $buildNumber = $env:TF_BUILD_BUILDNUMBER. The rest of the script is simply string and Date manipulation and a RegularExpression to replace AssemblyVersion and AssemblyFileVersion in original version of the file, you can find details Here in the original post I’ve used as a sample for my version.

The cool part about this script is that you can import it in another script to use functions decalred in it. The goal is maintaining all complexities inside this base script and use these functions in real scripts that gets called by TFS Build. This simplify maintenance, because you only need to maintain function only once.  As an example this is the simple PreBuild script that manages assembly numbering.

 Param
(
[string] $assemblyVersion,
[string] $fileAssemblyVersion
)


Write-Host "Running Pre Build Scripts"

$scriptRoot = Split-Path -Parent -Path $MyInvocation.MyCommand.Definition

Import-Module $scriptRoot\BuildFunctions

if ($assemblyVersion -eq "")
{
    $assemblyVersion = "2.3.0.0"
    $fileAssemblyVersion = "2.3.J.B"
}
 

Thanks to Import-Module commandlet I can import all functions of file BuildFunctions.psm1. This is much more simpler than having Custom Actions and insert them inside the workflow.

One of the coolest part of Powershell scripts is the ability to define parameters in the head of the script so you can specify them with notation –parameter value leaving all the parsing burden of commandline to Powershell infrastructure. Another cool part of this approach is that you can include a base AssemblyVersion number to be used if no valid number is passed by Command Line. Thanks to Git Support you can create a simple build definition valid for multiple branches and in such scenario it is much better to have version number stored in source control, because you can specify a different build number for each branch.

Now just fire a build and verify that assemblies in drop folder contains correct numbering.

image

Figure 2: Verify that all the assemblies contains the correct AssemblyVersionFile Number

If something went wrong, you can look at the diagnostic of the build to verify what is happened in the script. All Write-Host directive are in fact intercepted and are collected inside the diagnostics of the build.

image

Figure 3: Output of the scripts is collected inside the Diagnostic of the build.

Thanks to this approach you can

  • Create a simple reusable set of functions inside a Powershell Base Script
  • Use functions contained in Powershell Base Script inside simpler script for each build
  • All Write-Host output is redirected in diagnostic log of the build to diagnose problem.
  • Customization is still valid if you upgrade TFS
  • You can customize the build simply specifying path of the script.
  • You can test the script running it locally

If you compare how simple is this approach compared to managing customization of Workflow with Custom Action you can understand what a great improvement you got using the new TFS Build templates.

Gian Maria.

Deploy Asp.NET web site on IIS from TFS Build

In the last article of the series, I dealt with Deploying on Azure Web Sites from on-premise TFS, but the very same technique can be used to automatically deploy from a standard TFS Build to a standard Web Site hosted in IIS and not in Azure. For this demo I’ve prepared a VM on azure, but the configuration is the very same if the VM is on-premise or if you use a physical machine to run IIS. The only difference between deploy on Azure Web Site is that we are deploying on a Web site hosted on IIS.

Step 1: Configure IIS for Web Deploy

You can find a detailed article here with all the steps needed to configure Web Deploy Publishing, once Microsoft Web Deploy is installed, just create a site, and enable Web Publishing right-clicking on it. If the Deploy menu does not appears, some part of the Web Deploy Publishing service was not installed properly.

image

Figure 1: Configure Web Deploy Publishing

Configuring a Web Deploy publishing for a web site is just a matter of specifying some information and most of the time everything can be left as default value.

image

Figure 2: Deploy configuration

This dialog will setup the site to enable MSBuild publishing, it saves a .publishSettings file on the location specified (in this example the desktop). The most important settings is the url for the publishing server connection. Be sure that used port (8172 in this example) is opened in the firewall and that all router are configured to make it available to the machine where the build will be run.

Step 2: Configure the Publish settings file

Even if the configuration dialog shown in Figure 2 creates a publishSettings file, it is possible to create such file directly from Visual Studio. This is usually a preferable option because it is possible to customize to support Database Publishing and changing the connection string. Actually creating a publish settings from scratch from Visual Studio is really easy, you just Right Click the web project and choose publish, then choose to create a new publishing profile.

image

Figure 3: Configure the connection for publishing

The Validate connection button is really useful to verify if everything works correctly, once it is green it is possible to further customize the settings. A most common configuration, when you work with Database Projects, is the ability to configure automatic database schema publishing.

image

Figure 4: Configure for automatic Database Update and change the connection string used in destination server

Once everything is correctly configured you can close the configuration dialog, save the publish settings and check-in everything in source control. To verify if everything work you can do a Test Publish from Visual Studio, just be aware that the location of the .dacpac file should be changed to be found by the Build Controller (described later in this article)

Step 3: Configure the build

This is the most easy step, since it is the very same of Deploying on Azure Web Site from on-premise TFS, I’ve actually cloned a build used for that post, and simply changed the name and credentials of the publish settings file used.

image

Figure 5: Configure MSBuild Arguments to deploy the site

The whole string is the following one, you are simply asking to MsBuild to publish the site using the AzureVM profile.

/p:DeployOnBuild=true /p:PublishProfile=AzureVM /p:AllowUntrustedCertificate=true /p:UserName=gianmaria.ricci /p:Password=xxxxxxxxx

Clearly, to being able to publish database schema, you should manually change the location of the .dacpac file as described in previous article.

As a final note, always configure the build to index sources using a Symbol Server. If a Symbol Server is configured and there is a bug in production site that is not reproducible dev machines, it is possible to use the Intellitrace standalone collector to collect an intellitrace file, and once the itrace file is loaded in Visual Studio it will automatically download original source files used to compile the version of the site used to generate the trace.

SNAGHTML3e3488

Figure 6: Once symbol server is configured, I can browse the source from intellitrace file

This permits to simply open the intellitrace file offline, navigate through events, and have VS automatically download Source code for you, without even knowing where the solution is located.

Gian Maria.

Deploying on Azure Web sites from on-premise TFS

Many people asked me during course if the ability to automatically deploy to Windows Azure Web Sites is restricted only to those people that are using TF Service (TFS on the cloud), or if they can deploy with an on-premise installation of TFS.

The answer is clearly YES, and I strongly suggest you to watch the Continuous Deployment with Microsoft Visual Studio session of Brian Randell to have a deep explanation of all the possibilities you have to achieve automatic deployment of your applications from Team Foundation Server.

Deploying from on-premise TFS to Azure Web Site is simple, because it is only a matter of configuring msbuild to use the right publish file. The difference from an automatic deploy with TF Service is: when you publish from TF Service, the web site has a nice “deployment” tab listing all the deployment done with TF Service and a connection with Build Details, while if you publish from on-premise you loose this data and the Web Site completely ignores who and when the site was deployed.

To deploy on Azure from on-premise TFS you just need to download the publish profile of the Web Site into a local folder.

image

Figure 1: Download the publish profile

Then you can right-click your web project node from the Solution Explorer in Visual Studio and choose “publish”, from there you can “import” the file you just downloaded.

image

Figure 2: Import the publish profile

This file contains all the information needed to publish against that Web Site, you can modify as you need

image

Figure 3: Details of the publish definition.

From the list of definition (Figure 2) I usually rename the publish file to something more useful, as an example AzureDemoWebSite.

image

Figure 4: Rename your publish file

I usually modify the publication file to include publishing the database to the Azure Database, you do not need to specify the connection string of the database, it will be taken from the profile and the only piece of information that the script needs is the relative path of the .dacpac file to deploy.

image

Figure 5: Modification done to the publishing profile to deploy a database project

Now you should check-in everything and you are only one step away from publishing from azure. Just create a standard build, but instruct MSBUILD that you want to also deploy with a specific publication profile. This can be done in the Advanced section of the Build Process

image

Figure 6: Instruct MSBuild with custom Arguments to deploy the site.

The whole string is this one

/p:DeployOnBuild=true /p:PublishProfile=AzureDemoWebSite /p:AllowUntrustedCertificate=true

/p:UserName=$tailspinonpremise /p:Password=2Xocq…

The tricky part is specifying correct credentials. You can find username and password directly opening the original publication profile file you downloaded from azure. Publish file in Visual Studio or your standard Azure credential wont work. The username is usually in the form $websitename and the password is a long sequence of characters and numbers, you cannot miss it.

image

Figure 7: The original content of the publication profile, it contains the username and password that you need to publish to that web project

Now you can simply fire the build, wait for it to complete and your web site will be automatically deployed.

image

Figure 8: Build succeeded and site was deployed

image

Figure 9: Site was deployed

Publishing on on-premise IIS is quite the same, it is just a matter of creating the right publish file and use it to deploy during a build.

Gian Maria.

Code coverage during TFS 2012 build

A common question about TFS 2012 build is: how can I ask for code coverage?

The answer is really simple, you should go to the test section of build definition and change the run settings from Default to another setting that includes code coverage and this is really everything you need to do.

image_thumb2

Figure 1: Change run settings to enable code coverage

Now launch the build and verify that you have your binaries instrumented and Code Coverage correctly computed.

image_thumb5

Usually this lead to another question: Can I decide which assembly to include in code coverage instead of having all of them instrumented?

The solution to this answer is creating a customized test run setting file, the only drawback is that you have no template inside Visual Studio and no editor (as you had in VS 2010 with TestSettings files). The good news is that you can simply add an xml file inside your solution, give to it the extension .runsettings and copy inside it this simple fragment of configuration.

<?xml version="1.0" encoding="utf-8"?>
<!-- File name extension must be .runsettings -->
<RunSettings>
  <DataCollectionRunSettings>
    <DataCollectors>
      <DataCollector friendlyName="Code Coverage" uri="datacollector://Microsoft/CodeCoverage/2.0" assemblyQualifiedName="Microsoft.VisualStudio.Coverage.DynamicCoverageDataCollector, Microsoft.VisualStudio.TraceCollector, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
        <Configuration>
          <CodeCoverage>
            <!-- Match assembly file paths: -->
            <ModulePaths>
              <Include>
                <ModulePath>.*fabrikamfiber.web.dll$</ModulePath>
              </Include>

            </ModulePaths>

            <!-- We recommend you do not change the following values: -->
            <UseVerifiableInstrumentation>True</UseVerifiableInstrumentation>
            <AllowLowIntegrityProcesses>True</AllowLowIntegrityProcesses>
            <CollectFromChildProcesses>True</CollectFromChildProcesses>
            <CollectAspDotNet>False</CollectAspDotNet>

          </CodeCoverage>
        </Configuration>
      </DataCollector>
    </DataCollectors>
  </DataCollectionRunSettings>
</RunSettings>

You have lots of options, but in this example I’m interested only in limiting the number of assemblies that will be instrumented for Code Coverage. This can be done simply specifying one or more regular expression in the ModulePaths section. You can use Include to define regex for inclusion, or you can use exclude to specify which assemblies will be excluded.

Once you authored this file, you should use it as active test setting configuration to test if everything is good, and verify that after running all of your test locally, Code Coverage result is what you expected. Remember that once you’ve have this run settings activated, it will be used for all of your local test run.

image_thumb[2]

Once everything is ok you need to store this file in source control, check-in and modify Build configuration to use this customized file as a Run Settings File for the build and the game is done.

image_thumb[5]

Now fire the build again, this time only selected assemblies will be used for code coverage.

image_thumb[8]

MSDN Link to test run setting file: Customizing Code Coverage Analysis

Gian Maria.

TF Service: deploy on Azure Web Site with Database Project

The ability to automatically deploy a site on Azure Web Site from TFService is really interesting, but sadly enough there is no out-of-the-box solution to update the structure of an Azure Database with a VS2012 Database Project. In this post I’ll show how to modify the standard build template to deploy a Database Project during Azure Web Site Deployment. I’ve blogged in the past to explain how to Deploy a Database Project with TFS Build, but that post refers to the old type of Database Project (VS2010) and now I want to explain how to customize the AzureContinuousDeployment build to deploy on azure a database project of VS2012.

First of all create a copy of the standard build file in BuildProcessTemplate directory.

image

Figure 1: Create a copy of the original AzureContinuousDeployment.11.xaml file and check-in

This will avoid messing with the original build definition; to accomplish it simply create a copy of the file in your workspace, check-in the new file and open your local copy from Visual Studio to modify the Workflow definition. The main problem if you are not familiar with TFS Build Workflow, is to find the place where to put the new instructions. To help you locate the point where you should modify the build file, please look at Figure 2, that shows where to locate the Try Compile and Test sequence.

image

Figure 2: Try Compile and Test is the part of the workflow you need to modify.

Now you should expand Try Compile and Test, scroll down until you find a sequence called Deploy on Test Success, expand it and you will find a Publish Output sequence where you can find a call to a MSDeploy action that actually is deploying the web site.

image

Figure 3: The point of the workflow where the site is deployed

The right place where to insert additional operations to deploy some stuff is right after the MSDeploy.

First of all you should add a couple of Arguments to the Workflow to make it more generic and make it reusable; with arguments the user will be able to specify if he want to deploy a database (DeployDatabase argument) and the Database Output File Name (DatabaseProjectOutputFile) directly from the build editor. This will permit you to keep only one xaml file with the build workflow, and have multiple build, based on that workflow, and choose for each one what database to deploy. You should also configure the Metadata property to specify Name, description and other properties of your custom arguments. You can have a look at TFS2010 Create a Personalized Build post for details about Metadata and Workflow Arguments.

image

Figure 4: Add a couple of arguments to parametrize the workflow.

The whole customization is represented in Figure 5 and you can see that it is really easy. You start adding a condition to verify if the argument DeployDatabase is true, name this condition If Should Deploy Database, and then add a standard Sequence inside it in the then area. If you exclude WriteBuildMessage actions, that are merely logging, the whole operation is done by only two Actions.

image

Figure 5: The sequence added to the standard workflow to deploy a database project.

The ConvertWorkspaceItem is used to convert a path expressed in TFS source control (starts with dollar sign) to local path of the build server. This is needed because to deploy a database project the easiest path is using SqlPublish.exe program, (installed locally in your developing machines when you install Sql Server Data Tools). I’ve simply located them in my HD, then copied inside a folder of the source control to have it included along with the source code of my project. This technique is really common to achieve Continuous Deployment, if is it possible, including all the tools needed to build and deploy your solution should be included in the source code of the project.

image

Figure 6: Insert all SqlPackage.exe distribution in your source code and check-in, this will make the tool available to the Build Agent

This is the easiest way to have an executable available for build agents. When the agents starts the build it does a get latest before compiling the source and this will automatically get tools to deploy database along with the source code. This technique is really useful for TF Service because you have no access to the elastic Build installation, and you have no way to install SqlPackage.exe in the Build Server. (Note: If you have your Build Agent on premise, you can simply install SqlPackage.exe, then find the location on the hard disk and simply hardcode  (or add another variable) installation path in the build definition and get rid of the ConvertWorkspaceItem action )

The ConvertWorkspaceItem action is needed because I know the path on the source control Es: $/myproject/trunk/tools/Deploy but I do not know where the Build Server is creating the workspace to build the source. The ConvertWorkspaceItem is the action that permits me to convert a path on source control to a real path on disk. Configuration is represented in Figure 6

image

Figure 7: Configuration of the ConvertWorkspaceItem.

This is the configuration of the ConvertWorkspaceItem action and the Input path is composed by Workspace.Folders.First().ServerItem variable, that represents the first mapped server folder on the workspace used to build the solution. This is a convenient way to make the build file reusable, as long as you remember that the first folder to map should be the top level folder of your project (trunk, or specific branch), and it should contains a folder called /Tools/Deploy/SqlDac that should contains the SqlPackage.exe distribution. The result property point to a Variable of the workflow (I have previously declared), that will contain the physical location of the SqlPackage.exe tool after the execution of the action.

The other interesting action is the InvokeProcess used to invoke the SqlPackage.exe tool to deploy the database. You can customize the build with custom action, or msbuild scripts (I’ve talked a lot about it in the past) but the easiest way is to include an executable in source control Tools directory and have it invoked from InvokeProcess. This solution does not require deploying custom assemblies, and is really simple to setup. If you expand it you can find that this action have a couple of slots to place an activity that will be invoked with the standard output and the standard error, usually you have them setup as in Figure 8. The WriteBuildError activity is really useful because it write error message on the build log, and it makes also the build as Partially Failed, so if the database deploy operation fails, I have automatically my build marked as partially failed without the need of any other further customization work.

image

Figure 8: Intercept standard output and error and have them dumped as build message

This is the complete configuration of the InvokeProcess action.

image

Figure 9: Configuration of the InvokeProcess activity

Actually the interesting part is the FileName property that use the SqlPackageLocation variable (populated by ConvertWorkspaceItem) to locate where the agent downloaded SqlPackage.exe and the Arguments that contains all the info for the deploy. Here is its full value.

image

Figure 10: Configuration of the Arguments property, it contains the full command line arguments for SqlPackage.exe tool

The cool part is the ability to use the variable azureWebSiteProfile.SqlServerDBConnectionString that contains the database connection string extracted from the publish file, it was parsed for you by AzureContinuousDeployment build. The outputDirectory variable is the directory where the build copied all the output of the various project after the build, and is the location of the .dacpac file of your database project. Finally you can check-in modified workflow back to TFS.

Now you can let azure create a standard Build for you, with standard configuration from Azure Management portal, this will create a build in your Team Project. Once the build is created, you can simply edit to use new Build Workflow. As first step you need to change the workspace in Source Settings, because you need to map the entire trunk (main) directory, because you want Tools to be downloaded with source.

image

Figure 11: Change configuration of the workflow, map the entire trunk of the project to include the Tools directory

Finally you can go to the Process section so you can change the workflow, from the standard AzureContinuousDeployment to the one you customized with previous steps.

image

Figure 12: Choose the new Build workflow for the build

Now you should see in all variables added in Figure 4, if you correctly filled metadata for them, you should see description for them. I also created a new area of configuration called DeployCustom to separate all standard build properties by new ones introduced by the customization.

image

Figure 13: Specify values for your custom variables

Now I can proceed to set Enable Database Deploy to true and specify the name of the dacpac file I want to deploy. Name of dacpac file 99% is the name of the database project followed by the .dacpac extension.

Now at each Build the Azure database connected to the Web Site would be updated to the new structure of the database project.

If you prefer You can download the modified build definition file from Here but I strongly suggest you to modify your file. First of all because the original publish file can be updated from the time this post was published, but it is also important that you try to being familiar with build customization, so you will be able to further modify it if you need to deploy other stuff.

Gian Maria.