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

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

Unable to start the build controller

by Ewald Hofman 29. August 2010 05:22

I had an issue with my build controller that it would start. Finally I was able to resolve the issue.

First the context. I wanted to start the build under a Build Service account, so I created a new user in AD. Then I went to the TFS Administration Console and clicked on the Build Configuration. In there stop the build service and click on properties. It opens the properties for the build service.

image

Specify the credentials of the build service and click on Start.

Now my Build Controller says it is Initializing (and keeps in this state)

image

Click on the Properties and when you click on the Test Connection you get an error message

image

The message with To ‘http://<address>:9191/Build/v3.0/Services/Controller/1’  cannot be processed at the receiver, due to an AddressFilter mismatch at the EndpointDispatcher. Check that the sender and receiver’s EndpointAddresses agree.

When I change the Credentials of the Build Service to “NT AUTHORITY\NetworkService” it works again, so it has something to do with the security and/or authorization. When investigating the event log, I found the following entry.

Failed to add the build service account 'TFS\tfsbuild' to Windows Group TFS_BUILD_SERVICE_WPG. Return code: 2221.

I don’t know the root cause of this warning, but with the following steps you can solve the issue:

  1. Add the user account you want to run the build service with to the TFS_BUILD_SERVICE_WPG group
  2. Open the TFS Administration Console
  3. Go to the Build Configuration node.
  4. Open the properties of the Windows Service in the TFS Administration Console
  5. Stop the service
  6. Change the Credentials to “NT AUTHORITY\NetworkService”
  7. Click on Start
  8. Open the properties again
  9. Stop the service
  10. Set the Credentials to the build service account
  11. Click on Start
  12. Click on the properties of the build controller
  13. Click on Test Connection

The message should be now something like

image

Tags:

Team Build | VS 2010

Powered by BlogEngine.NET 1.6.1.0
Theme by Mads Kristensen


ClusterMap

Statistics

Statistics created at 09 Sep 2009

121 posts
492 comments
326 raters
1914014 visit (1041 per day)
12 users online

Recent comments

Comment RSS