Customize Team Build 2010 – Part 16: Specify the relative reference path

by Ewald Hofman 6. April 2011 05:56

In the series the following parts have been published

  1. Part 1: Introduction
  2. Part 2: Add arguments and variables
  3. Part 3: Use more complex arguments
  4. Part 4: Create your own activity
  5. Part 5: Increase AssemblyVersion
  6. Part 6: Use custom type for an argument
  7. Part 7: How is the custom assembly found
  8. Part 8: Send information to the build log
  9. Part 9: Impersonate activities (run under other credentials)
  10. Part 10: Include Version Number in the Build Number
  11. Part 11: Speed up opening my build process template
  12. Part 12: How to debug my custom activities
  13. Part 13: Get control over the Build Output
  14. Part 14: Execute a PowerShell script
  15. Part 15: Fail a build based on the exit code of a console application
  16. Part 16: Specify the relative reference path


As I have already blogged about, it is not intuitive how to specify the paths where the build server has to look for references that are stored in Source Control. It is a common practice to store 3rd party libraries in Source Control, so they are available to everyone, everyone uses the same version of the libraries and updating a library can be done centrally.

In Team Build 2010 these paths are specified as a parameter for MSBuild. What we will do in this post is building the values for this parameter based on the values in an argument. You are now pretty aware how to customize the build template, so let’s do the modifications in another way. Instead of opening the xaml file in the workflow designer, we open it in the XML editor. You can open it in the XML Editor by either selecting the Open with menu (see the context menu), or by choosing the View code option.

To add this functionality we need to:

  1. Specify a new argument
  2. Add the argument to the metadata
  3. Build the absolute paths for the references and add these paths to the MSBuild arguments

1. Specify a new argument

Locate at the top of the document the Members (which are the arguments) of the XAML

image

and add the following line

<x:Property Name="ReferencePaths" Type="InArgument(s:String[])" />

image

2. Add the argument to the metadata

Then locate the line

<mtbw:ProcessParameterMetadataCollection>

and paste the following line

<mtbw:ProcessParameterMetadata Category="Misc" Description="The list of reference paths, relative to the root path in the Workspace mapping." DisplayName="Reference paths" ParameterName="ReferencePaths" />
image

3. Build the absolute paths for the references and add these paths to the MSBuild arguments

Now locate the place where the assignments are done to the variables used in the agent.

image

And add the following lines after the last Assign activity

        <Sequence DisplayName="Initialize ReferencePath" sap:VirtualizedContainerService.HintSize="464,428">
          <Sequence.Variables>
            <Variable x:TypeArguments="x:String" Name="ReferencePathsArgument">
              <Variable.Default>
                <Literal x:TypeArguments="x:String" Value="" />
              </Variable.Default>
            </Variable>
          </Sequence.Variables>
          <sap:WorkflowViewStateService.ViewState>
            <scg:Dictionary x:TypeArguments="x:String, x:Object">
              <x:Boolean x:Key="IsExpanded">True</x:Boolean>
            </scg:Dictionary>
          </sap:WorkflowViewStateService.ViewState>
          <ForEach x:TypeArguments="x:String" DisplayName="Iterate through the paths" sap:VirtualizedContainerService.HintSize="287,206" mtbwt:BuildTrackingParticipant.Importance="Low" Values="[ReferencePaths]">
            <ActivityAction x:TypeArguments="x:String">
              <ActivityAction.Argument>
                <DelegateInArgument x:TypeArguments="x:String" Name="path" />
              </ActivityAction.Argument>
              <Assign x:TypeArguments="x:String" DisplayName="Build ReferencePath argument" sap:VirtualizedContainerService.HintSize="257,100" mtbwt:BuildTrackingParticipant.Importance="Low" 
To="[ReferencePathsArgument]" Value="[If(String.IsNullOrEmpty(ReferencePathsArgument), &quot;&quot;, ReferencePathsArgument + &quot;;&quot;) + IO.Path.Combine(SourcesDirectory, path)]" />             </ActivityAction>           </ForEach>           <Assign DisplayName="Append the reference paths to the MSBuild Arguments" sap:VirtualizedContainerService.HintSize="287,58">             <Assign.To>               <OutArgument x:TypeArguments="x:String">[MSBuildArguments]</OutArgument>             </Assign.To>             <Assign.Value>               <InArgument x:TypeArguments="x:String">[String.Format("{0} /p:ReferencePath=""{1}""", MSBuildArguments, ReferencePathsArgument)]</InArgument>             </Assign.Value>           </Assign>         </Sequence>

Now you can use the template to specify the paths relative to SourcesDirectory.


You can download the full solution at BuildProcess.zip. It will include the sources of every part and will continue to evolve.

Tags:

Team Build | VS 2010

Customize Team Build 2010 – Part 13: Get control over the Build Output

by Ewald Hofman 12. December 2010 22:57

In the series the following parts have been published

  1. Part 1: Introduction
  2. Part 2: Add arguments and variables
  3. Part 3: Use more complex arguments
  4. Part 4: Create your own activity
  5. Part 5: Increase AssemblyVersion
  6. Part 6: Use custom type for an argument
  7. Part 7: How is the custom assembly found
  8. Part 8: Send information to the build log
  9. Part 9: Impersonate activities (run under other credentials)
  10. Part 10: Include Version Number in the Build Number
  11. Part 11: Speed up opening my build process template
  12. Part 12: How to debug my custom activities
  13. Part 13: Get control over the Build Output
  14. Part 14: Execute a PowerShell script
  15. Part 15: Fail a build based on the exit code of a console application

In the part 8, I have explained how you can add informational messages, warnings or errors to the build output. If you want to integrate with other lines of text to the build output, you need to do more. This post will show you how you can add extra steps, additional information and hyperlinks to the build output.

UPDATE 13-12-2010: Thanks to Jason Pricket, it is now also possible to not show every activity in the build log. This is really useful when you are doing for-loops in your template. To see how you can do that, check out Jason's blog: http://blogs.msdn.com/b/jpricket/archive/2010/12/09/tfs-2010-making-your-build-log-less-noisy.aspx

Add an hyperlink to the end of the build output

Lets start with a simple example of how you can adjust the build output. In this case we are going to add at the end of the build output an hyperlink where a user can click on to for example start the deployment to the test environment.

In part 4 you can find information how you can create a custom activity

To add information to the build output, you need the BuildDetail. This value is a variable in your xaml and is thus easily transferable to you custom activity. Besides the BuildDetail the user has also to specify the text and the url that has to be added to the end of the build output.

The following code segment shows you how you can achieve this.

    [BuildActivity(HostEnvironmentOption.All)]
    public sealed class AddHyperlinkToBuildOutput : CodeActivity
    {
        [RequiredArgument]
        public InArgument<IBuildDetail> BuildDetail { get; set; }
 
        [RequiredArgument]
        public InArgument<string> DisplayText { get; set; }
 
        [RequiredArgument]
        public InArgument<string> Url { get; set; }
 
        protected override void Execute(CodeActivityContext context)
        {
            // Obtain the runtime value of the input arguments           
            IBuildDetail buildDetail = context.GetValue(this.BuildDetail);
            string displayText = context.GetValue(this.DisplayText);
            string url = context.GetValue(this.Url);

            // Add the hyperlink
            buildDetail.Information.AddExternalLink(displayText, new Uri(url));
            buildDetail.Information.Save();
        }
    }
If you add this activity to somewhere in your build process template (within the scope Run on Agent), you will get the following build output
image 

Add an line of text to the build output

The next challenge is to add this kind of output not only to the end of the build output but at the step that is currently executing. To be able to do this, you need the current node in the build output. The following code shows you how you can achieve this.

First you need to get the current activity tracking, which you can get with the following line of code

            IActivityTracking currentTracking = context.GetExtension<IBuildLoggingExtension>().GetActivityTracking(context);

Then you can create a new node and set its type to Activity Tracking Node (so copy it from the current node) and do nice things with the node.

            IBuildInformationNode childNode = currentTracking.Node.Children.CreateNode();
            childNode.Type = currentTracking.Node.Type;
            childNode.Fields.Add("DisplayText", "This text is displayed.");

You can also add a build step to display progress

            IBuildStep buildStep = childNode.Children.AddBuildStep("Custom Build Step", "This is my custom build step");
            buildStep.FinishTime = DateTime.Now.AddSeconds(10);
            buildStep.Status = BuildStepStatus.Succeeded;
Or you can add an hyperlink to the node
            childNode.Children.AddExternalLink("My link", new Uri(http://www.ewaldhofman.nl));
When you combine this together you get the following result in the build output

image 


You can download the full solution at BuildProcess.zip. It will include the sources of every part and will continue to evolve.

Tags:

Part 15: Fail a build based on the exit code of a console application

by Ewald Hofman 9. November 2010 06:51

In the series the following parts have been published

  1. Part 1: Introduction
  2. Part 2: Add arguments and variables
  3. Part 3: Use more complex arguments
  4. Part 4: Create your own activity
  5. Part 5: Increase AssemblyVersion
  6. Part 6: Use custom type for an argument
  7. Part 7: How is the custom assembly found
  8. Part 8: Send information to the build log
  9. Part 9: Impersonate activities (run under other credentials)
  10. Part 10: Include Version Number in the Build Number
  11. Part 11: Speed up opening my build process template
  12. Part 12: How to debug my custom activities
  13. Part 13: Get control over the Build Output
  14. Part 14: Execute a PowerShell script
  15. Part 15: Fail a build based on the exit code of a console application
  16. Part 16: Specify the relative reference path


When you have a Console Application or a batch file that has errors, the exitcode is set to another value then 0. You would expect that the build would see this and report an error. This is not true however. First we setup the scenario.

  1. Add a ConsoleApplication project to your solution you are building.
  2. In the Main function set the ExitCode to 1
  3.     class Program
        {
           
    static void Main(string
    [] args)
            {
               
    Console.WriteLine("This is an error in the script."
    );
               
    Environment.ExitCode = 1;
            }
        }

  4. Checkin the code. You can choose to include this Console Application in the build or you can decide to add the exe to source control
  5. Now modify the Build Process Template CustomTemplate.xaml
  6. Add an argument ErrornousScript
  7. Scroll down beneath the TryCatch activity called “Try Compile, Test, and Associate Changesets and Work Items”
  8. Add an Sequence activity to the template
  9. In the Sequence, add a ConvertWorkspaceItem and an InvokeProcess activity (see Part 14: Execute a PowerShell script  for more detailed steps)
  10. In the FileName property of the InvokeProcess use the ErrornousScript so the ConsoleApplication will be called.
  11. Modify the build definition and make sure that the ErrornousScript is executing the exe that is setting the ExitCode to 1.

You have now setup a build definition that will execute the errornous Console Application. When you run it, you will see that the build succeeds. This is not what you want!

image

To solve this, you can make use of the Result property on the InvokeProcess activity.

So lets change our Build Process Template.

  1. Add the new variables (scoped to the sequence where you run the Console Application) called ExitCode (type = Int32) and ErrorMessage
  2. Click on the InvokeProcess activity and change the Result property to ExitCode
  3. In the Handle Standard Output of the InvokeProcess add a Sequence activity
  4. In the Sequence activity, add an Assign primitive. Set the following properties:
    To = ErrorMessage
    Value = If(Not String.IsNullOrEmpty(ErrorMessage), Environment.NewLine + ErrorMessage, "") + stdOutput
  5. And add the default BuildMessage to the sequence that outputs the stdOutput
  6. Add beneath the InvokeProcess activity and If activity with the condition ExitCode <> 0
  7. In the Then section add a Throw activity and set the Exception property to New Exception(ErrorMessage)

The complete workflow looks now like

image

When you now check in the Build Process Template and run the build, you get the following result

image

And that is exactly what we want.


 

You can download the full solution at BuildProcess.zip. It will include the sources of every part and will continue to evolve.

Tags:

Team Build | VS 2010

Part 14: Execute a PowerShell script

by Ewald Hofman 9. November 2010 05:32

In the series the following parts have been published

  1. Part 1: Introduction
  2. Part 2: Add arguments and variables
  3. Part 3: Use more complex arguments
  4. Part 4: Create your own activity
  5. Part 5: Increase AssemblyVersion
  6. Part 6: Use custom type for an argument
  7. Part 7: How is the custom assembly found
  8. Part 8: Send information to the build log
  9. Part 9: Impersonate activities (run under other credentials)
  10. Part 10: Include Version Number in the Build Number
  11. Part 11: Speed up opening my build process template
  12. Part 12: How to debug my custom activities
  13. Part 13: Get control over the Build Output
  14. Part 14: Execute a PowerShell script
  15. Part 15: Fail a build based on the exit code of a console application
  16. Part 16: Specify the relative reference path

With PowerShell you can add powerful scripting to your build to for example execute a deployment. If you want more information on PowerShell, please refer to http://technet.microsoft.com/en-us/library/aa973757.aspx

For this example we will create a simple PowerShell script that prints “Hello world!”. To create the script, create a new text file and name it “HelloWorld.ps1”. Add to the contents of the script:

Write-Host “Hello World!”

To test the script do the following:

  1. Open the command prompt
  2. To run the script you must change the execution policy. To do this execute in the command prompt:

    powershell set-executionpolicy remotesigned
  3. Now go to the directory where you have saved the PowerShell script
  4. Execute the following command

    powershell .\HelloWorld.ps1

image_thumb1

In this example I use a relative path, but when the path to the PowerShell script contains spaces, you need to change the syntax to

powershell "& '<full path to script>' "

for example:

powershell "& ‘C:\sources\Build Customization\SolutionToBuild\PowerShell Scripts\HellloWorld.ps1’ "

In this blog post, I create a new solution and that solution includes also this PowerShell script. I want to create an argument on the Build Process Template that holds the path to the PowerShell script. In the Build Process Template I will add an InvokeProcess activity to execute the PowerShell command. This InvokeProcess activity needs the location of the script as an argument for the PowerShell command. Since you don’t know the full path at the build server of this script, you can either specify in the argument the relative path of the script, but it is hard to find out what the relative path is. I prefer to specify the location of the script in source control and then convert that server path to a local path. To do this conversion you can use the ConvertWorkspaceItem activity.

So to complete the task, open the Build Process Template CustomTemplate.xaml that we created in earlier parts, follow the following steps

  1. Add a new argument called “DeploymentScript” and set the appropriate settings in the metadata. See Part 2: Add arguments and variables  for more information.
  2. Scroll down beneath the TryCatch activity called “Try Compile, Test, and Associate Changesets and Work Items”
  3. Add a new If activity and set the condition to "Not String.IsNullOrEmpty(DeploymentScript)" to ensure it will only run when the argument is passed.
  4. Add in the Then branch of the If activity a new Sequence activity and rename it to “Start deployment”
  5. Click on the activity and add a new variable called DeploymentScriptFilename (scoped to the “Start deployment” Sequence
  6. Add a ConvertWorkspaceItem activity on the “Start deployment” Sequence
  7. Add a InvokeProcess activity beneath the ConvertWorkspaceItem activity in the “Start deployment” Sequence
  8. Click on the ConvertWorkspaceItem activity and change the properties
    DisplayName = Convert deployment script filename
    Input = DeploymentScript
    Result = DeploymentScriptFilename
    Workspace = Workspace
  9. Click on the InvokeProcess activity and change the properties
    Arguments = String.Format(" ""& '{0}' "" ", DeploymentScriptFilename)
    DisplayName = Execute deployment script
    FileName = "PowerShell"
  10. To see results from the powershell command drop a WriteBuildMessage activity on the "Handle Standard Output" and pass the stdOutput variable to the Message property.
  11. Do the same for a WriteBuildError activity on the "Handle Error Output"
  12. To publish it, check in the Build Process Template

This leads to the following result

image_thumb[14]

We now go to the build definition that depends on the template and set the path of the deployment script to the server path to the HelloWorld.ps1. (If you want to see the result of the PowerShell script, change the Logging verbosity to Detailed or Diagnostic). Save and run the build.

image_thumb[16]

A lot of the deployment scripts you have will have some kind of arguments (like username / password or environment variables) that you want to define in the Build Definition. To make the PowerShell configurable, you can follow the following steps.

Create a new script and give it the name "HelloWho.ps1". In the contents of the file add the following lines:

param (
        $person
    )

$message = [System.String]::Format(“Hello {0}!", $person)
Write-Host $message

When you now run the script on the command prompt, you will see the following

image_thumb[18]

So lets change the Build Process Template to accept one parameter for the deployment script. You can of course make it configurable to add a for-loop that reads through a collection of parameters but that is out of scope of this blog post.

  1. Add a new Argument called DeploymentScriptParameter
  2. In the InvokeProcess activity where the PowerShell command is executed, modify the Arguments property to String.Format(" ""& '{0}' '{1}' "" ", DeploymentScriptFilename, DeploymentScriptParameter)
  3. Check in the Build Process Template

Now modify the build definition and set the Parameter of the deployment to any value and run the build.

image_thumb[21]


You can download the full solution at BuildProcess.zip. It will include the sources of every part and will continue to evolve.

Tags:

Team Build | VS 2010

Customize Team Build 2010 – Part 13: Get control over the Build Output

by Ewald Hofman 2. October 2010 02:17

In the series the following parts have been published

  1. Part 1: Introduction
  2. Part 2: Add arguments and variables
  3. Part 3: Use more complex arguments
  4. Part 4: Create your own activity
  5. Part 5: Increase AssemblyVersion
  6. Part 6: Use custom type for an argument
  7. Part 7: How is the custom assembly found
  8. Part 8: Send information to the build log
  9. Part 9: Impersonate activities (run under other credentials)
  10. Part 10: Include Version Number in the Build Number
  11. Part 11: Speed up opening my build process template
  12. Part 12: How to debug my custom activities
  13. Part 13: Get control over the Build Output
  14. Part 14: Execute a PowerShell script
  15. Part 15: Fail a build based on the exit code of a console application
  16. Part 16: Specify the relative reference path 

 

In the part 8, I have explained how you can add informational messages, warnings or errors to the build output. If you want to integrate with other lines of text to the build output, you need to do more. This post will show you how you can add extra steps, additional information and hyperlinks to the build output.

Add an hyperlink to the end of the build output

Lets start with a simple example of how you can adjust the build output. In this case we are going to add at the end of the build output an hyperlink where a user can click on to for example start the deployment to the test environment.

In part 4 you can find information how you can create a custom activity

To add information to the build output, you need the BuildDetail. This value is a variable in your xaml and is thus easily transferable to you custom activity. Besides the BuildDetail the user has also to specify the text and the url that has to be added to the end of the build output.

The following code segment shows you how you can achieve this.

    [BuildActivity(HostEnvironmentOption.All)]
    public sealed class AddHyperlinkToBuildOutput : CodeActivity
    {
        [RequiredArgument]
        public InArgument<IBuildDetail> BuildDetail { get; set; }
 
        [RequiredArgument]
        public InArgument<string> DisplayText { get; set; }
 
        [RequiredArgument]
        public InArgument<string> Url { get; set; }
 
        protected override void Execute(CodeActivityContext context)
        {
            // Obtain the runtime value of the input arguments           
            IBuildDetail buildDetail = context.GetValue(this.BuildDetail);
            string displayText = context.GetValue(this.DisplayText);
            string url = context.GetValue(this.Url);

            // Add the hyperlink
            buildDetail.Information.AddExternalLink(displayText, new Uri(url));
            buildDetail.Information.Save();
        }
    }
If you add this activity to somewhere in your build process template (within the scope Run on Agent), you will get the following build output
image 

Add an line of text to the build output

The next challenge is to add this kind of output not only to the end of the build output but at the step that is currently executing. To be able to do this, you need the current node in the build output. The following code shows you how you can achieve this.

First you need to get the current activity tracking, which you can get with the following line of code

            IActivityTracking currentTracking = context.GetExtension<IBuildLoggingExtension>().GetActivityTracking(context);

Then you can create a new node and set its type to Activity Tracking Node (so copy it from the current node) and do nice things with the node.

            IBuildInformationNode childNode = currentTracking.Node.Children.CreateNode();
            childNode.Type = currentTracking.Node.Type;
            childNode.Fields.Add("DisplayText", "This text is displayed.");

You can also add a build step to display progress

            IBuildStep buildStep = childNode.Children.AddBuildStep("Custom Build Step", "This is my custom build step");
            buildStep.FinishTime = DateTime.Now.AddSeconds(10);
            buildStep.Status = BuildStepStatus.Succeeded;
Or you can add an hyperlink to the node
            childNode.Children.AddExternalLink("My link", new Uri(http://www.ewaldhofman.nl));
When you combine this together you get the following result in the build output

image

 


 

You can download the full solution at BuildProcess.zip. It will include the sources of every part and will continue to evolve.

Tags:

Team Build | VSTS 2010

Customize Team Build 2010 – Part 12: How to debug my custom activities

by Ewald Hofman 1. October 2010 14:19

In the series the following parts have been published

  1. Part 1: Introduction
  2. Part 2: Add arguments and variables
  3. Part 3: Use more complex arguments
  4. Part 4: Create your own activity
  5. Part 5: Increase AssemblyVersion
  6. Part 6: Use custom type for an argument
  7. Part 7: How is the custom assembly found
  8. Part 8: Send information to the build log
  9. Part 9: Impersonate activities (run under other credentials)
  10. Part 10: Include Version Number in the Build Number
  11. Part 11: Speed up opening my build process template
  12. Part 12: How to debug my custom activities
  13. Part 13: Get control over the Build Output
  14. Part 14: Execute a PowerShell script
  15. Part 15: Fail a build based on the exit code of a console application
  16. Part 16: Specify the relative reference path 

 

Developers are “spoilt” persons who expect to be able to have easy debugging experiences for every technique they work with. So they also expect it when developing custom activities for the build process template. This post describes how you can debug your custom activities without having to develop on the build server itself.

Remote debugging prerequisites

The prerequisite for these steps are to install the Microsoft Visual Studio Remote Debugging Monitor. You can find information how to install this at http://msdn.microsoft.com/en-us/library/bt727f1t.aspx. I chose for the option to run the remote debugger on the build server from a file share.

Debugging symbols prerequisites

To be able to start the debugging, you need to have the pdb files on the buildserver together with the assembly. The pdb must have been build with Full Debug Info.

Steps

In my setup I have a development machine and a build server. To setup the remote debugging, I performed the following steps

  1. Locate on your development machine the folder C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\Remote Debugger
  2. Create a share for the Remote Debugger folder. Make sure that the share (and the folder) has the correct permissions so the user on the build server has access to the share.
  3. On the build server go to the shared “Remote Debugger” folder
  4. Start msvsmon.exe which is located in the folder that represents the platform of the build server. This will open a winform application like

    image 
  5. Go back to your development machine and open the BuildProcess solution.
  6. Start the Attach to process command (Ctrl+Alt+P)
  7. Type in the Qualifier the name of the build server. In my case the user account that has started the msvsmon is another user then the user on my development machine. In that case you have to type the qualifier in the format that is shown in the Remote Debugging Monitor (in my case LOCAL\Administrator@TFSLAB) and confirm it by pressing <Enter>

    image
  8. Since the build service is running with other credentials, check the option “Show processes from all users”.
  9. Now the Attach to process dialog shows the TFSBuildServiceHost process

    image
  10. Set the breakpoint in the activity you want to debug and kick of a build.

Be aware that when you attach to the TFSBuildServiceHost that you debug every single build that is run by this windows service, so make sure you don’t debug the build server that is in production!


You can download the full solution at BuildProcess.zip. It will include the sources of every part and will continue to evolve.

Tags:

Team Build | VSTS 2010

Customize Team Build 2010 – Part 11: Speed up opening my build process template

by Ewald Hofman 1. October 2010 13:13

In the series the following parts have been published

  1. Part 1: Introduction
  2. Part 2: Add arguments and variables
  3. Part 3: Use more complex arguments
  4. Part 4: Create your own activity
  5. Part 5: Increase AssemblyVersion
  6. Part 6: Use custom type for an argument
  7. Part 7: How is the custom assembly found
  8. Part 8: Send information to the build log
  9. Part 9: Impersonate activities (run under other credentials)
  10. Part 10: Include Version Number in the Build Number
  11. Part 11: Speed up opening my build process template
  12. Part 12: How to debug my custom activities
  13. Part 13: Get control over the Build Output
  14. Part 14: Execute a PowerShell script
  15. Part 15: Fail a build based on the exit code of a console application 
  16. Part 16: Specify the relative reference path 

 

When you open the build process template, it takes 15 – 30 seconds until it opens. When you are in the process of creating your custom build process template, this can be very frustrating. Thanks to Ed Blankenship how has found a little trick to speed up the opening of the template. It now only takes a few seconds.

  1. Create a file called empty.xaml and place the following text in it:
    <Activity xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities">
    </Activity>
  2. Open this file in Visual Studio.
  3. In the toolbox panel, add a new tab called “Team Foundation Build Activities”.  Note that it is important to get the tab name correct because if it is not correct then the activities will be reloaded.
  4. Inside the new tab, right click and select “Choose Items”
  5. Click the Browse button
  6. Load the file C:\Windows\Microsoft.NET\assembly\GAC_MSIL\Microsoft.TeamFoundation.Build.Workflow\v4.0_10.0.0.0__b03f5f7f11d50a3a\Microsoft.TeamFoundation.Build.Workflow.dll
  7. Click OK to add the toolbox items to the tab.
  8. Create another new tab called “Team Foundation LabManagement Activities”.
  9. Inside the new tab, right click and select “Choose Items”
  10. Click the Browse button
  11. Load the file C:\Windows\Microsoft.NET\assembly\GAC_MSIL\Microsoft.TeamFoundation.Lab.Workflow.Activities\v4.0_10.0.0.0__b03f5f7f11d50a3a\Microsoft.TeamFoundation.Lab.Workflow.Activities.dll
  12. Click OK to add the toolbox items to the tab.

You can download the full solution at BuildProcess.zip. It will include the sources of every part and will continue to evolve.

Tags:

Team Build | VSTS 2010

Customize Team Build 2010 – Part 10: Include Version Number in the Build Number

by Ewald Hofman 1. June 2010 11:07

In the series the following parts have been published

  1. Part 1: Introduction
  2. Part 2: Add arguments and variables
  3. Part 3: Use more complex arguments
  4. Part 4: Create your own activity
  5. Part 5: Increase AssemblyVersion
  6. Part 6: Use custom type for an argument
  7. Part 7: How is the custom assembly found
  8. Part 8: Send information to the build log
  9. Part 9: Impersonate activities (run under other credentials)
  10. Part 10: Include Version Number in the Build Number
  11. Part 11: Speed up opening my build process template
  12. Part 12: How to debug my custom activities
  13. Part 13: Get control over the Build Output
  14. Part 14: Execute a PowerShell script
  15. Part 15: Fail a build based on the exit code of a console application
  16. Part 16: Specify the relative reference path

 

When you queue a new build, the number (or name) of the build will be determined based on the BuildNumberFormat. In the 5th part of this series, the AssemblyFileVersion is increased on every run. To be able to have a relation between an assembly (for which you can retrieve the file version) and the build, I want to include the version number in the build number. This post will show you how you can achieve this.

You can change this format by clicking on the ellipsis (…) button when you edit the build definition. You see then the BuildNumber Format Editor.

image

When you click on the Macros >> button, you get a list of all available variables.

image

This list does not contain the version number, nor is it extensible to add a custom token. So we have to do something else.

Approach

The approach I will use is the following:

  1. Add the text $(Version) to the BuildNumberFormat.
  2. Read the AssemblyFileVersion from the first file that is found which applies to the AssemblyInfoFileMask (see Customize Team Build 2010 – Part 5: Increase AssemblyVersion), and store this value in a variable called Version
  3. Replace in the BulidNumberFormat the text $(Version) with the Version variable.
  4. The default workflow is continued to determine the build number based on the BuildNumberFormat

The solution for this approach consists of two classes. One to retrieve the version number and one to replace the $(Version) token.

Retrieve version number

I have chosen to get the version number directly from Source Control, because the determining of the build number is performed before the sources are retrieved locally. When the AssemblyFileVersion is found, the build part of the version number is increased because in a later stadium of the Build Process Template, the file version is increased in the files.

This results in the following class:

using System;
using System.Activities;
using System.IO;
using System.Text.RegularExpressions;
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.Build.Workflow.Activities;
using Microsoft.TeamFoundation.VersionControl.Client;

namespace BuildTasks.Activities
{
    [BuildActivity(HostEnvironmentOption.Controller)]
    public sealed class GetAssemblyVersion : CodeActivity<string>
    {
        [RequiredArgument]
        public InArgument<string> AssemblyInfoFileMask { get; set; }

        [RequiredArgument]
        public InArgument<IBuildDetail> BuildDetail { get; set; }

        protected override string Execute(CodeActivityContext context)
        {
            // Obtain the runtime value of the input arguments
            string assemblyInfoFileMask = context.GetValue(this.AssemblyInfoFileMask);
            IBuildDetail buildDetail = context.GetValue(this.BuildDetail);

            var workspace = buildDetail.BuildDefinition.Workspace;
            var vc = buildDetail.BuildServer.TeamProjectCollection.GetService<VersionControlServer>();

            string attribute = "AssemblyFileVersion";

            // Define the regular expression to find (which is for example 'AssemblyFileVersion("1.0.0.0")' )
            Regex regex = new Regex(attribute + @"\(""\d+\.\d+\.\d+\.\d+""\)");

            // For every workspace folder (mapping)
            foreach (var folder in workspace.Mappings)
            {
                // Get all files (recursively) that apply to the file mask
                ItemSet itemSet = vc.GetItems(folder.ServerItem + "//" + assemblyInfoFileMask, RecursionType.Full);
                foreach (Item item in itemSet.Items)
                {
                    context.TrackBuildMessage(string.Format("Download {0}", item.ServerItem));
                   
                    // Download the file
                    string localFile = Path.GetTempFileName();
                    item.DownloadFile(localFile);

                    // Read the text from the AssemblyInfo file
                    string text = File.ReadAllText(localFile);
                    // Search for the first occurrence of the version attribute
                    Match match = regex.Match(text);
                    // When found
                    if (match.Success)
                    {
                        // Retrieve the version number
                        string versionNumber = match.Value.Substring(attribute.Length + 2, match.Value.Length - attribute.Length - 4);
                        Version version = new Version(versionNumber);
                        // Increase the build number -> this will be the new version number for the build
                        Version newVersion = new Version(version.Major, version.Minor, version.Build + 1, version.Revision);

                        context.TrackBuildMessage(string.Format("Version found {0}", newVersion));

                        return newVersion.ToString();
                    }
                }
            }

            return "No version found";
        }
    }
}
Replace token in BuildNumberFormat

As stated before I want to reuse the BuildNumberFormat capabilities to be as flexible as possible. So I add a simple activity to replace the $(Version) token.

using System.Activities;
using Microsoft.TeamFoundation.Build.Client;

namespace BuildTasks.Activities
{
    [BuildActivity(HostEnvironmentOption.Controller)]
    public sealed class UpdateVersionInBuildNumber : CodeActivity<string>
    {
        [RequiredArgument]
        public InArgument<string> BuildNumberFormat { get; set; }

        [RequiredArgument]
        public InArgument<string> VersionNumber { get; set; }

        protected override string Execute(CodeActivityContext context)
        {
            string buildNumberFormat = context.GetValue<string>(this.BuildNumberFormat);
            string versionNumber = context.GetValue<string>(this.VersionNumber);

            return buildNumberFormat.Replace("$(Version)", versionNumber);
        }
    }
}
Change the Build Process Template

Now compile the Activity project to get the new activities in the template (if that does not add the activities, then restart Visual Studio). Now open the CustomTemplate.xaml.

Select the “Update Build Number for Triggered Builds” activity, and select the Variables. Add a new variable called newVersionNumber.

image

Now add the GetAssembly to the “Update Build Number for Triggered Builds” activity (before the “Update Build Number” activity), and set the arguments to the following values.

image

Add the UpdateVersionInBuildNumber under the GetAssembly and set the arguments to the following values

image

The workflow will look like the following

image

The Build Process Template is now ready. Check in the changes to proceed to the next steps.

Update BuildNumberFormat

Next go to the build definition that makes use of the Build Process Template, and choose Edit Build Definition. Then go to the Process Tab. In the Basic group, you will find the BuildNumberFormat. By default, this is set to $(BuildDefinitionName)_$(Date:yyyyMMdd)$(Rev:.r). I want to change this to include the version number and the date. I can achieve this with the following BuildNumberFormat (but you can use any format you like):

$(BuildDefinitionName) $(Version) ($(Date:yyyyMMdd HHmm))

Now save the build definition and queue a new build. You will now see that the format of the build number is changed to something like

image


 

You can download the full solution at BuildProcess.zip. It will include the sources of every part and will continue to evolve.

Tags:

Team Build | VSTS 2010

Customize Team Build 2010 – Part 9: Impersonate activities (run under other credentials)

by Ewald Hofman 27. May 2010 22:25

In the series the following parts have been published

  1. Part 1: Introduction
  2. Part 2: Add arguments and variables
  3. Part 3: Use more complex arguments
  4. Part 4: Create your own activity
  5. Part 5: Increase AssemblyVersion
  6. Part 6: Use custom type for an argument
  7. Part 7: How is the custom assembly found
  8. Part 8: Send information to the build log
  9. Part 9: Impersonate activities (run under other credentials)
  10. Part 10: Include Version Number in the Build Number
  11. Part 11: Speed up opening my build process template
  12. Part 12: How to debug my custom activities
  13. Part 13: Get control over the Build Output
  14. Part 14: Execute a PowerShell script
  15. Part 15: Fail a build based on the exit code of a console application
  16. Part 16: Specify the relative reference path

 

 

Update: If you want to use the TFS Object Model in the activity code, check the following post: http://blogs.msdn.com/b/taylaf/archive/2009/12/04/introducing-tfs-impersonation.aspx. It gives you the ability to execute TFS request on behalf on someone else without providing a password.

There are situation in which you want to run your activity under other credentials, which is also called impersonation. This could be the case for example when you deploy your solution to the development environment.

To achieve the impersonation of the an activity we need to be able to specify the credentials in an argument of the build. Because you don’t want that the password is visible, we need to specify a custom type. This process is covered in Customize Team Build 2010 – Part 6: Use custom type for an argument.

Secondly we need to impersonate. To achieve this I create a class with that logs on as a different user in the constructor and in the destructor (dispose method) the user is logged off again.

using System.Runtime.InteropServices;
using System.Security.Principal;
using System;
using Achmea.Build.Tasks.CustomType;

namespace Achmea.Build.Tasks.Library
{
    public class Impersonation : IDisposable
    {
        private WindowsImpersonationContext _impersonatedUser = null;
        private IntPtr _userHandle;

        public Impersonation(Credential credentials)
        {
            if (credentials != null && !string.IsNullOrEmpty(credentials.UserName))
            {
                _userHandle = new IntPtr(0);

                bool returnValue = LogonUser(credentials.UserName, credentials.Domain, credentials.Password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref _userHandle);

                if (!returnValue)
                    throw new ApplicationException("Could not impersonate user");

                WindowsIdentity newId = new WindowsIdentity(_userHandle);
                _impersonatedUser = newId.Impersonate();
            }
        }

        #region IDisposable Members

        public void Dispose()
        {
            if (_impersonatedUser != null)
            {
                _impersonatedUser.Undo();
                CloseHandle(_userHandle);
            }
        }

        #endregion

        #region Interop imports/constants
        public const int LOGON32_LOGON_INTERACTIVE = 2;
        public const int LOGON32_LOGON_SERVICE = 3;
        public const int LOGON32_PROVIDER_DEFAULT = 0;

        [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
        public static extern bool LogonUser(String lpszUserName, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public extern static bool CloseHandle(IntPtr handle);
        #endregion
    }
}

You can now easily impersonate an activity by surrounding the code of the activity by constructing the Impersonation class in the first line, and dispose it at the last line. In C# you can make it even easier when you use the “using” statement

using System.Activities;
using Achmea.Build.Tasks.CustomType;
using Achmea.Build.Tasks.Library;
using Microsoft.TeamFoundation.Build.Client;

namespace BuildTasks.Activities
{
    [BuildActivity(HostEnvironmentOption.Agent)]
    public class CopyFile : CodeActivity
    {

        public InArgument<Credential> Credentials { get; set; }

        protected override void Execute(CodeActivityContext context)
        {
            using (Impersonation impersonation = new Impersonation(context.GetValue(this.Credentials)))
            {
                // Insert your activity code over here
            }
        }
    }
}

 

You can download the full solution at BuildProcess.zip. It will include the sources of every part and will continue to evolve.

Tags:

Team Build | VSTS 2010

Customize Team Build 2010 – Part 8: Send information to the build log?

by Ewald Hofman 27. May 2010 21:45

In the series the following parts have been published

  1. Part 1: Introduction
  2. Part 2: Add arguments and variables
  3. Part 3: Use more complex arguments
  4. Part 4: Create your own activity
  5. Part 5: Increase AssemblyVersion
  6. Part 6: Use custom type for an argument
  7. Part 7: How is the custom assembly found
  8. Part 8: Send information to the build log
  9. Part 9: Impersonate activities (run under other credentials)
  10. Part 10: Include Version Number in the Build Number
  11. Part 11: Speed up opening my build process template
  12. Part 12: How to debug my custom activities
  13. Part 13: Get control over the Build Output
  14. Part 14: Execute a PowerShell script
  15. Part 15: Fail a build based on the exit code of a console application
  16. Part 16: Specify the relative reference path

In the build you can set the verbosity to different levels to get diagnostic information from the activities that are executed. The information from the activities that come out of the box are great, but if you could add your own diagnostic information would be wonderful.

 

To add this information is pretty simple.

  1. Add a reference to the Microsoft.TeamFoundation.Build.Workflow assembly. You can find it in the folder C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies
  2. Then add a using statement to the namespace Microsoft.TeamFoundation.Build.Workflow.Activities
  3. You can now add the line context.TrackMessage(“My diagnostic information”); to show the information in the build log. You can also specify the importance of the message to indicate in which Verbosity it will be shown. The following table shows when the message will be shown.

    Verbosity Importance
    Minimal -
    Normal High
    Detailed Normal
    Diagnostic Low

I created an activity with an argument that reports that argument back to the build log, also with the different possibilities of presenting the information.

using System.Activities;
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.Build.Workflow.Activities;

namespace BuildTasks.Activities
{

    [BuildActivity(HostEnvironmentOption.All)]
    public sealed class DiagnosticInformation : CodeActivity
    {
        public InArgument<string> TextIn { get; set; }

        protected override void Execute(CodeActivityContext context)
        {
            string textIn = context.GetValue(this.TextIn);

            context.TrackBuildMessage("Message: " + textIn);
            context.TrackBuildMessage("Message (High importance): " + textIn, BuildMessageImportance.High);
            context.TrackBuildMessage("Message (Normal importance): " + textIn, BuildMessageImportance.Normal);
            context.TrackBuildMessage("Message (Low importance): " + textIn, BuildMessageImportance.Low);
            context.TrackBuildError(textIn);
            context.TrackBuildWarning(textIn);
        }
    }
}

When you run add the activity to your Build Process Template and run the build, you will see the following result for the different verbosities.

Verbosity Result
Diagnostic image
Detailed image
Normal image
Minimal image

 

You can download the full solution at BuildProcess.zip. It will include the sources of every part and will continue to evolve.

Tags:

Team Build | VSTS 2010

Customize Team Build 2010 – Part 7: How is the custom assembly found?

by Ewald Hofman 27. May 2010 04:36

In the series the following parts have been published

  1. Part 1: Introduction
  2. Part 2: Add arguments and variables
  3. Part 3: Use more complex arguments
  4. Part 4: Create your own activity
  5. Part 5: Increase AssemblyVersion
  6. Part 6: Use custom type for an argument
  7. Part 7: How is the custom assembly found
  8. Part 8: Send information to the build log
  9. Part 9: Impersonate activities (run under other credentials)
  10. Part 10: Include Version Number in the Build Number
  11. Part 11: Speed up opening my build process template
  12. Part 12: How to debug my custom activities
  13. Part 13: Get control over the Build Output
  14. Part 14: Execute a PowerShell script
  15. Part 15: Fail a build based on the exit code of a console application
  16. Part 16: Specify the relative reference path

The solution that is created in the parts 4 till 6 uses an assembly that contains the custom activities, the custom types and the custom editors. When another person edits a build definition based on the modified Build Process Template, that person was able to use the custom types and editors. I wondered how Visual Studio was able to find the correct assembly.

I figured out that it looks in the following locations

  1. The “version control path to custom assemblies” that is specified in the build controller the build uses
  2. The GAC
  3. The Visual Studio probing path

If the assembly can still not be found, try to reopen Visual Studio. This will ensure that the assembly is reloaded.

Version control path to custom assemblies

When you edit the build definition, you specify the controller you want to use.

image

In this build controller, you can set the Version Control path that contains the assemblies that are used by the Build Process Template. You can see the information of the build controller by right clicking on the Builds node in the Team Explorer window. Select then Manage Build Controllers.

image

A dialog pops up with all the build controllers and its agents

image

Select the controller you use in the build definition, and click on Properties

image

Over here you can specify the path where the assemblies live in Source Control you want to use when someone Edits a build definition.

The Visual Studio probing path (or GAC)

 

 

 

 

If you don’t want to specify the assembly via the Version Control path in the build controller, you can also make it available by installing it in the GAC or in one of the Visual Studio probing path.

You can find the probing paths of Visual Studio by editing the devenv.exe.config file. You can find this file at C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE (or C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE for 32 bits machines)

image

By default this config contains the following directories (relative to the C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE directory):

  • PublicAssemblies
  • PrivateAssemblies
  • CommonExtensions\Microsoft\TemplateProviders
  • PrivateAssemblies\DataCollectors
  • PrivateAssemblies\DataCollectors\x86
  • CommonExtensions\Microsoft\Editor
  • CommonExtensions\Platform\Debugger

UPDATE 31-8-2010: Thanks to venkateswar who provided the following solution for a common problem in http://social.msdn.microsoft.com/Forums/en-US/tfsbuild/thread/2b24609d-fc8f-4908-bdc5-6986d5e53ecc/

"TF21509:An error occured while initializing a build definition \CustomBuildTasks\BuildName:Cannot create
unknown type '{clr-namepace:NamespaceName,asembly=AssemblyName}Activityname'."

You can solve this by adding the attribute [BuildActivity(HostEnvironmentOption.All)] at class level.

[BuildActivity(HostEnvironmentOption.All)]
public sealed class CustomActivity : CodeActivity

See more info on this at http://www.ewaldhofman.nl/post/2010/04/29/Customize-Team-Build-2010-e28093-Part-4-Create-your-own-activity.aspx (step 10)


UPDATE 30-9-2010: Thanks to Sven Hubert who was so kind to share his solution.

If your custom assembly uses a dependent assembly (reference) which is needed to run activities, they will not get deployed properly. If this is the case you will get “unknown type” errors on build definition initialization.

To work around this issue, add a fake CodeActivity to your dependent assembly with the following class scoped attribute:

[Microsoft.TeamFoundation.Build.Client.BuildActivity(Microsoft.TeamFoundation.Build.Client.HostEnvironmentOption.All)]
Public sealed class FakeActivity : CodeActivity


 

You can download the full solution at BuildProcess.zip. It will include the sources of every part and will continue to evolve.

Tags:

Team Build | VSTS 2010

Customize Team Build 2010 – Part 6: Use custom type for an argument

by Ewald Hofman 17. May 2010 07:06

In the series the following parts have been published

  1. Part 1: Introduction
  2. Part 2: Add arguments and variables
  3. Part 3: Use more complex arguments
  4. Part 4: Create your own activity
  5. Part 5: Increase AssemblyVersion
  6. Part 6: Use custom type for an argument
  7. Part 7: How is the custom assembly found
  8. Part 8: Send information to the build log
  9. Part 9: Impersonate activities (run under other credentials)
  10. Part 10: Include Version Number in the Build Number
  11. Part 11: Speed up opening my build process template
  12. Part 12: How to debug my custom activities
  13. Part 13: Get control over the Build Output
  14. Part 14: Execute a PowerShell script
  15. Part 15: Fail a build based on the exit code of a console application
  16. Part 16: Specify the relative reference path

In this post I will show you how you can create your own type for an argument, including an editor to change the value for the argument.

In this post I want to add an argument that holds an username and password. I will use this information to execute one of my activities with different credentials. Since I don’t want that the password is visible to anyone, I will create a new type called Credential. This has a UserName and Password property. In the properties window of the Process tab the Credential argument will only show the UserName. When I edit the argument a dialog is opened where I can enter the UserName and Password. If you want to make this option even more secure, you can even provide an encryption for the internal storage of the password. For the simplicity this is not implemented in this post.

At the end of the post, the classes, that are required for the solution, are attached for your convenience.

  1. Open the solution that is created in the following post: Customize Team Build 2010 – Part 4: Create your own activity.
  2. Create a new folder in the BuildTasks project called CustomType. In this folder all files required to support a custom type including the editor is stored.

    Credential
    In the credential class we will store the information that is required for the storage of the credentials. There is no magic in this class.
  3. Add a new class to this folder and call it Credential
  4. Add the UserName and Password property to this class.
  5. When editing the Process tab for the Build Definition, the ToString() function is called to retrieve the value. So override this function and return the UserName property.
  6. This will result in the following code
    namespace BuildTasks.CustomType
    {
        public class Credential
        {
            public string UserName { get; set; }
            public string Password { get; set; }

            public override string ToString()
            {
                return UserName;
            }

        }
    }



     
    CredentialDialog
    This dialog will be shown when an user edits the value for the argument in the Process tab of the Build Definition. It gives you the ability to provide a user friendly method of providing values.
     
  7. Add a new form to this folder and call it CredentialDialog
  8. Create an UI like this and call the two textboxes UserNameTextbox and PasswordTextbox.

    image
  9. Now add the following code to the textbox:
    using System.Windows.Forms;

    namespace BuildTasks.CustomType
    {
        public partial class CredentialDialog : Form
       
        {
            public CredentialDialog()
            {
                InitializeComponent();
            }

            public string Password
            {
                get
                {
                    return PasswordMaskedTextbox.Text;
                }
                set
                {
                    PasswordMaskedTextbox.Text = value;
                }
            }
           
            public string UserName
            {
                get
                {
                    return UserNameTextbox.Text;
                }
                set
                {
                    UserNameTextbox.Text = value;
                }
            }
        }
    }
    CredentialEditor
    This class contains the metadata for Visual Studio what you want to do when the user clicks on the ellipsis button of the argument 
  10. Add a new class to the CustomType folder and call it CredentialEditor.
  11. This class overrides from the UITypeEditor class. You should override two methods, being EditValue and GetEditStyle. In the GetEditStyle you can tell Visual Studio to open up a combobox or a dialog. In this post I choose to open a dialog.
  12. In the EditValue you add the logic that is executed when the user clicks on the ellipsis button.
  13. The full code of the class is the following:

    using System.Drawing.Design;
    using System.Windows.Forms.Design;
    using System.ComponentModel;
    using System;
    using System.Windows.Forms;

    namespace BuildTasks.CustomType
    {

        class CredentialEditor : UITypeEditor
        {

            public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
            {
                if (provider != null)
                {
                    IWindowsFormsEditorService editorService = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));

                    if (editorService != null)
                    {
                        Credential credential = value as Credential;

                        using (CredentialDialog dialog = new CredentialDialog())
                        {
                            dialog.UserName = credential.UserName;
                            dialog.Password = credential.Password;

                            if (editorService.ShowDialog(dialog) == DialogResult.OK)
                            {
                                credential.UserName = dialog.UserName;
                                credential.Password = dialog.Password;
                            }
                        }
                    }

                }

                return value;
                
            }

            public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
            {
                return UITypeEditorEditStyle.Modal;
            }
        }
    }

    Metadata
    Now we add a new argument with the correct type and provide metadata to the Build Process Template so Visual Studio knows it has to execute the logic that is specified in the CredentialEditor.
  14. First build the BuildTasks project so we have access to the new Credentials type.
  15. Now open the CustomTemplate.xaml Build Process Template
  16. Open the Arguments list and add a new argument called Credentials
  17. In the Argument Type choose for the “Browse for Types …” option

    image 
  18. In the Browse dialog, navigate to the BuildTasks reference and choose the Credential class.

    image
  19. Click on OK to close the dialog
  20. Now locate the Metadata argument in the list to provide metadata for this argument. When you have found it, click on the ellipsis button. This will open the Metadata editor.
  21. Add the Credentials parameter. The most exciting we do in this dialog is providing the Editor value. You have to give it the value of the CredentialEditor class. You specify the reference to this class in the for of <full namespace>.<class>,<assembly name>. In our case, this is BuildTasks.CustomType.CredentialEditor,BuildTasks

    image
  22. Save the CustomTemplate.xaml file and check it in.
    Test the dialog
  23. Edit the build definition that is using the Build Process Template and go to the Process tab. You will now see a new argument called Credential.
  24. When you click on the ellipsis, you will see the new dialog.

     image
  25. When you accept the values, you will see the following in the Credential argument

    image

 

You can download the full solution at BuildProcess.zip. It will include the sources of every part and will continue to evolve.

Tags:

Team Build | VSTS 2010

Customize Team Build 2010 – Part 5: Increase AssemblyVersion

by Ewald Hofman 13. May 2010 08:33

In the series the following parts have been published

  1. Part 1: Introduction
  2. Part 2: Add arguments and variables
  3. Part 3: Use more complex arguments
  4. Part 4: Create your own activity
  5. Part 5: Increase AssemblyVersion
  6. Part 6: Use custom type for an argument
  7. Part 7: How is the custom assembly found
  8. Part 8: Send information to the build log
  9. Part 9: Impersonate activities (run under other credentials)
  10. Part 10: Include Version Number in the Build Number
  11. Part 11: Speed up opening my build process template
  12. Part 12: How to debug my custom activities
  13. Part 13: Get control over the Build Output
  14. Part 14: Execute a PowerShell script
  15. Part 15: Fail a build based on the exit code of a console application
  16. Part 16: Specify the relative reference path

In this post I will show you how you can create an activity to increase the version in the AssemblyInfo file. The solution is pretty simple and could be the base for your own implementation if you want to have another approach.

The solution uses the version number that is stored in the AssemblyInfo file in Source Control. The advantage is that it is the simplest implementation possible, but for every changeset you will get an additional changeset with the change on the AssemblyInfo which ‘pollutes’ the History of your code base. Another approach could be is to store the latest version number in an external system (like a file or database), or to use a generated version number (such as the date: <year>.<month>.<day>.0).

At the end of the post, the three classes, that are required for the solution, are attached for your convenience.

  1. Open the solution that is created in the following post: Customize Team Build 2010 – Part 4: Create your own activity.

    IncreaseAssemblyVersion
  2. Add in the Activities folder a new class called “IncreaseAssemblyVersion”
  3. In this class we add the arguments AssemblyInfoFileMask and SourcesDirectory
     
    image
  4. Then we override the Execute method, which increases the build number of the version (which is the 3rd number) in all the AssemblyInfo files. 

    image 

    Checkout
  5. Add in the Activities folder a new class called “Checkout”
  6. In this class we add the arguments AssemblyInfoFileMask and Workspace
      
    image
  7. Then we override the Execute method, which checks all files out that are in the scope of the defined workspace in the build definition. 

    image 

    Checkin
  8. Add in the Activities folder a new class called “Checkin”
  9. In this class we add the argument Workspace
      
    image
  10. Then we override the Execute method, which checks all pending changes in the workspace in. These pending changes are all the files that are changed by the IncreaseAssemblyVersion activity 

    image
  11. Now we add the new activity to the Build Process Template. Open the CustomTemplate.xaml in the Template project.
  12. When you open the toolbox, you see all the activities that are in the BuildTasks assembly, including the Checkin, Checkout and the IncreaseAssemblyVersion activities

     image
  13. Now navigate in the CustomTemplate workflow to the “Get Workspace” activity (which is halfway in the workflow). From the Control Flow tab in the Toolbox drop the Sequence activity below the Get Workspace activity. Then add the Checkout, IncreaseAssemblyVersion and Checkin activity in the Sequence. 

      image
  14. When you look at the properties for the Checkout activity, you have to set the values for two arguments 

    image
  15. For the AssemblyInfoFileMask you can either specify an hard-coded value in the template (so every build that uses the template uses the same mask), or you can create an argument (so every build can configure its own mask) and use that argument as the value. I choose to use a argument. To do this, add an AssemblyInfoFileMask argument to the Build Process Template

    image
  16. Open the Metadata and create a new entry

     image
  17. Now that argument is created, it is easy to setup the workflow. You can see the values in the following table.

    Activity Property Value
    Checkout AssemblyInfoFileMask AssemblyInfoFileMask
      Workspace Workspace
    IncreaseAssemblyVersion AssemblyInfoFileMask AssemblyInfoFileMask
      SourcesDirectory SourcesDirectory
    Checkin Workspace Workspace
  18. Save the CustomTemplate.xaml and check in the file.
  19. Now Edit the build definition that makes use of this Build Process Template and go to the Process tab. Since we have defined a default value for the argument, it is prefilled. Change it when applicable.

    image
  20. Now queue your build and you will get an incremental unique version number. You can tweak it to your own needs.

 

You can download the full solution at BuildProcess.zip. It will include the sources of every part and will continue to evolve.

Tags:

Team Build | VSTS 2010

Customize Team Build 2010 – Part 4: Create your own activity

by Ewald Hofman 29. April 2010 12:21

In the series the following parts have been published

  1. Part 1: Introduction
  2. Part 2: Add arguments and variables
  3. Part 3: Use more complex arguments
  4. Part 4: Create your own activity
  5. Part 5: Increase AssemblyVersion
  6. Part 6: Use custom type for an argument
  7. Part 7: How is the custom assembly found
  8. Part 8: Send information to the build log
  9. Part 9: Impersonate activities (run under other credentials)
  10. Part 10: Include Version Number in the Build Number
  11. Part 11: Speed up opening my build process template
  12. Part 12: How to debug my custom activities
  13. Part 13: Get control over the Build Output
  14. Part 14: Execute a PowerShell script
  15. Part 15: Fail a build based on the exit code of a console application
  16. Part 16: Specify the relative reference path

In this post I will show you how you can add your own custom activities. Debugging the customizations is not the best experience. In this post I will show you how I modified the build process template. If you have a better idea, feel free to ping me (because I am never to old to learn :) )

  1. Open a new visual studio 2010 editor and create a new solution with 2 projects (of type Class Library) called Template and BuildTasks. One of the projects is for the custom code and custom activities, the other one to modify the build process template.
  2. Add a project reference from the Template project to the BuildTasks project

    image
  3. Add in the BuildTasks project a reference to the following assemblies:
    1. From c:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0
      1. Microsoft.TeamFoundation.Build.Client.dll
    2. System.Activities
  4.   And add the following references to the Template project
    1. From c:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0
      1. Microsoft.TeamFoundation.Build.Client.dll
      2. Microsoft.TeamFoundation.VersionControl.Client.dll
      3. Microsoft.TeamFoundation.WorkItemTracking.Client.dll
    2. From C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies
      1. Microsoft.TeamFoundation.Build.Workflow.dll
      2. Microsoft.TeamFoundation.TestImpact.BuildIntegration.dll
    3. From C:\Windows\assembly\GAC_MSIL\Microsoft.TeamFoundation.TestImpact.Client\10.0.0.0__b03f5f7f11d50a3a
      1. Microsoft.TeamFoundation.TestImpact.Client.dll
    4. System.Activities
    5. System.Drawing
    6. System.ServiceModel
    7. System.ServiceModel.Activities
    8. System.Xaml
  5. Create a copy of the DefaultTemplate, call it CustomTemplate.xaml and put it in the folder where the Template project is located. Add the file to the project, and set the build action to XamlAppDef. If you don't see the XamlAppDef option, then add an activity to the Template project to add the correct references and then delete it again.
  6. Add to the BuildTasks project two folders called “Activities” and “Library”

    image
  7. Right click on the Activities and choose Add –> New Item. Choose from the dialog to only show the Workflow templates. And choose the Code Activity. Give it the name DoExcitingThings, and close the dialog with OK

    image
  8. In the code we see some interesting things. As we have seen in earlier posts in this series the build heavily relies on activities (such as this code activity) and you can configure activities with Arguments which can be set with the properties window. In the code you decorate every property you want to see in the properties window with the InArgument (or InOutArgument). When you want to get the value of this property, you must use the context to get the value. The property itself won’t hold the value!

    image
  9. I have modified the class so we can see the purpose and usage of the different argument types

    image
  10. We also have to indicate that our activity is used by the Build Controller and the Build Agents. To do this, add a using to the Microsoft.TeamFoundation.Build.Client and decorate the class with the following statement: [BuildActivity(HostEnvironmentOption.All)] 

    If you forget to specify this argument you encounter the error

    "TF21509:An error occured while initializing a build definition \CustomBuildTasks\BuildName:Cannot create
    unknown type '{clr-namepace:NamespaceName,asembly=AssemblyName}Activityname'."

    image
  11. Build the solution
  12. Open the CustomTemplate.xaml file and open the toolbox. In the toolbox we see our new DoExcitingThings activity added.

    image
  13. Drag ‘n drop this activity after the “Get the Build” activity.

    image
  14. When you open the properties window you see the three arguments we have added to our exciting activity.

    image
  15. Lets put in a textual value in all the three arguments

    image
  16. There are errors for the two arguments that have an output value, because it needs to store the value somewhere. So to solve this, you must create a variable for the correct scope (see part 2) and use the variable as value for the argument. You can either set the value for the variable in the variable window itself

     image

    Or you can use the Assign activity which you can find in the Primitives tab

     image
  17. Finally add a WriteBuildMessage to show the values of the arguments after the DoExcitingThings activity.
  18. Save the changes and check-in your CustomTemplate.xaml.
  19. Now execute a build based on the CustomTemplate. The build will fail unfortunately with the following error message

    image
  20. The build controller was unable to load our exciting Code Activity, which is obvious. It is pretty simple to solve this. Open the dialog to manage the build controllers. You can find it when you right click the Builds node for the team project in the team explorer

    image
  21. This will open the following dialog

    image
  22. Select the Controller and open the Properties

    image
  23. You see there a box to specify the path for custom assemblies. This means that you need to have one common location where you store all the assemblies that hold customizations (or just use one assembly that holds all the customizations). Since the assembly is not added by default to source control, you need to add the assembly first to Version Control and then specify that path in here.

    image
  24. Be aware that when you add a file to Source Control that it is marked read-only. So do not use the bin or obj folder! You might want to add some logic to the Post-build event in the C# project to automatically create a copy of the assembly and automatically check it in to Version Control.

    You can use for example the following Post-build event:

    "$(DevEnvDir)\TF.exe" checkout "$/CustomBuildTasks/BuildProcessTemplates/CustomActivities/$(TargetFileName)"
    xcopy /y "$(TargetPath)" "$(SolutionDir)..\..\BuildProcessTemplates\CustomActivities"
    "$(DevEnvDir)\TF.exe" checkin "$/CustomBuildTasks/BuildProcessTemplates/CustomActivities/$(TargetFileName)"
  25. When you now run the build, you will get the following result in the build log

     image

 

You can download the full solution at BuildProcess.zip. It will include the sources of every part and will continue to evolve.

Tags: ,

Team Build | VSTS 2010

Customize Team Build 2010 – Part 3: Use more complex arguments

by Ewald Hofman 28. April 2010 02:36

In the series the following parts have been published

  1. Part 1: Introduction
  2. Part 2: Add arguments and variables
  3. Part 3: Use more complex arguments
  4. Part 4: Create your own activity
  5. Part 5: Increase AssemblyVersion
  6. Part 6: Use custom type for an argument
  7. Part 7: How is the custom assembly found
  8. Part 8: Send information to the build log
  9. Part 9: Impersonate activities (run under other credentials)
  10. Part 10: Include Version Number in the Build Number
  11. Part 11: Speed up opening my build process template
  12. Part 12: How to debug my custom activities
  13. Part 13: Get control over the Build Output
  14. Part 14: Execute a PowerShell script
  15. Part 15: Fail a build based on the exit code of a console application
  16. Part 16: Specify the relative reference path


 

In this post I will show you how you can add more complex arguments to hold for example a list of strings or a Custom class.

In Part 2, I have described how you can add new arguments to your build workflow. We are now going to add a copy files activity. I want that after the compilation of the solution, my files are copied to a location. So I need to specify the list of files to copy and the target location where the files should be copied to. So I need to add 2 arguments:

  • Destination path
  • Source files

For the destination path, we can use the plain String type (which is the default), but for the list of files we need an array of strings. To select that, click on the string which will open a dropdown with the option to select the type of the argument.

image

Choose the Array of [T] from the list, which will open up a new dialog

image

Change the value Int32 to String and confirm with OK. The type of the argument SourceFiles is System.String[] now. Don’t forget to use the Metadata option to decorate the arguments to show them nicely in the Properties Window.

image

To use the new arguments now, locate in the workflow the place where the projects are actually compiled

image

After the “Run MSBuild for Project” we will add the logic to copy the files that the user have configured to copy. Open the toolbox and go to the Control Flow tab.

image

Drag ‘n drop the “ForEach<T>” activity on the white rectangle after the “Run MSBuild for Project” activity.

image

Open the properties window to change the properties of the ForEach activity. Change the following properties

Property Value
TypeArgument String
Values SourceFiles

 

image

In the Body, my best practice is to first drop a Sequence activity so you are always able to add new activities afterwards. In the sequence, add the activity InvokeProcess from the tab “Team Foundation Build Activities”. Select the InvokeProcess activity, and open the Properties Window. Change the following properties

Property Value
FileName “xcopy”
Arguments String.Format("""{0}\{1}"" ""{2}""", BinariesDirectory, item, Destination)

Save the workflow and check in the changes to source control.

Now you can edit your build definition. When you choose the build template you just modified, you will see the properties you just added. When you select the SourceFiles property, you will get the button with the ellipsis (…)

image

When you click on the button you will get a new dialog where you can enter the items in the string collection

image

We enter now the a file that we want to copy from the Binaries folder to c:\temp, which is in my case ConsoleApp.exe and ConsoleApp.pdb. When you look in the build log, you see that it has copied every file I have specified

image


 

You can download the full solution at BuildProcess.zip. It will include the sources of every part and will continue to evolve.

Tags:

Team Build | VSTS 2010

Customize Team Build 2010 – Part 2: Add arguments and variables

by Ewald Hofman 27. April 2010 04:47

In the series the following parts have been published

  1. Part 1: Introduction
  2. Part 2: Add arguments and variables
  3. Part 3: Use more complex arguments
  4. Part 4: Create your own activity
  5. Part 5: Increase AssemblyVersion
  6. Part 6: Use custom type for an argument
  7. Part 7: How is the custom assembly found
  8. Part 8: Send information to the build log
  9. Part 9: Impersonate activities (run under other credentials)
  10. Part 10: Include Version Number in the Build Number
  11. Part 11: Speed up opening my build process template
  12. Part 12: How to debug my custom activities
  13. Part 13: Get control over the Build Output
  14. Part 14: Execute a PowerShell script
  15. Part 15: Fail a build based on the exit code of a console application
  16. Part 16: Specify the relative reference path

 

In this post I am going to show you how you can add new arguments and variables in the build template. First, the difference between a variable and an argument is the following, according to http://msdn.microsoft.com/en-us/library/dd489456.aspx.

Variables are storage locations for data. Variables are declared as part of the definition of a workflow. Variables take on values at runtime and these values are stored as part of the state of a workflow instance. A variable definition specifies the type of the variable and optionally, the name.

Activity authors use arguments to define the way data flows into and out of an activity

In this post I will add a WriteBuildMessage activity to the default build process template that will show the message “Hello ?” where the ? will be the value of an argument, and the message will be stored in a variable.

  1. First open Visual Studio 2010 and go in Source Control to the folder BuildProcessTemplates of the team project you want to modify
  2. Double click the DefaultTemplate.xaml file to open up the workflow. This might take a while.
  3. A similar window should pop up now

    image
  4. In the bottom of the screen you see the Variables, Arguments and imports

    image
  5. Click on the Arguements, which will open up the list of arguments that exist on the current build process template.

    image
  6. Go to the end of the list, and click on the cell that shows Create Argument.

    image
  7. Change the argument1 name into TestMessage and accept the rest of the values

    image
  8. There is an interesting feature to add metadata to your arguments to tell Visual Studio how the user will see the argument when (s)he creates a new build definition. To do that, click on the button with ellipses (…) on the Metadata argument

    image
  9. This will open the Process Parameter Metadata Editor.

    image 
  10. Click on the Add button and add the TestMessage argument you just added.

    image 
  11. Press OK to accept the changes.
  12. Now click on the Variables to open up the variables. You will see an empty list, because a variable is scoped to an activity.

    image
  13. So click on the top activity called Sequence

    image  
  14. This will show the variable BuildDetail, which will be available during the complete lifetime of the build workflow and is set during the “Get the Build” activity.
  15. Now add a new variable called “MyTestMessage” by clicking on the Create Variable cell.

    image
  16. Now click on the Default cell for the MyTestMessage. When you start typing, you will see that it uses VB.Net as the language and that it supports intellisense.
  17. Type in "Hello " + TestMessage

    image
  18. Now open the toolbox, which might take a while, and search for the WriteBuildMessage activity in the “Team Foundation Build Activities” tab

    image
  19. Now drag ‘n drop the WriteBuildMessage to the workflow, just under the Get the Build

     image
  20. When you select the activity and open the properties window, you can set the properties of the activity.

    image  
  21. Now set the Message property to the value of the variable, so set it to MyTestMessage. Also change the DisplayName to “Say hello” and the importance to High

    image
  22. Now save the build process template and it is time to execute a build against the new template to see the results of your kicking ass template. First edit the build definition and click on the Process step. You will see that the new argument is now available to you. Set the value to anything you like. I use “world”

    image
  23. Save the build definition and queue it. While the build executes, you will see our exciting message

    image 

 


 

You can download the full solution at BuildProcess.zip. It will include the sources of every part and will continue to evolve.

Tags:

Team Build | VSTS 2010

Customize Team Build 2010 – Part 1: Introduction

by Ewald Hofman 20. April 2010 05:49

In the series the following parts have been published

  1. Part 1: Introduction
  2. Part 2: Add arguments and variables
  3. Part 3: Use more complex arguments
  4. Part 4: Create your own activity
  5. Part 5: Increase AssemblyVersion
  6. Part 6: Use custom type for an argument
  7. Part 7: How is the custom assembly found
  8. Part 8: Send information to the build log
  9. Part 9: Impersonate activities (run under other credentials)
  10. Part 10: Include Version Number in the Build Number
  11. Part 11: Speed up opening my build process template
  12. Part 12: How to debug my custom activities
  13. Part 13: Get control over the Build Output
  14. Part 14: Execute a PowerShell script
  15. Part 15: Fail a build based on the exit code of a console application
  16. Part 16: Specify the relative reference path

Who created a new build definition in TFS 2008 knows that Team Build 2008 heavily relies on MSBuild. The workflow that is executed during the build is defined in a custom scripting language in XML. The language is powerful, but not intuitive. It is hard to understand what is going on exactly, especially for novice users.

In TFS 2010 the build relies on Windows Workflow 4.0. With Workflow you can create a workflow based on activities. The advantages of this approach is that Windows Workflow is very intuitive and it supports parallel execution. Microsoft brings a lot of activities out of the box, but if required you can add your own activities too. This series of blog posts tells you how you can modify the Build Process Template to your own needs. Before starting to build your own customized build process template, it is good to first know how Team Build 2010 works.

Build Controller and Build Agent

When you queue a build in TFS 2008 you choose one of the available Build Agents to execute the build. In TFS 2010 there is a new component introduced, called the Build Controller, to initialize the build. When you queue a build, you choose the Build Controller which starts processing the build. The Build Controller initializes the build and chooses an available Build Agent. The Build Controller persists the workflow and hands it over to the Build Agent, which will continue executing the build and do the heavy lifting. For a deep insight in the overview see Understanding a Team Foundation Build System.

Workflow

Build Process Template

In TFS 2008 the build was executed based on a MSBuild script. This script imports the %ProgramFiles%\MSBuild\Microsoft\VisualStudio\TeamBuild\Microsoft.TeamFoundation.Build.targets file. This file contains all the logic to execute the actual build. In the TFSBuild.proj file you override targets and properties to customize the build to your needs. All target files you import (your ‘templates’) in the TFSBuild.proj must exist on the build server. It is not possible in TFS 2008 to store it in Source Control so the build automatically picks up the latest target file. If you have a build farm of multiple build servers, you needed to sync the template target file over all the build servers.

In TFS 2010 you also have a template, which is called the Build Process Template, but it is defined in Windows Workflow. This template is stored in Source Control, so you don’t need to deploy it to every build server anymore. The Build Controller will just use the version that is stored in Source Control.

You configure the build now by choosing a Build Process Template and set the properties that are defined in the template.

TimeTravelling003

In my opinion, Microsoft has made a giant leap to make the build much easier to configure.


 

You can download the full solution at BuildProcess.zip. It will include the sources of every part and will continue to evolve.

Tags:

Team Build | VSTS 2010

Powered by BlogEngine.NET 1.6.1.0
Theme by Mads Kristensen


ClusterMap

Statistics

Statistics created at 09 Sep 2009

121 posts
493 comments
328 raters
1951396 visit (1042 per day)
11 users online

Recent comments

Comment RSS