Programmatically use a server as the Build Server for multiple Project Collections

by Ewald Hofman 25. November 2010 05:41

Important: With this post you create an unsupported scenario by Microsoft. It will break your support for this server with Microsoft. So handle with care.

I am the administrator an a TFS environment with a lot of Project Collections. In the supported configuration of Microsoft 2010 you need one Build Controller per Project Collection, and it is not supported to have multiple Build Controllers installed. Jim Lamb created a post how you can modify your system to change this behaviour. But since I have so many Project Collections, I automated this with the API of TFS.

When you install a new build server via the UI, you do the following steps

  1. Register the build service (with this you hook the windows server into the build server environment)
  2. Add a new build controller
  3. Add a new build agent

So in pseudo code, the code would look like

foreach (projectCollection in GetAllProjectCollections)
{
      CreateNewWindowsService();
      RegisterService();
      AddNewController();
      AddNewAgent();
}

The following code fragements show you the most important parts of the method implementations. Attached is the full project.

CreateNewWindowsService

We create a new windows service with the SC command via the Diagnostics.Process class:

            var pi = new ProcessStartInfo("sc.exe")
                         {
                             Arguments =
                                
string
.Format(
                                    
"create \"{0}\" start= auto binpath= \"C:\\Program Files\\Microsoft Team Foundation Server 2010\\Tools\\TfsBuildServiceHost.exe
             /NamedInstance:{0}\" DisplayName= \"Visual Studio Team Foundation Build Service Host ({1})\""
,
                                     serviceHostName, tpcName)
                         };
           
Process
.Start(pi);

            pi.Arguments =
string.Format("failure {0} reset= 86400 actions= restart/60000"
, serviceHostName);
           
Process.Start(pi);

RegisterService

The trick in this method is that we set the NamedInstance static property. This property is Internal, so we need to set it through reflection. To get information on these you need nice Microsoft friends and the .Net reflectorSmile .

            // Indicate which build service host instance we are using
            typeof(BuildServiceHostUtilities).Assembly.GetType("Microsoft.TeamFoundation.Build.Config.BuildServiceHostProcess").InvokeMember("NamedInstance",
             System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.SetProperty | System.Reflection.BindingFlags.Static, null, null, new object[] { serviceName });

           
// Create the build service host
            serviceHost = buildServer.CreateBuildServiceHost(serviceName, endPoint);
            serviceHost.Save();

           
// Register the build service host
            BuildServiceHostUtilities
.Register(serviceHost, user, password);

AddNewController and AddNewAgent

Once you have the BuildServerHost, the rest is pretty straightforward. There are methods on the BuildServerHost to modify the controllers and the agents

                controller = serviceHost.CreateBuildController(controllerName);
                agent = controller.ServiceHost.CreateBuildAgent(agentName, buildDirectory, controller);
                controller.AddBuildAgent(agent);
You have now seen the highlights of the application. If you need it and want to have sample information when you work in this area, download the app
TFS2010_RegisterBuildServerToTPCs

Tags:

TFS SDK | VSTS 2010 | Team Build

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

TF203071: Cannot branch anymore after the migration to TFS 2010

by Ewald Hofman 19. September 2010 23:37

After we have migrated our TFS 2008 servers to TFS 2010, some teams had trouble with creating their branches. They were sure that they were able to create the branches in TFS 2008. They received the following error message.

clip_image002

Diving deeper into the problem, I found out that on that path a Branch folder was created.

clip_image002[6]

A question to the product team gave the following hint:

We have introduced the concept of “branches” as first class entities in 2010. Since we didn’t have this concept in 2008, the upgrade tries to detect your branch roots by using a heuristic, it can go wrong in cases. In those cases you need to remove the incorrect branch roots using the method specified below and specify the correct branch root.

You can resolve the issue by converting the branch folder to a normal folder. You can find this command in the menu of Visual Studio: File -> Source Control -> Branching and Merging -> Convert to Folder

Tags:

VSTS 2010 | Version Control

Create custom work item control for TFS Web Access 2010 (TWA)

by Ewald Hofman 10. August 2010 05:06

For the customization of the work item controls for the client are many examples. There is even a codeplex project that hosts some examples. However if you want to provide a custom work item control for Web Access, it turns out that there is only little information. In this post I will describe what I did to create the custom Web Access control.

Thanks to Guneet Umra of Avanade and Serkan Inci of Microsoft to help me out on this.

For this example I will show you how you can create a textbox that has a blue background, but you can make it as fancy as you like.

  1. Open Visual Studio and create a new Class library called WebControl.
  2. Add the references to
    1. C:\Windows\assembly\GAC_MSIL\Microsoft.TeamFoundation.WebAccess.Controls\10.0.0.0__b03f5f7f11d50a3a\Microsoft.TeamFoundation.WebAccess.Controls.dll
    2. C:\Windows\assembly\GAC_MSIL\Microsoft.TeamFoundation.WebAccess.WorkItemTracking\10.0.0.0__b03f5f7f11d50a3a\Microsoft.TeamFoundation.WebAccess.WorkItemTracking.dll
    3. C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0\Microsoft.TeamFoundation.WorkItemTracking.Client.dll
    4. C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies\Microsoft.TeamFoundation.WorkItemTracking.Controls.dll

      Or you can add the following lines to your project file:

          <Reference Include="Microsoft.TeamFoundation.WorkItemTracking.Client, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
            <SpecificVersion>False</SpecificVersion>
            <Private>False</Private>
          </Reference>
          <Reference Include="Microsoft.TeamFoundation.WorkItemTracking.Controls, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
            <SpecificVersion>False</SpecificVersion>
            <Private>False</Private>
          </Reference>
          <Reference Include="Microsoft.TeamFoundation.WebAccess.WorkItemTracking, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
            <SpecificVersion>False</SpecificVersion>
          </Reference>
          <Reference Include="Microsoft.TeamFoundation.WebAccess.Controls, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
            <SpecificVersion>False</SpecificVersion>
          </Reference>

  3. Create a wicc file, named BlueTextbox.wicc (for more information the wicc file, see http://msdn.microsoft.com/en-us/library/bb286959.aspx)
  4. Set the Build Action (in the properties window) of this file to Content (so it is included in the setup project that will be created later)
  5. Add the following contents to the wicc file

    <?xml version="1.0" encoding="utf-8" ?>
    <CustomControl xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <Assembly>WebControl.dll</Assembly>
      <FullClassName>WebControl.BlueTextbox</FullClassName>
    </CustomControl>
  6. Rename the Class1.cs file to BlueTextbox.cs
  7. Paste the following contents to the file

    using System;
    using System.Drawing;
    using Microsoft.TeamFoundation.WebAccess.WorkItemTracking.Controls;
    using System.Web.UI;
    using System.Web.UI.WebControls;

    namespace WebControl
    {
        public class BlueTextbox : BaseWorkItemWebControl
        {
            public BlueTextbox()
                : base(HtmlTextWriterTag.Div)
            {

            }

            /// <summary>
            ///  The textbox with the blue background
            /// </summary>
            public TextBox TextBox { get; set; }

            /// <summary>
            /// The value in the work item
            /// </summary>
            public string FieldValue
            {
                get
                {
                    // When it has a value, return that value
                    if (HasValidField && Field.Value != null)
                        return Field.Value.ToString();

                    // Else return the empty string
                    return string.Empty;
                }
                set
                {
                    // When the field is value and is editable
                    if (HasValidField && Field.FieldDefinition.IsEditable)
                        // And it is changed
                        if ((Field.Value != null || value != null)
                            && (Field.Value == null || Field.Value.ToString() != value))
                        {
                            // Set the value in the work item
                            base.OnBeforeUpdateDatasource(EventArgs.Empty);
                            Field.Value = value;
                            base.OnAfterUpdateDatasource(EventArgs.Empty);
                        }
                }
            }

            /// <summary>
            /// The value of the textbox
            /// </summary>
            public string Value
            {
                get
                {
                    EnsureInnerControls();

                    return TextBox.Text;
                }
                set
                {
                    EnsureInnerControls();

                    TextBox.Text = value;
                }
            }

            /// <summary>
            /// Build the control
            /// </summary>
            public override void InitializeControl()
            {
                base.InitializeControl();

                // Create the TextBox
                EnsureInnerControls();

                // Save the value when it is changed
                TextBox.TextChanged += delegate { FlushToDatasource(); };
            }

            /// <summary>
            /// Add the textbox
            /// </summary>
            public void EnsureInnerControls()
            {
                if (TextBox != null)
                    return;

                TextBox = new TextBox { BackColor = Color.Blue };

                base.Controls.Clear();
                base.Controls.Add(TextBox);
            }

            /// <summary>
            /// THe underlying data is changed. Change the contents of the TextBox accordingly
            /// </summary>
            public override void InvalidateDatasource()
            {
                base.InvalidateDatasource();

                // If the field is valid
                if (HasValidField)
                {
                    // And it has a value
                    if (Field.Value != null)
                    {
                        // change the contents of the TextBox
                        Value = Field.Value.ToString();
                    }
                    else
                    {
                        // else clear the value
                        Clear();
                    }
                }
                else
                {
                    // If the field is not valid, then also clear the contents of the TextBox
                    Clear();
                }

                // Ensure the control is shows correctly
                ResetStyles();
            }

            /// <summary>
            /// Ensure that the control is correctly shows (width + enabled)
            /// </summary>
            private void ResetStyles()
            {
                Width = Unit.Percentage(100);
                Enabled = !ControlReadOnly && !EditorReadOnly;
            }

            public override void FlushToDatasource()
            {
                base.FlushToDatasource();

                FieldValue = Value;
            }

        }
    }
  8. To distribute this control, the easiest way is to create a setup project. Since the location is different for x86 and x64 the easiest way is to create two setup projects.
  9. First create the x64 setup project: Add a new project of type Setup Project with the name WebControlSetup.x64 (you can find the project type in the Add New Project dialog under Other Project Types –> Setup and Deployment –> Visual Studio Installer)

    image
  10. Remove the User’s Desktop and the User’s Programs Menu folders
  11. Click on the project in the Solution Explorer and open the properties window. Change the TargetPlatform to x64
  12. Change the DefaultLocation of the Application Folder to [ProgramFiles64Folder]\Microsoft Team Foundation Server 2010\Application Tier\Web Access\Web\App_Data\CustomControls
  13. Right click on the right pane to add the Primary output of the WebControl project

    image 
  14. When you add the primary output also all the Microsoft.TeamFoundation dll’s are added. Those dll’s should not be installed however

    image
  15. You can remove those by opening up the Detected Dependencies, select those dll’s, right click to open the context menu and choose Exclude. You will see the dll’s will be removed from the File System window

    image
  16. Now also add the Content of the WebControl project
  17. Repeat these steps to create a x86 setup project, but now use the target folder “[ProgramFilesFolder]\Microsoft Team Foundation Server 2010\Application Tier\Web Access\Web\App_Data\CustomControls”
  18. You can now build the WebControl solution, and install the appropriate msi on the TFS server.
  19. Now change the work item type to make use of the new control. You can find information how to modify work item types at http://msdn.microsoft.com/en-us/library/ms243849.aspx
  20. When you change the FieldControl of the Title field in the FORMS section to BlueTextbox,

        <FORM>
          <Layout>
            <Group>
              <Column PercentWidth="80">
                <Control FieldName="System.Title" Type="BlueTextbox" Label="&amp;Title:" LabelPosition="Left" />
              </Column>
    you will see the following when you create a new task

    image
  21. There is a nice little feature in TFS to have two separate layouts for the Windows and the Web UI: You can add the attribute Target=”Windows” or Target=”Web” to the Layouts node to show two different layouts.

        <FORM>
          <Layout Target="WinForms">
            <Group>
              <Column PercentWidth="80">
                <Control Type="FieldControl" FieldName="System.Title" Label="&amp;Title:" LabelPosition="Left" />
              </Column>


          <Layout Target="Web">
            <Group>
              <Column PercentWidth="80">
                <Control Type="BlueTextbox" FieldName="System.Title" Label="&amp;Title:" LabelPosition="Left" />
              </Column>

Tags:

Work items | VSTS 2010 | TSWA

How to use WCF to subscribe to the TFS 2010 Event Service [rolling up hours]

by Ewald Hofman 2. August 2010 06:43

There is a lot of information on the web around the TFS Event Service, but that is mainly around ASMX and TFS 2008. I am using Visual Studio 2010, TFS 2010 and WCF. To be able to subscribe to the created event, the easiest is to have a local instance of TFS 2010 running on your machine.

The purpose of my WCF service will be to rollup the hours of the children into the hour fields (estimate, remaining work and completed work) of the (grand)parents. The result will be a framework on which you can build further as it is not smart enough yet to handle all the other link types (like bugs that are assigned to test cases etc.)

This article assumes that you have basic knowledge of WCF.

The steps that are involved into this exercise are:

  1. Create a new Visual Studio WCF Service Application
  2. Create the interface for the rollup Service
  3. Specify the web.config
  4. Subscribe the WCF servcie to the TFS WorkItemChanged event
  5. Write logic in the service to retrieve the changed work item
  6. Update the hours of the parent work item
  7. Deploy the web service to IIS
  8. Test and debug the service

Create a new Visual Studio WCF Service Application

Open Visual Studio 2010 and create a new project of the type WCF Service Application, which is called EventService. Cleanup the proposed situation by removing all methods in the IService1 and the Service1 files and the CompositeType. Then change the name of the files to RollupService and IRollupService (and check whether the name of the class and interface have changed too). We have now an empty WCF Service Application container in which we can add the logic.

Create the interface for the rollup Service

To be able to consume the event, we need to decorate the interface with the ServiceContract attribute and we need to add a new operation Notify that has two string arguments. In short your IRollupService will look like this:

using System.ServiceModel;

namespace EventService
{

    [ServiceContract(Namespace="http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03")]
    public interface IRollupService
    {

        [OperationContract(Action = http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03/Notify)]
        [XmlSerializerFormat(Style = OperationFormatStyle.Document)]
        void Notify(string eventXml, string tfsIdentityXml);

    }

}

Next implement the Notify method in the RollupService class as well.

namespace EventService
{
    public class RollupService : IRollupService
    {

        void IRollupService.Notify(string eventXml, string tfsIdentityXml)
        {
            // Add logic
        }

    }
}

 

Specify the web.config

In WCF the web.config is very important and it took me hours to find the correct contents of the config to finally hook up to the TFS 2010 system.

Here is the list of issues I had to solve:

Problem HTTP code 415: Cannot process the message because the content type 'application/soap+xml; charset=utf-8' was not the expected type 'text/xml; charset=utf-8'
Issue Because TFS 2010 is now using SOAP 1.2, you need to use wsHttpBinding.
Solution Change the basicHttpBinding to wsHttpBinding

Thanks to Mattias Sköldin his post  http://mskold.blogspot.com/2010/02/upgrading-tfs-event-subscriptions-to.html
   
Problem System.Web.Services.Protocols.SoapException: The message could not be processed. This is most likely because the action 'http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03/Notify' is incorrect or because the message contains an invalid or expired security context token or because there is a mismatch between bindings. The security context token would be invalid if the service aborted the channel due to inactivity. To prevent the service from aborting idle sessions prematurely increase the Receive timeout on the service endpoint's binding.
Issue You have to change the security of the binding to None
Solution Add a new bindig configuration (in the example see the EventServiceBinding) where you set the Security to None

Finally I was able to execute the notification with the following web.config

<?xml version="1.0"?>
<configuration>

  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="EventServiceBinding">
          <security mode="None" />
        </binding>
      </wsHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="EventServiceBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service behaviorConfiguration="EventServiceBehavior" name="EventService.RollupService">
        <endpoint address="" binding="wsHttpBinding" bindingConfiguration="EventServiceBinding"
          contract="EventService.IRollupService" />
      </service>
    </services>
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>

</configuration>

Publish the web service to IIS

In Visual Studio right click on the project in the solution explorer, and find the Publish command. When you start the command, you get a dialog to enter the information where you want to publish this WCF Service to.

To exclude any issues with the interference with other web application, I always tend to use a new web site for this (in this example I used port 1001). I use the following information.

image 

Subscribe the WCF servcie to the TFS WorkItemChanged event

In the folder "C:\Program Files\Microsoft Team Foundation Server 2010\Tools” you can find the application bisubscribe with which you can subscribe your events. To register the service to be executed on every change of a work item execute the following command.

"C:\Program Files\Microsoft Team Foundation Server 2010\Tools\bissubscribe" /eventType WorkItemChangedEvent /address http://localhost:1001/RollupService.svc /collection http://localhost:8080/tfs/DefaultCollection

Write logic in the service to retrieve the changed work item

When you build the project and attach to the correct w3wp process, you can debug what is actually send to your service. it turns out that TFS sends this information:

eventXml
<?xml version="1.0" encoding="utf-16"?>
<WorkItemChangedEvent xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <PortfolioProject>MyTeamProject</PortfolioProject>
  <ProjectNodeId>f0fedf0c-3c7f-47e1-b144-ba85fc9765ba</ProjectNodeId>
  <AreaPath>\MyTeamProject</AreaPath>
  <Title>MyTeamProject Work Item Changed: Task 109 - MyNewTitle</Title>
  <WorkItemTitle>k</WorkItemTitle>
  <Subscriber>[DefaultCollection]\Project Collection Service Accounts</Subscriber>
  <ChangerSid>S-1-5-21-1482476501-2139871995-682003330-85089</ChangerSid>
  <DisplayUrl>http://localhost:8080/tfs/web/wi.aspx?pcguid=64925f8d-7df7-4369-a922-6e44d69d781f&amp;id=109</DisplayUrl>
  <TimeZone>W. Europe Daylight Time</TimeZone>
  <TimeZoneOffset>+02:00:00</TimeZoneOffset>
  <ChangeType>Change</ChangeType>
  <CoreFields>
    <IntegerFields>
      <Field>
        <Name>ID</Name>
        <ReferenceName>System.Id</ReferenceName>
        <OldValue>109</OldValue>
        <NewValue>109</NewValue>
      </Field>
      <Field>
        <Name>Rev</Name>
        <ReferenceName>System.Rev</ReferenceName>
        <OldValue>12</OldValue>
        <NewValue>13</NewValue>
      </Field>
      <Field>
        <Name>Area ID</Name>
        <ReferenceName>System.AreaId</ReferenceName>
        <OldValue>203</OldValue>
        <NewValue>203</NewValue>
      </Field>
    </IntegerFields>
    <StringFields>
      <Field>
        <Name>Work Item Type</Name>
        <ReferenceName>System.WorkItemType</ReferenceName>
        <OldValue>Task</OldValue>
        <NewValue>Task</NewValue>
      </Field>
      <Field>
        <Name>Title</Name>
        <ReferenceName>System.Title</ReferenceName>
        <OldValue>MyOldTitle</OldValue>
        <NewValue>MyNewTitle</NewValue>
      </Field>
      <Field>
        <Name>Area Path</Name>
        <ReferenceName>System.AreaPath</ReferenceName>
        <OldValue>\MyTeamProject</OldValue>
        <NewValue>\MyTeamProject</NewValue>
      </Field>
      <Field>
        <Name>State</Name>
        <ReferenceName>System.State</ReferenceName>
        <OldValue>Proposed</OldValue>
        <NewValue>Proposed</NewValue>
      </Field>
      <Field>
        <Name>Reason</Name>
        <ReferenceName>System.Reason</ReferenceName>
        <OldValue>New</OldValue>
        <NewValue>New</NewValue>
      </Field>
      <Field>
        <Name>Assigned To</Name>
        <ReferenceName>System.AssignedTo</ReferenceName>
        <OldValue>Ewald Hofman</OldValue>
        <NewValue>Ewald Hofman</NewValue>
      </Field>
      <Field>
        <Name>Changed By</Name>
        <ReferenceName>System.ChangedBy</ReferenceName>
        <OldValue>Ewald Hofman</OldValue>
        <NewValue>Ewald Hofman</NewValue>
      </Field>
      <Field>
        <Name>Created By</Name>
        <ReferenceName>System.CreatedBy</ReferenceName>
        <OldValue>Ewald Hofman</OldValue>
        <NewValue>Ewald Hofman</NewValue>
      </Field>
      <Field>
        <Name>Changed Date</Name>
        <ReferenceName>System.ChangedDate</ReferenceName>
        <OldValue>30-7-2010 13:39:12</OldValue>
        <NewValue>30-7-2010 13:56:49</NewValue>
      </Field>
      <Field>
        <Name>Created Date</Name>
        <ReferenceName>System.CreatedDate</ReferenceName>
        <OldValue>30-7-2010 11:42:24</OldValue>
        <NewValue>30-7-2010 11:42:24</NewValue>
      </Field>
      <Field>
        <Name>Authorized As</Name>
        <ReferenceName>System.AuthorizedAs</ReferenceName>
        <OldValue>Ewald Hofman</OldValue>
        <NewValue>Ewald Hofman</NewValue>
      </Field>
      <Field>
        <Name>Iteration Path</Name>
        <ReferenceName>System.IterationPath</ReferenceName>
        <OldValue>\MyTeamProject</OldValue>
        <NewValue>\MyTeamProject</NewValue>
      </Field>
    </StringFields>
  </CoreFields>
  <ChangedFields>
    <IntegerFields />
    <StringFields>
      <Field>
        <Name>Title</Name>
        <ReferenceName>System.Title</ReferenceName>
        <OldValue>MyOldTitle</OldValue>
        <NewValue>MyNewTitle</NewValue>
      </Field>
      <Field>
        <Name>Original Estimate</Name>
        <ReferenceName>Microsoft.VSTS.Scheduling.OriginalEstimate</ReferenceName>
        <OldValue>3</OldValue>
        <NewValue>6</NewValue>
      </Field>
      <Field>
        <Name>Remaining Work</Name>
        <ReferenceName>Microsoft.VSTS.Scheduling.RemainingWork</ReferenceName>
        <OldValue>3</OldValue>
        <NewValue>1</NewValue>
      </Field>
      <Field>
        <Name>Completed Work</Name>
        <ReferenceName>Microsoft.VSTS.Scheduling.CompletedWork</ReferenceName>
        <OldValue>0</OldValue>
        <NewValue>3</NewValue>
      </Field>
    </StringFields>
  </ChangedFields>
</WorkItemChangedEvent>
tfsIdentityXml
<TeamFoundationServer url="http://localhost:8080/tfs/DefaultCollection/Services/v3.0/LocationService.asmx" />

Based on the information that is in those arguments it is possible to see the changes of the effort fields (estimate, remaining and completed) from the current work item. You can use a simple xQuery to get the required information. To be able to get the work item, we need:

  1. the url to the TFS Server, which we can find in the tfsIdentityXml
  2. the parent work item, which we can find via the links of the changed work item. The eventXml has the id of the changed work item
  3. the current and previous values of the effort fields, which are in the eventXml

To be able to read from the eventXml, I have created a seperate class to have a seperation of concerns called EventXmlHelper. There is one method in there that reads the EventXml and has some arguments to define what you want to read

    using System;
    using System.Xml;
    public class EventXmlHelper
    {
        public enum FieldSection
        {
            CoreFields,
            ChangedFields
        }

        public enum FieldType
        {
            IntegerField,
            StringField
        }

        public enum ValueType
        {
            NewValue,
            OldValue
        }

        public static T GetWorkItemValue<T>(string eventXml, FieldSection section, FieldType type, ValueType valueType, string refName)
        {
            var path = string.Format("/WorkItemChangedEvent/{0}/{1}s/Field[ReferenceName='{3}']/{2}", section, type, valueType, refName);

            var doc = new XmlDocument();
            doc.LoadXml(eventXml);

            var node = doc.SelectSingleNode(path);

            object text;
            if (node == null)
            {
                if (typeof(T) == typeof(int))
                {
                    text = 0;
                }
                else if (typeof(T) == typeof(string))
                    {
                        text =  "";
                    }
                else
                {
                    throw new NotImplementedException();
                }
            }
            else
            {
                text = node.InnerText;
            }

            return (T)Convert.ChangeType(text, typeof(T));
        }
    }

To be able to communicate with TFS, I also created a helper class. This class opens the connection to TFS and is able to open the parent work item.

    using System;
    using System.Linq;
    using System.Xml;
    using Microsoft.TeamFoundation.Client;
    using Microsoft.TeamFoundation.WorkItemTracking.Client;
    public class TfsHelper
    {
        public TfsTeamProjectCollection TfsInstance { get; set; }

        public TfsHelper(string tfsIdentityXml)
        {
            //Get the url from the tfsIdentity xml.
            var doc = new XmlDocument();
            doc.LoadXml(tfsIdentityXml);

            if (doc.FirstChild == null) throw new Exception("url not found");
            var url = doc.FirstChild.Attributes["url"].Value;

            //the url is in the form of http://localhost:8080/tfs/DefaultCollection/Services/v3.0/LocationService.asmx
            //strip the /Services/v3.0/LocationService.asmx part
            url = url.Substring(0, url.Length - ("/Services/v3.0/LocationService.asmx").Length);

            // Instantiate a reference to the TFS Project Collection
            TfsInstance = new TfsTeamProjectCollection(new Uri(url));
        }

        /// <summary>
        /// Returns the work item with the specified id
        /// </summary>
        public WorkItem OpenWorkItem(int id)
        {
            var store = (WorkItemStore)TfsInstance.GetService(typeof(WorkItemStore));
            return store.GetWorkItem(id);
        }

        /// <summary>
        /// Returns the parent work item of the work item with the specified id. When it has no parent, null is returned.
        /// </summary>
        public WorkItem OpenParentWorkItem(int id)
        {
            // Get the work item with the specified id
            var workItem = OpenWorkItem(id);

            // Get the link to the parent work item through the work item links
            var q = from l in workItem.WorkItemLinks.OfType<WorkItemLink>()
                    where l.LinkTypeEnd.LinkType.LinkTopology == WorkItemLinkType.Topology.Tree
                    && !l.LinkTypeEnd.IsForwardLink
                    select l.TargetId;

            // If there is a link with a parent work item
            if (q.Count() > 0)
            {
                // Return that one
                return OpenWorkItem(q.ElementAt(0));
            }
            else
            {
                return null;
            }

        }

    }

Update the hours of the parent work item

With these helper files, rolling up the hours is a piece of cake. However you still have to harden your code to deal with errors.

        void IRollupService.Notify(string eventXml, string tfsIdentityXml)
        {
            const string refNameEstimate = "Microsoft.VSTS.Scheduling.OriginalEstimate";
            const string refNameRemaining = "Microsoft.VSTS.Scheduling.RemainingWork";
            const string refNameCompleted = "Microsoft.VSTS.Scheduling.CompletedWork";

            // Extract the required information out of the eventXml
            var workItemId = EventXmlHelper.GetWorkItemValue<int>(eventXml, EventXmlHelper.FieldSection.CoreFields,
                                                                  EventXmlHelper.FieldType.IntegerField,
                                                                  EventXmlHelper.ValueType.NewValue, "System.Id");
            var oldOriginalEstimate = EventXmlHelper.GetWorkItemValue<int>(eventXml,
                                                                           EventXmlHelper.FieldSection.ChangedFields,
                                                                           EventXmlHelper.FieldType.StringField,
                                                                           EventXmlHelper.ValueType.OldValue,
                                                                           refNameEstimate);
            var newOriginalEstimate = EventXmlHelper.GetWorkItemValue<int>(eventXml,
                                                                           EventXmlHelper.FieldSection.ChangedFields,
                                                                           EventXmlHelper.FieldType.StringField,
                                                                           EventXmlHelper.ValueType.NewValue,
                                                                           refNameEstimate);
            var oldRemainingWork = EventXmlHelper.GetWorkItemValue<int>(eventXml,
                                                                        EventXmlHelper.FieldSection.ChangedFields,
                                                                        EventXmlHelper.FieldType.StringField,
                                                                        EventXmlHelper.ValueType.OldValue,
                                                                        refNameRemaining);
            var newRemainingWork = EventXmlHelper.GetWorkItemValue<int>(eventXml,
                                                                        EventXmlHelper.FieldSection.ChangedFields,
                                                                        EventXmlHelper.FieldType.StringField,
                                                                        EventXmlHelper.ValueType.NewValue,
                                                                        refNameRemaining);
            var oldCompletedWork = EventXmlHelper.GetWorkItemValue<int>(eventXml,
                                                                        EventXmlHelper.FieldSection.ChangedFields,
                                                                        EventXmlHelper.FieldType.StringField,
                                                                        EventXmlHelper.ValueType.OldValue,
                                                                        refNameCompleted);
            var newCompletedWork = EventXmlHelper.GetWorkItemValue<int>(eventXml,
                                                                        EventXmlHelper.FieldSection.ChangedFields,
                                                                        EventXmlHelper.FieldType.StringField,
                                                                        EventXmlHelper.ValueType.NewValue,
                                                                        refNameCompleted);

            // Create a new TFS helper
            var tfsHelper = new TfsHelper(tfsIdentityXml);

            // Get the parent work item
            var parentWorkItem = tfsHelper.OpenParentWorkItem(workItemId);

            // If there is one
            if (parentWorkItem != null)
            {
                // Update the effort fields with the difference between the old and the new value
                parentWorkItem.Fields[refNameEstimate].Value =
                    Convert.ToInt32(parentWorkItem.Fields[refNameEstimate].Value) + newOriginalEstimate -
                    oldOriginalEstimate;
                parentWorkItem.Fields[refNameRemaining].Value =
                    Convert.ToInt32(parentWorkItem.Fields[refNameRemaining].Value) + newRemainingWork - oldRemainingWork;
                parentWorkItem.Fields[refNameCompleted].Value =
                    Convert.ToInt32(parentWorkItem.Fields[refNameCompleted].Value) + newCompletedWork - oldCompletedWork;

                parentWorkItem.Save();
            }
        }

Test and debug the service

To test your service, you can create two task work items which have a parent/child relation. Now attach Visual Studio to the w3wp process that hosts the web service (Tools –> Attach to Process) and set a breakpoint in your code. Then modify the effort fields in the child work item and wait. It can take 1 to 2 minutes before the event is processed and your breakpoint is hit. See debugging tip #2 how to change this.

Tips for debugging:

#1: When the service is not working as you would expect, you can follow the post of Grant Holiday how to see the errors the event system is having http://blogs.msdn.com/b/granth/archive/2009/10/28/tfs2010-diagnosing-email-and-soap-subscription-failures.aspx

#2: The Job Agent Service, which is the agent that calls our service, is configured by default to run every 2 minutes. You can change the setting by following the instructions at http://blogs.msdn.com/b/chrisid/archive/2010/03/05/faster-delivery-of-notifications.aspx

Tags:

TFS SDK | VSTS 2010 | Work items

Change the Bug Status report to reflect additional states to the Bug

by Ewald Hofman 16. July 2010 13:42

The bug work item has 3 (Agile: Active, Resolved, Closed) or 4 states (CMMI: Proposed, Active, Resolved, Closed). Those states are used also in the reporting. When you use additional states you will see that the colors are not in the trend that the default states have. Also the order of the states might not be in the correct order. The last requirement I have in this case (because this bug work item has 10+ states) is to aggregate some states into categories to see less states.

This post shows you have you can achieve these requirements.

image

In order to support the new states in the report, you have to change the rdl.

  1. Go to http://msdn.microsoft.com/en-us/library/ff730838.aspx to find out how you can start up a new Visual Studio project to modify the report
  2. Now download the Bug Status (you can find the instructions how to do that in Reflect the rename of a state for the Bug Work Item)
  3. And add the Bug Status report to the project
  4. Open the report by double clicking it. You will see something similar like this

    image
  5. First we are going to solve the coloring
    1. Now right click on the orange / blue area to open the context menu for the data series

      image
    2. Choose for the Series Properties
    3. And go to the Fill section

      image
    4. Now click on the fx button to open the expression for the color

      image
    5. You see the list of states and its colors. The color is specified as (Transparancy, Red, Blue, Green). The transparancy of 80 means (because it is a Hex value) 50%. Play around with colors to get the result you want.
  6. Now we also need to change the sorting of the states
    1. To do that click on the data series again and scroll completely to the right

      image
    2. You see that there is a window shown with the Chart Data.
    3. Click on the triangle in the Series Groups

      image
    4. And choose the “Series Group Properties…”
    5. Go to the Sorting section

      image
    6. Click on the fx button to change the sort by expression

      image
    7. Again you can modify this expression to get the correct sorting. The !1, !2 and !3 are just textual values to ensure that they are alphabetically sorted before Active, Assigned and so on.
  7. The third modification you might want to make is to aggregate a few states. If you want to do that, you should change the value for the Series Groups from System_State to an expression.

Tags:

Reporting | VSTS 2010

Reflect the rename of a state for the Bug Work Item

by Ewald Hofman 16. July 2010 13:20

The bug work item has 3 (Agile: Active, Resolved, Closed) or 4 states (CMMI: Proposed, Active, Resolved, Closed). Those states are used also in the reporting. When you rename the state, it is not automatically picked up by the reporting. Luckily Microsoft has foreseen that not everybody uses the same name for states and introduced a parameter.

To reflect the new state name in the report (in this post, I assume that you have renamed the state Active to Assigned), you have to change the value of the parameter. You can do that by following these steps (I use SQL Server 2008 R2):

  1. Go to the report site for the team project (you can find that by right clicking the Reports node in the team explorer)

    image
  2. It will lead you to the following site

    image
  3. Click on the Bugs. It will open all the reports that are in the Bugs folder
  4. Now hover over the Bug Status report and click on the triangle that pops up. This will open a menu of actions you can perform on the report

    image
  5. Choose the Manage action, which leads to the following page

    image
  6. Click on the Parameters section (on the left side). You will see the parameters that are specified in the report including there default values

    image 
  7. In the list is also the parameter ActiveName, which defines the name of the state Active.
  8. Because we changed the Active state to Assigned, you have to change the Default Value to “Assigned”.
  9. Now scroll down until you see at the bottom the Apply button (don’t forget that one!!)
  10. The report will now pick up the new state. However there is a little bug in the report. There is one location in which the “Active” state is still hard coded.
  11. Go back to the action menu that you saw in step 4 and now choose the Download action.
  12. Download it to your local harddrive.
  13. Open the rdl file in notepad.
  14. Replace all occurrences of “Active” (including quotes) with the value Parameters!ActiveName.Value
  15. Save the changes and go to the page you see in step 5
  16. Now choose the Replace action and choose the local file

    image
  17. And press OK.

Tags:

Reporting | VSTS 2010

The “Active bugs by Assignment” and “Resolved Bugs by Assignment” chart is not visible in the Bug Status report

by Ewald Hofman 16. July 2010 12:54

I have a TFS 2010 demo box on Windows Server 2008 R2 and SQL Server 2008.

While I was busy in a team project based on the default Agile or CMMI process template, I saw in the Bug Status report something strange. Although I had bugs assigned (of course it was a demo environment, because I never deliver bugs in real life :) ), the chart that should have been shown was not drawn.

clip_image002

So I went into the data warehouse to confirm that the data was correct and I even added a column to the tablix as a double check

clip_image002[6]

And it confirmed what I already thought: the data is correct. So why is the report not showing?

First I updated my SQL Server to the latest version (SQL Server 2008 R2), but that did not make any difference.

Another few hours of trying and modifying did not solve it. I couldn’t get the hang on it. Until I had help from John Socha-Leialohawho was able to solve the issue. What he did is the following:

  1. Download the report from the Reporting site
  2. Open the report in BIDS(the screen shots in this example are from BIDS for SQL Server 2008 R2, so might be slightly different if you use another version)
  3. Select the chart by clicking on it
  4. Right click on the chart to open the context menu

    image
  5. Choose “Change Chart Type” from the context menu
  6. You will see that the stacked bar is chosen

    image
  7. Change the chart type to the Bar chart type

     image
  8. And press OK
  9. Now change the chart type back to “Stacked bar”
  10. Follow the same steps for the Resolved Bugs chart.
  11. And upload the report to the reporting site again (be aware the when you look at the report on the Report site, that it is using a cached report. Just use other parameter values to use the new layout)

And here is the new report that shows the correct result.

image

Tags:

Reporting | VSTS 2010

Refresh the warehouse automatically

by Ewald Hofman 7. July 2010 13:17

When you are modifying the reports in Team Foundation Server, you want to add new data (such as work items) to test the reports. I have written a blog post how you can do that manually, but I wanted to do that with a little app to save time.

Attached is the source code and the exe (be aware to download the config too when you use the exe) with which you can achieve it.

You can use the application as following: RefreshWarehouse TfsServerName Port Collection
For example: "RefreshWarehouse localhost 8080 defaultcollection" to refresh the warehouse on the local tfs server.

RefreshWarehouse.zip (25.75 kb)

RefreshWarehouse.exe (31.50 kb)

RefreshWarehouse.exe.config (1.66 kb)

Tags:

Reporting | 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

How to connect VS 2003, VS 2005 and VS 2008 to TFS 2010?

by Ewald Hofman 29. April 2010 12:21

The architecture of TFS 2010 is changed, and the shipped products are now aware of this new architecture. So you need an update for these products to be able to connect to TFS.

Visual Studio 2008

You need to install the Forward Compatibility Update for Visual Studio 2008. Before you can apply this Update, it is required that Service Pack 1 is applied to Visual Studio 2008. You can find the download over here

http://www.microsoft.com/downloads/details.aspx?FamilyID=CF13EA45-D17B-4EDC-8E6C-6C5B208EC54D&displayLang=en

To make a connection to the TFS 2010 server, you must type in the full url to the server, which is

http://<myserver>:<port>/<virtualdir>/<collectionname>

such as http://tfs2010:8080/tfs/DefaultCollection

Visual Studio 2005

For Visual Studio 2005 you also need to apply a Forward Compatibility Update. You also need Service Pack 1 for Visual Studio 2005 to be able to apply the Update. You can find the download at:

http://www.microsoft.com/downloads/details.aspx?FamilyID=22215e4c-af6f-4e2f-96df-20e94d762689&displaylang=en

You make the connection to the TFS 2010 server in a similar was as you do for Visual Studio 2008

Visual Studio 2003

For Visual Studio 2003 there is no Team Explorer, you will need the MSSCCI provider to be able to connect to TFS 2010. You can find the MSSCCI provider in the Visual Studio Gallery at:

http://visualstudiogallery.msdn.microsoft.com/en-us/bce06506-be38-47a1-9f29-d3937d3d88d6

Installation order does matter

Be aware that the order of the installation is important for the solution to work correctly.

1. Install Visual Studio 200x

2. Install Team Explorer 200x

3. Install latest Service Pack for Visual Studio 200x

4. Install the Forward Compatibility Update

When you install Team Explorer after you install the service pack, Team Explorer will not be patched by the Forward Compatibility Update!

Tags: , , ,

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

TFS 2010 did not update the Warehouse and Cube

by Ewald Hofman 27. April 2010 14:30

After the upgrade from TFS 2008 to TFS 2010 the reporting was not working anymore. I got the following error message in the eventlog and the GetProcessingStatus webservice (you can find it when you open http://localhost:8080/tfs/TeamFoundation/Administration/v3.0/WarehouseControlService.asmx on your application tier):

[Full Analysis Database Sync]: ---> Microsoft.TeamFoundation.Server.WarehouseException: TF221122: An error occurred running job Full Analysis Database Sync for team project collection or Team Foundation server TEAM FOUNDATION. ---> Microsoft.TeamFoundation.Framework.Server.AnalysisServiceConnectionException: Error encountered when creating connection to Analysis Services. Contact your Team Foundation Server administrator. ---> Microsoft.AnalysisServices.ConnectionException: A connection cannot be made. Ensure that the server is running. ---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags) at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size) --- End of inner exception stack trace --- at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size) at System.IO.BufferedStream.Read(Byte[] array, Int32 offset, Int32 count) at Microsoft.AnalysisServices.DimeRecord.ForceRead(Stream stream, Byte[] buffer, Int32 length) at Microsoft.AnalysisServices.DimeRecord.ReadHeader() at Microsoft.AnalysisServices.DimeRecord..ctor(Stream stream) at Microsoft.AnalysisServices.DimeReader.ReadRecord() at Microsoft.AnalysisServices.TcpStream.GetResponseDataType() --- End of inner exception stack trace --- at Microsoft.AnalysisServices.XmlaClient.Connect(ConnectionInfo connectionInfo, Boolean beginSession) at Microsoft.AnalysisServices.Server.Connect(String connectionString, String sessionId) at Microsoft.AnalysisServices.Server.Connect(String connectionString) at Microsoft.TeamFoundation.Warehouse.AnalysisServicesUtil.Connect(Server server, String serverName) --- End of inner exception stack trace --- at Microsoft.TeamFoundation.Warehouse.AnalysisServicesUtil.Connect(Server server, String serverName) at Microsoft.TeamFoundation.Warehouse.AnalysisDatabaseSyncJobExtension.GetLastProcessedTimeStamp(String serverName, String dbName) at Microsoft.TeamFoundation.Warehouse.AnalysisDatabaseSyncJobExtension.DetermineProcessType(ControllerConfig controllerConfig, AnalysisDatabaseProcessingType desiredProcessingType, Boolean& lastProcessingFailed, Boolean& needCubeSchemaUpdate) at Microsoft.TeamFoundation.Warehouse.AnalysisDatabaseSyncJobExtension.RunInternal(TeamFoundationRequestContext requestContext, TeamFoundationJobDefinition jobDefinition, DateTime queueTime, String& resultMessage) at Microsoft.TeamFoundation.Warehouse.WarehouseJobExtension.Run(TeamFoundationRequestContext requestContext, TeamFoundationJobDefinition jobDefinition, DateTime queueTime, String& resultMessage) --- End of inner exception stack trace ---

I don’t know the root cause yet, but changing the Service Account for TFS from NETWORK SERVICE to a real account solved the issue. You can change the account in the TFS Admin Console, in the Application Tier node. You have there an action to change the service account.

Tags:

VSTS 2010 | Reporting

Upgrade the Build Server was not successful

by Ewald Hofman 27. April 2010 12:27

After upgrading the TFS server and the build server, everything seemed fine until I fired the first upgraded build. When you upgrade a build, you use the UpgradeTemplate, which basically has only one activity which is to fire off the MSBuild with the TFSBuild.proj you used also in TFS 2008.

When I fired my build, I got the following error:

TF270000: The TFSBuild workflow activity cannot continue because it requires a build targets file that is version 3 or higher. The version of the current build targets file is 2. To fix this problem, log on to build machine TFS2008_BS, open Control Panel, and run Repair on Microsoft Team Foundation Server 2010 to reinstall the appropriate version of C:\Program Files\MSBuild\Microsoft\VisualStudio\TeamBuild\Microsoft.TeamFoundation.Build.targets.

Of course I tried to repair the installation, but that did not solve the issue.


Solution

What is happening is that TFS 2010 uses an updated Microsoft.TeamFoundation.Build.targets file in C:\Program Files\MSBuild\Microsoft\VisualStudio\TeamBuild. In my installation this file was not updated, also not in the repair (that is why you should repair the installation: it will replace the targets file).

The solution in my case was to manually replace the targets file with the 2010 one, which is attached to this post.

There is also a Connect bug on this issue, please vote on this if you have the problem too: http://connect.microsoft.com/VisualStudio/feedback/details/542413/tfsbuild-fails-because-target-file-is-wrong-version

Microsoft.TeamFoundation.Build.targets (85 KB)

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

JIT debugger in mscorsvw after installing TFS 2010 on Windows Server 2003

by Ewald Hofman 26. April 2010 12:05

When you install TFS 2010 on a Windows Server 2003, with Visual Studio 2008 installed, you might get regularly an exception that shows you a window to open Visual Studio to start debugging. This is a known issue and solved with the following support article: http://support.microsoft.com/kb/2023204

It basically tells you to run the following command;

C:\Windows\Microsoft.NET\Framework\v4.0.30319\ngen install "Microsoft.VisualStudio.QualityTools.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /queue:1 /execonfig:"C:\Program Files\Common Files\Microsoft Shared\Team Foundation Server\10.0\tfsnop.exe"

Tags:

VSTS 2010

Disable the requirement on the secure connection for Reporting Services

by Ewald Hofman 22. April 2010 05:22

When I installed a brand new TFS 2010 instance, I was encountered with the following error message

   [ Reporting ] TF255455: SQL Server Reporting Services is configured to require a secure connection. However, no HTTPS URL is configured with a valid certificate. Use the Reporting Services Configuration Manager to configure or remove HTTPS support. For more information see http://go.microsoft.com/fwlink/?LinkId=179982

The link that was provided did not work for (maybe it has been already fixed), however I found the solution on the MSDN Forums provided by Ed Holloway:

This issue is happening due to the way SQL RS enables (and enforces) HTTPS on a machine.  If the SQL installer finds any certificates on the machine with the purpose set to * (anything) or server authentication it will set the SQL RS SecureConnectionLevel to 2, which requires HTTPS.  (This can happen in a few other scenarios too, but this is the common one)  So even though you may not have intended for RS to use SSL in this case, it is trying to enforce it.


NOTE:
These directions will disable SSL for SQL RS.

To work around this
Edit:
C:\Program Files\Microsoft SQL Server\MSRS10.<ServerInstance>\Reporting Services\ReportServer\rsreportserver.config
<Add Key="SecureConnectionLevel" Value="2"/>  (Change from current value to 0)

Here is what the values mean:
3 Most secure—Use SSL for absolutely everything.
2 Secure—Use SSL for rendering and methods that pass credentials but don't insist on it for all SOAP calls.
1 Basic Security—Accepts http but rejects any calls that might be involved in the passing of credentials.
0 Least Secure—Don't use SSL at all.

Tags:

VSTS 2010 | Reporting

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

Time travelling with Work Item Queries In TFS 2010

by Ewald Hofman 20. April 2010 05:28

Someone asked me if I could help him because he made a mess of the work items. He published old data from Excel to TFS, so all the updates of his team mates where gone with one click.

There is a nice and very under-appreciated feature in the work item queries to get the values of the work items at a moment in history as if you created a snapshot at that time. It is pretty easy to accomplish this with the ASOF feature. The following steps show you how you can use the ASOF statement.

  1. Create a new query with the fields and filters you are interested in via the default “Add query” command
  2. Save the query (File –> Save New Query 1 [Query])
  3. You get now the ability to store the query on the file system 

    TimeTravelling002
  4. Select an appropriate location and click Save
  5. Open the file you just saved in Notepad. You will now see the Work Item Query Language (WIQL) that is used to define the query. For more information on the syntax, please refer to http://msdn.microsoft.com/en-us/library/bb130198.aspx
    This WIQL could look like:

    <?xml version="1.0" encoding="utf-8"?><WorkItemQuery Version="1"><TeamFoundationServer>http://myserver:8080/tfs/defaultcollection</TeamFoundationServer><TeamProject>Agile</TeamProject><Wiql>SELECT [System.Id], [System.Title] FROM WorkItems WHERE [System.AssignedTo] = 'Ewald Hofman' ORDER BY [System.Id]</Wiql></WorkItemQuery>
  6. You can only execute a modified WIQL with a .NET app. So lets create a new C# ConsoleApplication project
  7. Add the references to
    1. Microsoft.TeamFoundation.Client
    2. Microsoft.TeamFoundation.Common
    3. Microsoft.TeamFoundation.WorkItemTracking.Client
    4. System.Windows.Forms

      you can find the TeamFoundation assemblies in %Program Files%\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0
  8. Add the following using statements to your code

    using Microsoft.TeamFoundation.Client;
    using Microsoft.TeamFoundation.WorkItemTracking.Client;
    using System.Net;
    using System.Windows.Forms;
  9. Now add the following code to the class Program. You will have to modify the tfsServer and queryText variables to your own values. Notice at the end of the queryText the ASOF syntax. With this statement you are time travelling.
    [STAThread()]
    static void Main(string[] args)
    {
    
    
        StringBuilder clipboardText = new StringBuilder();
        bool titlesPrinted = false;
    
    
        string tfsServer = @"http://myserver:8080/tfs/defaultcollection";
        string queryText = @"SELECT [System.Id], [System.Title], [System.State] FROM WorkItems 
                                WHERE [System.AssignedTo] = 'Ewald Hofman' ORDER BY [System.Id] ASOF '4/10/2010'";
    
        // Open the connection to TFS
        using (var tfs = new TfsTeamProjectCollection(new Uri(tfsServer), CredentialCache.DefaultCredentials))
        {
    
            // Get the work item service
            var store = (WorkItemStore)tfs.GetService(typeof(WorkItemStore));
    
            // Execute the query
            var wiCollection = store.Query(queryText);
    
            // Iterate through all work items
            foreach (WorkItem wi in wiCollection)
            {
                // Add the column headers
                if (!titlesPrinted)
                {
                    titlesPrinted = true;
    
                    foreach (FieldDefinition field in wiCollection.DisplayFields)
                    {
                        clipboardText.Append(field.Name);
                        clipboardText.Append("\t");
                    }
                    clipboardText.AppendLine();
                }
    
                // Add the work item values
                foreach (FieldDefinition field in wiCollection.DisplayFields)
                {
                    clipboardText.Append(wi.Fields[field.Name].Value);
                    clipboardText.Append("\t");
                }
                clipboardText.AppendLine();
            }
        }
    
        // Put the complete text to the clipboard, so it can be copied to Excel
        if (clipboardText.Length > 0)
            SetClipboard(clipboardText.ToString());
    
    
    
    }
    
    /// <summary>
    /// Try a few times to put it on the clipboard: known issue...
    /// </summary>
    public static void SetClipboard(object data)
    {
        for (int i = 0; i < 10; i++)
        {
            try
            {
                Clipboard.SetDataObject(data);
                return;
            }
            catch { }
            System.Threading.Thread.Sleep(100);
        }
    }
  10. You can now run the code, open Excel and start paste command.

Tags:

TFS SDK | VSTS 2010 | Work items

TFS SDK 2010 – Part 6 – Replace text in all Work Item Query Definitions

by Ewald Hofman 9. March 2010 04:20

Updates

  • 19-3-2010: Added the possibility to change the queries in a specific folder

When you work iterative, you might just want to replace your current release or iteration in the query definitions, instead of creating a bunch of new queries. This post shows you how you can perform a quick and simple replace mechanism to achieve this.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;

using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Framework.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.TestManagement.Client;
using System.Diagnostics;

namespace TFS_SDK
{
    class Program
    {
        static void Main(string[] args)
        {
            // The url to the tfs server
            Uri tfsUri = new Uri("http://localhost:8080/tfs/");
            const string projectName = "Agile";
            const string startFolder = null; //@"Team Queries\Release 1\Sprint 2";
            const string searchFor = "Iteration 1";
            const string replaceWith = "Iteration 2";

            // Load the tfs instance
            TfsTeamProjectCollection tpc = new TfsTeamProjectCollection(tfsUri, new UICredentialsProvider());

            // Log in to TFS
            tpc.EnsureAuthenticated();

            var wiStore = tpc.GetService<WorkItemStore>();
            var project = wiStore.Projects[projectName];

            foreach (QueryDefinition queryDefinition in GetAllTeamQueries(project, startFolder))
            {
                if (queryDefinition.QueryText.Contains(searchFor))
                {
                    queryDefinition.QueryText = queryDefinition.QueryText.Replace(searchFor, replaceWith);
                }
            }

            project.QueryHierarchy.Save();
        }

        private static List<QueryDefinition> GetAllTeamQueries(Project project, string startFolder)
        {
            var ret = new List<QueryDefinition>();

            var startQueryFolder = GetQueryFolder(project.QueryHierarchy,
                                                  startFolder == null ? (new string[] { }) : startFolder.Split('\\'));

            ret.AddRange(GetAllTeamQueries(startQueryFolder));

            return ret;
        }

        private static List<QueryDefinition> GetAllTeamQueries(QueryFolder queryFolder)
        {
            var ret = new List<QueryDefinition>();

            foreach (QueryItem queryItem in queryFolder)
            {
                if (queryItem is QueryFolder)
                {
                    ret.AddRange(GetAllTeamQueries(queryItem as QueryFolder));
                }
                else
                {
                    ret.Add(queryItem as QueryDefinition);
                }
            }

            return ret;
        }

        private static QueryFolder GetQueryFolder(QueryFolder queryFolder, string[] folders)
        {
            return folders.Length == 0 ? queryFolder : GetQueryFolder((QueryFolder)queryFolder[folders[0]], folders.Skip(1).ToArray());
        }
    }
}

Tags:

VSTS 2010 | TFS SDK

VS ALM 2010 pricing

by Ewald Hofman 25. January 2010 22:32

Times are coming closer to the launch date of VS ALM 2010. Microsoft has just released the pricing for the new products. To refresh the memory, the features in the different SKU’s look like: 

The prices that belong to these SKU’s are

Suggested Retail Pricing (USD) for Visual Studio 2010

With 1-Year MSDN Subscription

Product

Buy

Upgrade

Buy

Renew

Visual Studio 2010 Ultimate

-

-

$11,899

$3,799

Visual Studio 2010 Premium

-

-

$5,469

$2,299

Visual Studio 2010 Professional

$799

$549

$1,199

$799

Visual Studio Test Professional 2010

-

-

$2,169

$899

Visual Studio Team Foundation Server 2010

$499

$399

-

-

Visual Studio Team Foundation Server 2010 CAL

$499

-

-

-

Visual Studio Load Test Virtual User Pack 2010 (1000 Virtual Users)

$4,499

-

-

-

Tags:

VSTS 2010

TFS Sidekicks for TFS 2010 Beta 2

by Ewald Hofman 4. January 2010 23:56

Almost two months ago, I posted the following blog item TFS Sidekicks minor release update (2.4)and indicated that there would be support for TFS 2010 Beta 2 at the end of 2009.

Attrice has announced that they just released an update for the version 2.4 that supports TFS 2010 Beta 2. For more information see http://www.attrice.info/blog/2010/01/03/team-foundation-sidekicks-2-4-release-2/

Tags:

VSTS 2010

TFS SDK 2010 – Part 5 – Create a new Test Case work item

by Ewald Hofman 11. December 2009 06:26

In Part 1 I have described how to access the Application Instance of the TFS server. This post describes how you can create a new test case based on the TestManagement capabilities. In later posts I will show what you can do more with the test management.

In order to get access to the work items, add a reference to:

  • Microsoft.TeamFoundation.TestManagement.Client
  • WindowBase (which you can find on the .Net tab in the Add Reference Dialog)

You can find the dll’s in C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0

Then you have to add the following using statements:

using Microsoft.TeamFoundation.TestManagement.Client;

You can now create the work items with the following code:

// Get the work item store
ITestManagementService tms = tfai.GetTeamFoundationServer(tpc.Id).GetService<ITestManagementService>();

// Get the team project
var project = tms.GetTeamProject("Agile");

var testCase = project.TestCases.Create();
testCase.Title = "Browse my blog";

var navigateToSiteStep = testCase.CreateTestStep();
navigateToSiteStep.Title = "Navigate to \"http://www.ewaldhofman.nl\"";
testCase.Actions.Add(navigateToSiteStep);

var clickOnFirstPostStep = testCase.CreateTestStep();
clickOnFirstPostStep.Title = "Click on the first post in the summary";
clickOnFirstPostStep.ExpectedResult = "The details of the post are visible";
testCase.Actions.Add(clickOnFirstPostStep);

testCase.Save();

The result is a new test case with two steps in it:

image

Tags:

TFS SDK | VSTS 2010

TFS 2010 – Adding the SharePoint portal afterwards [Beta 2]

by Ewald Hofman 11. December 2009 05:39

I created a new Team Project in TFS 2010 Beta 2 and choose not to configure SharePoint during the creation of the Team Project. Of course I found out fairly quickly that a portal for TFS is very useful, especially the Iteration and the Product backlog workbooks and the dashboard reports.

This blog describes how you can configure the SharePoint portal afterwards. Many thanks to Adam Cogan, who gave me fantastic directions to improve the blog post.

Update #1 September 9th, 2009: As suggested by Adam Cogan, added the option of the Dummy project.

Update #2 December 11th, 2009: As suggested by Adam Cogan, modified the post to Beta 2 + added the summary.


Summary of your options

You have several options to get the portal to your team project. The best option would be to have the ability in the Team Foundation Administration Console to create the portal for you, but that feature will not be added in TFS 2010 RTM . If you want it in a future version, please vote on https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=519770

Then there are two other options that you can use today:
Option 1: Create a Dummy Project in TFS to get the SharePoint Portal (recommended)
Option 2: Create the Portal in SharePoint and then fix up the missing documents


Option 1: Create a Dummy Project in TFS to get the SharePoint Portal (recommended)

Step 1: Create a new temporary project (with a SharePoint site for it).

  1. Open the Team Explorer

  2. Right click in the Team Explorer the root node (i.e. the project collection)

  3. Select "New team project" from the menu

  4. Walk throught he wizard and make sure you check the option to create the portal (which is by default checked)

Step 2: Disable the site for the new project

  1. Open the Team Explorer

  2. Select the team project you created in step 1

  3. In the menu click on Team -> Show Project Portal.

  4. In the menu click on Team -> Team Project Settings -> Portal Settings...

  5. The following dialog pops up


  6. Uncheck the option "Enable team project portal"

  7. Confirm the dialog with OK

Step 3: Enable the site for the original one. Point it to the newly created site.

  1. Open the Team Explorer

  2. Select the team project you want to add the portal to

  3. In the menu open Team -> Team Project Settings -> Portal Settings...

  4. The same dialog as in step 2 pops up

  5. Check the option "Enable team project portal"

  6. Click on the "Configure URL" button

  7. The following dialog pops up

     

  8. In the dialog select in the combobox of the web application the TFS server

  9. Enter in the Relative site path the text "sites/[Project Collection Name]/[Team Project Name created in step 1]"

  10. Confirm the "Specify an existing SharePoint Site" with OK

  11. Check the "Reports and dashboards refer to data for this team project" option

  12. Confirm the dialog "Project Portal Settings" with OK

Step 4: Delete the temporary project you created.

  1. Open the command prompt (Start –> Run, cmd)

  2. Go to C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE

  3. Enter the following command:

    TFSDeleteProject /q /collection:http://<servername>:8080/tfs/<project_collection_name> <Team Project Name>

    for example, TFSDeleteProject /q /collection:http://localhost:8080/tfs/DefaultCollection TempProject


Option 2: Create the Portal in SharePoint and then fix up the missing documents

Step 1: Create new portal site

  1. Go to the sharepoint site of your project collection (/sites//default.aspx">/sites//default.aspx">/sites//default.aspx">/sites//default.aspx">/sites//default.aspx">http://<servername>/sites/<project_collection_name>/default.aspx)

  2. Click on the Site Actions at the left side of the screen and choose the option Site Settings

  3. In the site settings, choose the Sites and workspaces option

  4. Create a new site

  5. Enter the values for the Title, the description, the site address. And choose for the TFS2010 Agile Dashboard as template.

  6. Create the site, by clicking on the Create button

Step 2: Integrate portal site with team project

  1. Open Visual Studio

  2. Open the Team Explorer (View -> Team Explorer)

  3. Select in the Team Explorer tool window the Team Project for which you are create a new portal

  4. Open the Project Portal Settings (Team -> Team Project Settings -> Portal Setings...)

  5. Check the Enable team project portal checkbox

  6. Click on Configure URL...

  7. You will get a new dialog as below

  8. Enter the url to the TFS server in the web application combobox

  9. And specify the relative site path: sites/<project collection>/<site name>

  10. Confirm with OK

  11. Check in the Project Portal Settings dialog the checkbox "Reports and dashboards refer to data for this team project"

  12. Confirm the settings with OK (this takes a while...)

  13. When you now browse to the portal, you will see that the dashboards are now showing up with the data for the current team project. We will fix that in the next step.

Step 3: Download process template

  1. To get a copy of the documents that are default in a team project, we need to have a fresh set of files that are not attached to a team project yet. You can do that with the following steps.

  2. Start the Process Template Manager (Team -> Team Project Collection Settings -> Process Template Manager...)

  3. Choose the Agile process template and click on download

  4. Choose a folder to download

Step 4: Add Product and Iteration backlog

  1. Go to the Team Explorer in Visual Studio

  2. Make sure the team project is in the list of team projects, and expand the team project

  3. Right click the Documents node, and choose New Document Library

  4. Enter "Shared Documents", and click on Add

  5. Right click the Shared Documents node and choose Upload Document

  6. Go the the file location where you stored the process template from step 3 and then navigate to the subdirectory "Agile Process Template 5.0\MSF for Agile Software Development v5.0\Windows SharePoint Services\Shared Documents\Project Management"

  7. Select in the Open Dialog the files "Iteration Backlog" and "Product Backlog", and click Open

Step 5: Bind Iteration backlog workbook to the team project

  1. Right click on the "Iteration Backlog" file and select Edit, and confirm any warning messages

  2. Place your cursor in cell A1 of the Iteration backlog worksheet

  3. Switch to the Team ribbon and click New List.

  4. Select your Team Project and click Connect

  5. From the New List dialog, select the Iteration Backlog query in the Workbook Queries folder.

  6. The final step is to add a set of document properties that allow the workbook to communicate with the TFS reporting warehouse. Before we create the properties we need to collect some information about your project. The first piece of information comes from the table created in the previous step.  As you collect these properties, copy them into notepad so they can be used in later steps.

    Property How to retrieve the value?
    [Table name] Switch to the Design ribbon and select the Table Name value in the Properties portion of the ribbon
    [Project GUID] In the Visual Studio Team Explorer, right click your Team Project and select Properties.  Select the URL value and copy the GUID (long value with lots of characters) at the end of the URL
    [Team Project name] In the Properties dialog, select the Name field and copy the value
    [TFS server name]

    In the Properties dialog, select the Server Name field and copy the value

    [UPDATE] I have found that this is not correct: you need to specify the instance of your SQL Server. The value is used to create a connection to the TFS cube.

  7. Switch back to the Iteration Backlog workbook.

  8. Click the Office button and select Prepare – Properties.

  9. Click the Document Properties – Server drop down and select Advanced Properties.

  10. Switch to the Custom tab and add the following properties using the values you collected above.

    Variable name Value
    [Table name]_ASServerName [TFS server name]
    [Table name]_ASDatabase tfs_warehouse
    [Table name]_TeamProjectName [Team Project name]
    [Table name]_TeamProjectId [Project GUID]

  11. Click OK to close the properties dialog.

  12. It is possible that the Estimated Work (Hours) is showing the #REF! value. To resolve that change the formula with:

    =SUMIFS([Table name][Original Estimate]; [Table name][Iteration Path];CurrentIteration&"*";[Table name][Area Path];AreaPath&"*";[Table name][Work Item Type]; "Task")

    For example

    =SUMIFS(VSTS_ab392b55_6647_439a_bae4_8c66e908bc0d[Original Estimate]; VSTS_ab392b55_6647_439a_bae4_8c66e908bc0d[Iteration Path];CurrentIteration&"*";VSTS_ab392b55_6647_439a_bae4_8c66e908bc0d[Area Path];AreaPath&"*";VSTS_ab392b55_6647_439a_bae4_8c66e908bc0d[Work Item Type]; "Task")

  13. Also the Total Remaining Work in the Individual Capacity table may contain #REF! values. To resolve that change the formula with:

    =SUMIFS([Table name][Remaining Work]; [Table name][Iteration Path];CurrentIteration&"*";[Table name][Area Path];AreaPath&"*";[Table name][Assigned To];[Team Member];[Table name][Work Item Type]; "Task")

    For example

    =SUMIFS(VSTS_ab392b55_6647_439a_bae4_8c66e908bc0d[Remaining Work]; VSTS_ab392b55_6647_439a_bae4_8c66e908bc0d[Iteration Path];CurrentIteration&"*";VSTS_ab392b55_6647_439a_bae4_8c66e908bc0d[Area Path];AreaPath&"*";VSTS_ab392b55_6647_439a_bae4_8c66e908bc0d[Assigned To];[Team Member];VSTS_ab392b55_6647_439a_bae4_8c66e908bc0d[Work Item Type]; "Task")

  14. Save and close the workbook.

Step 6: Bind Product backlog workbook to the team project

  1. Repeat the steps for binding the Iteration backlog for thiw workbook too.

  2. In the worksheet Capacity, the formula of the Storypoints might be missing. You can resolve it with:

    =IF([Iteration]="";"";SUMIFS([Table name][Story Points];[Table name][Iteration Path];[Iteration]&"*"))

    Example

    =IF([Iteration]="";"";SUMIFS(VSTS_487f1e4c_db30_4302_b5e8_bd80195bc2ec[Story Points];VSTS_487f1e4c_db30_4302_b5e8_bd80195bc2ec[Iteration Path];[Iteration]&"*"))

Tags:

Portal | VSTS 2010

TFS SDK 2010 – Part 2 - Get a work item

by Ewald Hofman 11. December 2009 04:23

In Part 1 I have described how to access the Application Instance of the TFS server. This post describes how you can create access to your work items:

In order to get access to the work items, add a reference to:

  • Microsoft.TeamFoundation.WorkItemTracking.Client.dll

You can find the dll’s in C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0

Then you have to add the following using statements:

using Microsoft.TeamFoundation.WorkItemTracking.Client;

You can now enumerate the values of a work item with the following code:

// Get the work item store
WorkItemStore wiStore = tfai.GetTeamFoundationServer(tpc.Id).GetService<WorkItemStore>();

// Get the work item with the Id 1
WorkItem wi = wiStore.GetWorkItem(1);

// Write the name and value for all fields in the work item
foreach (Field fd in wi.Fields)
{
    Console.WriteLine("{0}: {1}", fd.Name, fd.Value);
}

All code examples are based on Beta 2 and are subject to change.

Tags:

TFS SDK | VSTS 2010

TFS SDK 2010 – Part 4 - Create a new User Story, with the implementation (Tasks) and test scenarios (Test Case)

by Ewald Hofman 10. December 2009 08:31

In Part 1 I have described how to access the Application Instance of the TFS server. This post describes how you can create new work items, including a new linked work item. The new link makes use of the new link type in TFS 2010, so it shows up on the correct tab page. In this example a new User Story is created with one Task as its implementation and one Test Case which tests the User Story:

In order to get access to the work items, add a reference to:

  • Microsoft.TeamFoundation.WorkItemTracking.Client.dll

You can find the dll’s in C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0

Then you have to add the following using statements:

using Microsoft.TeamFoundation.WorkItemTracking.Client;

You can now create the work items with the following code:

// Get the work item store
WorkItemStore wiStore = tfai.GetTeamFoundationServer(tpc.Id).GetService<WorkItemStore>();

// Get the team project
var project = wiStore.Projects["Agile"];

// Create a new User Story
var wiUserStory = new WorkItem(project.WorkItemTypes["User Story"])
{
    Title = string.Format("New User Story, created at {0:g}", DateTime.Now),
    Description = "This is an example how you create a new work item with the SDK"
};
wiUserStory.Save();

// Create a new Task
var wiTask = new WorkItem(project.WorkItemTypes["Task"])
{
    Title = "Create a very secure design"
};
wiTask.Save();

// Add a parent-child link between User Story and Task
var hierarchicalLink = wiStore.WorkItemLinkTypes["System.LinkTypes.Hierarchy"];
wiUserStory.WorkItemLinks.Add(new WorkItemLink(hierarchicalLink.ForwardEnd, wiTask.Id));
wiUserStory.Save();

// Create a new Test Case
var wiTestCase = new WorkItem(project.WorkItemTypes["Test Case"])
{
    Title = "Test on security",
};
wiTestCase.Fields["Steps"].Value = "<steps id=\"0\" last=\"2\"><step id=\"1\" type=\"ActionStep\"><parameterizedString>" + 
                                   "<text>Go to the correct url</text></parameterizedString><parameterizedString /><description />" + 
                                   "</step><step id=\"2\" type=\"ActionStep\"><parameterizedString><text>Hack the site</text>" + 
                                   "</parameterizedString><parameterizedString /><description /></step></steps>";
wiTestCase.Save();

// Add a tested by link between User Story and Test Case
var testedByLink = wiStore.WorkItemLinkTypes["Microsoft.VSTS.Common.TestedBy"];
wiUserStory.WorkItemLinks.Add(new WorkItemLink(testedByLink.ForwardEnd, wiTestCase.Id));
wiUserStory.Save();

Tags:

TFS SDK | VSTS 2010

TFS SDK 2010 – Part 3 - Enumerate the build controllers and agents

by Ewald Hofman 6. December 2009 05:48

In Part 1 I have described how to access the Application Instance of the TFS server. This post describes how you can create access to your build controller and agents:

In order to get access to the work items, add a reference to:

  • Microsoft.TeamFoundation.WorkItemTracking.Build.dll

You can find the dll’s in C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0

Then you have to add the following using statements:

using Microsoft.TeamFoundation.Build.Client;

You can now enumerate the values of a work item with the following code:

// Get the build server
IBuildServer buildServer = tfai.GetTeamFoundationServer(tpc.Id).GetService<IBuildServer>();

// Enumerate the controllers
foreach (IBuildController controller in buildServer.QueryBuildControllers(true))
{
    Console.WriteLine("{0}", controller.Name);

    // Enumerate the agents in the controller
    foreach (IBuildAgent agent in controller.Agents)
    {
        Console.WriteLine("\t{0}", agent.Name);
    }
}

All code examples are based on Beta 2 and are subject to change.

Tags:

VSTS 2010 | TFS SDK

TFS SDK 2010 – Part 1 – Get the Team Project Collection

by Ewald Hofman 3. December 2009 11:28

This is the first post in a series that describes how you can work with the TFS Object Model, API or SDK. In this first part we will open a connection to the team project collection that opens the ability to access all artifacts of TFS.

Create a new project and add the following references to your project:

  • Microsoft.TeamFoundation.Client.dll
  • Microsoft.TeamFoundation.Common.dll

You can find the dll’s in C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0

Then you have to add the following using statements:

using Microsoft.TeamFoundation.Client; 
using Microsoft.TeamFoundation.Framework.Client;

You can now open the connection with the following code:

// The url to the tfs server 
Uri tfsUri = new Uri("http://localhost:8080/tfs/");

// Load the tfs instance 
TeamFoundationApplicationInstance tfai = new TeamFoundationApplicationInstance(tfsUri, new UICredentialsProvider()); 

// Log in to TFS 
tfai.EnsureAuthenticated(); 

// Get the default project collection 
TeamProjectCollection tpc = tfai.GetService<ITeamProjectCollectionService>().GetDefaultCollection();

The following posts will describe how to access the rest of the artifacts (work items, version control and team build) in the TFS SDK.

All code examples are based on Beta 2 and are subject to change.

Tags:

VSTS 2010 | TFS SDK

Power Tools and MSSCCI provider for TFS 2010 Beta 2

by Ewald Hofman 1. December 2009 11:55

Today Microsoft has released the first two extensions on TFS:

  • MSSCCI provider
  • TFPT

MSSCCI provider

With the MSSCCI provider, you can connect to TFS Version Control with environments other then Visual Studio 2008/2010. This provider has shown its relevance to have great adaptation in the previous power tools. Having this provider for the TFS 2010 Beta 2 version makes the decision to use TFS 2010 in the beta 2 phase even more easy for companies.

You can find the download at http://visualstudiogallery.msdn.microsoft.com/en-us/f959ea32-5ac3-424a-a709-5001a158ebe8

TFPT

The TFPT are the power tools for TFS. When I go to a customer, first thing I recommend is to install the power tools. I can not live without them anymore!

The following table lists the features that are available in the power tools

Power tool Description
Process Template Editor (PTE) You can change the process template and the work item types (WIT) without the power tools with the command line. With the PTE, you have access to a visual editor with the Tools menu in Visual Studio. This makes it much easier to customize the process template to your specific needs.
Best Practice Analyzer (BPA) The BPA checks your TFS installation on the recommended settings. As a TFS administrator, you will love this tool since it will tell you how you can improve the health of the configuration.
Check-in policy pack

Check-in policies are extremely helpful in guiding the TFS users what is required when they check in their code. Installing the check-in policies improves the quality, the traceability and the stability of the versioned items. Included in the power tools are:

- Custom Path Policy, which makes it possible to apply a check-in policy on specific version control folders
- Forbidden Patterns Policy, which disallows to check-in filenames of a specific pattern
- Changeset Comments Policy, which ensures that the comment is entered when checking in
- Work Item Query Policy, which ensures that a work item is included that is part of a work item query

 
Windows Shell Extension Not everybody wants to work with Visual Studio to be able to put files under version control, like a requirements engineer or a tester. With this extension, the context menu of the Windows Explorer contains the version control menu items (such as get latest, check in and check out). The menu items will appear in the menu for every folder that is included in a workspace.
PowerShell support PowerShell gives you an alternative to programming in C# against the TFS SDK. It is a great tool for administrators to automate tasks.

Command line support

TFPT has the ability to perform most actions by the command line

Work Item Templates

With these templates you have the ability to populate work items with default values. For example, when you are creating lots of work items for a specific person for a specific area in a specific iteration, you can add these values to the template and create work items from the template, or apply the template to already created work items

Alert editor

TFS has a built-in alert editor, which is very limited in functionality. With the alert editor, you can define the condition when the alert should be triggered with a nice UI.

You can find the download at http://visualstudiogallery.msdn.microsoft.com/en-us/0e69a28f-020c-488b-80b3-f4c89a20621d

Tags: , , , ,

VSTS 2010

Refresh the TFS Warehouse manually

by Ewald Hofman 25. November 2009 08:18

Reporting (SSRS and Excel) in TFS makes use of Sql Server Analysis Server, or OLAP cube. This cube is by default refreshed every two hours. This is in most cases frequently enough to get the correct information. You can however change this default behaviour. You can either change the interval of the warehouse refreshment or you can refresh the cube manually.

Be aware that SSRS is caching the reports, which means that when the data might not be refreshed in the SSRS report as you expected. For changing the caching settings of the reports see http://msdn.microsoft.com/en-us/library/ms157146.aspx.

Change the interval

To change the interval follow the following steps

1. Go to the desktop of the Application Tier

2. Open Internet Explorer and type http://localhost:8080/tfs/TeamFoundation/Administration/v3.0/WarehouseControlService.asmx in the adress bar. You get a list of all available web services.

image

3. To change the interval, choose the ChangeSetting webservice

4. You will see a new page where you can enter the setting and its new value.

image

Enter in the SettingId: RunIntervalSeconds
and in the newValue the number of seconds (3600 is one hour)

5. Click on Invoke to change the setting

Manually refresh the cube

You can also choose to refresh the cube once. To do that follow the following steps.

1. Open the list of web services again with http://localhost:8080/tfs/TeamFoundation/Administration/v3.0/WarehouseControlService.asmx

2. Select the ProcessWarehouse web service from the list

image

3. Enter in the collectionName the name of the Project Collection you want to refresh. The default collection is named DefaultCollection, but you can change that in the collection that is in use on your TFS environment.

4. Click on Invoke

5. Go back to the list of webservices and click on the ProcessAnalysisDatabase webservice, and enter in the processType textbox the value Full.

image

6. Click on Invoke

7. The data warehouse is now refreshed. This can take some time when you have a large database. To check the status of the warehouse update, you can check the GetProcessingStatus webservice. You can leave the parameters for the webservice blank to retrieve all information. The warehouse update is ready when all jobs have the “Idle” job status.

Tags:

Reporting | VSTS 2010

Allow in TFS 2010 Team Query contributions by non-Project Administrators

by Ewald Hofman 13. November 2009 05:34

Team Queries are a great way to share queries over the team. In TFS 2008 you had to have the role of a Project Administrator to create Team Queries. Since Project Administrators can do much more, such as the adding and removing users to the team project and change the Team Project settings, you do not want to give everybody this role. In TFS 2008 you had to find workarounds to share the query with the team, such as storing it in SharePoint, saving it as a file, or by sending over the query string.

In TFS 2010, you can now adjust this yourself. By default, only the Project Admin is able to add, modify and delete Team Queries.

To adjust this, open the context menu on the folder you want to change.

image

Select the Security option. This shows you a dialog in which you can adjust the security for this folder.

image

You can for example create a `Shared Queries´ folder. You want to allow that the Contributors can add new Team Queries. You can do that by selecting the Contributor role in the upper list, and then check the Contribute permission on the lower list.

image

Press OK, and we are one big happy family again that is able to share our valuable information.

Tags:

VSTS 2010 | Work items

Great news for the Teamprise users

by Ewald Hofman 9. November 2009 05:23

Microsoft has announced today at TechEd that it acquired TeamPrise Client Suite. The best known component of this suite is the Eclipse plug-in that allows Java users to integrate with TFS. This is just release by Brian Harry: http://blogs.msdn.com/bharry/archive/2009/11/09/microsoft-has-acquired-the-teamprise-client-suite.aspx .

This is another step for Microsoft to improve its service to the customers. It gets easier and cheaper for the Java community to use the TFS environment, which will broaden the footprint for the TFS environment. I can’t wait to get all those enthusiastic Java users into the TFS community and show all the goodness!

Tags:

VSTS 2010

Lap around TFS 2010 on DotNed on November 26th

by Ewald Hofman 9. November 2009 05:16

I am very excited to show the latest and greatest that is available in TFS 2010. Hassan Fadili from the VSTS track in the DotNed community user group and MVP Team System has asked me to do together with him a presentation on this topic. Most of the new things in TFS 2010 will be shown:

  • Administration / Setup
  • Workitem Tracking
  • Build Management
  • Reporting
  • Test Management
  • VS2010 Architect (UML Integratie)

The session will be at November 26th in Schiphol Rijk. If you are interested in this topic and get up-to-speed very quickly on tooling that will available for you in a few months, please join the session

For the full invitation see http://www.dotned.nl/meetings.aspx

Tags:

VSTS 2010

Import test cases from Excel

by Ewald Hofman 6. November 2009 13:28

On of the pillars of TFS 2010 is the “No More No Repro”. This statement is based on the exceptional tooling to improve the communication and information hand-over between the developer and the tester. The tooling that is used is the IntelliTrace (aka Historical Debugging) and the Test Center.

The Test Center is heavily based on the Test Case work item. That work item contains the steps for the test case, which are shown when executing the test case.

 ScreenShot001

That is very nice, but what to do with all those test cases that we have already defined in other applications. And what to do with testers who does not want to leave their own tooling, such as Excel. For those situation, Microsoft has created a Test Case Importer tool on Codeplex. This post shows you what you can expect from that importer.

You can download the importer from: http://tcmimport.codeplex.com.

When you first start the importer you will see the following screen

ScreenShot002

The importer will guide you through a couple of steps to give enough information how and what to import. In this post the following sheet is used as example.

ScreenShot003

First it asks the destination of the test steps.

 image

Then the wizard asks for the destination. This is a combination of the TFS Server, the team project and the work item type.

image

The next step is to create a mapping between the columns in Excel and the fields in the work item

image

In the Data Mapping step you have the possibility to create a mapping between values in Excel and lists in the TFS work item, for example for the Priority field.

When you then start the import, a progress dialog appears

image

When the importer is ready, you have created for each row a new test case work item which you can use to do the further testing.

I am very satisfied that Microsoft has provided a tool to import test cases that were created in the past. Can’t wait to convert all those test cases in the excellent TFS 2010 environment and make my product very stable.

Tags:

VSTS 2010 | Work items | Test Essentials

VS & TFS 2010 Beta 2 has arrived

by Ewald Hofman 19. October 2009 12:09

Finally, Microsoft has released today the beta 2 for MSDN subscribers today. With the release of this beta 2, Microsoft has also announced a new SKU model.

In Visual Studio 2008, the following model was valid, which consisted of four SKU's. The branding of Visual Studio had terms of TFS, Team System and Team Suite. Research indicated that this branding was little know by a lot of customers.

 

 The marketing team of Microsoft now brings a new model, that is more in line that you see with the Windows versions.

This new model should make an end to the confusion with a lot of customers about the branding.

Tags:

VSTS 2010

TFS 2010 Beta 2 has a Go Live license

by Ewald Hofman 5. October 2009 06:16

TFS 2010 beta 2 will arrive very soon. This version is very stable, and Microsoft is very confident so it is giving a Go Live license to all customers. You can find more details on the blog of Brian Keller. The blog says:

"But the best news is that beta 2 of Team Foundation Server 2010 will have a “go live” license, meaning that you can use it for your day-to-day application building" 

In my opinion Microsoft has done a great job with TFS 2010. There are awesome features that will drive me nuts when I have to use TFS 2005/2008 in the future :). So grab the copy of Beta 2 when it arrives and start using it to your software development process. Make use of the greatness of:

  1. Testing features
  2. Historical debugging
  3. Hierarchical work items
  4. Improved reports
  5. Excel reporting
  6. and much more

You can find guidance at:

I feel very lucky to live in a time where the TFS tooling gets so beautiful :)

 

Tags:

VSTS 2010

Free download of TFS Work Item Manager & TFS Project Dashboard

by Ewald Hofman 9. September 2009 11:26

Inspired by agile development methodologies, these two free applications have been designed to make working with Microsoft’s Team Foundation Server faster and easier. By promoting robust yet flexible project management practices, TFS Work Item Manager Beta and TFS Project Dashboard Beta allow for rapid delivery of high-quality software. Both tools have been used extensively internally at Telerik and Imaginet for over six months with great results. The applications have been built by Imaginet Resources using RadControls for WPF and are available for free download.

Read more on this interesting offer at http://www.telerik.com/products/tfsmanager-and-tfsdashboard.aspx

 

Tags:

VSTS 2010 | Work items

Visual Studio Code Analysis Performance

by Ewald Hofman 6. September 2009 23:39

Doug Holland posted a very nice suggestion to improve the performance of Code Analyze. Bottom line is to add an option to only analyze the code files that have been checked out. If you like the suggestion, please vote on Microsoft Connect: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=488181

You can read the full story at http://software.intel.com/en-us/blogs/2009/09/04/visual-studio-code-analysis-performance/

Tags: ,

VSTS 2010

Configure TFS portal afterwards

by Ewald Hofman 13. August 2009 08:47

Update #1 January 8th, 2010: There is an updated post on this topic for Beta 2: http://www.ewaldhofman.nl/post/2009/12/10/Configure-TFS-portal-afterwards-Beta-2.aspx

I created a new Team Project in TFS 2010 Beta 1 and choose not to configure SharePoint during the creation of the Team Project. Of course I found out fairly quickly that a portal for TFS is very useful, especially the Iteration and the Product backlog workbooks and the dashboard reports.

This blog describes how you can configure the sharepoint portal afterwards.

Update: September 9th, 2009

Adding the portal afterwards is much easier as described below. Here are the steps

Step 1: Create a new temporary project (with a SharePoint site for it).

  1. Open the Team Explorer

  2. Right click in the Team Explorer the root node (i.e. the project collection)

  3. Select "New team project" from the menu

  4. Walk throught he wizard and make sure you check the option to create the portal (which is by default checked)

Step 2: Disable the site for the new project

  1. Open the Team Explorer

  2. Select the team project you created in step 1

  3. In the menu click on Team -> Show Project Portal.

  4. In the menu click on Team -> Team Project Settings -> Portal Settings...

  5. The following dialog pops up


  6. Uncheck the option "Enable team project portal"

  7. Confirm the dialog with OK

Step 3: Enable the site for the original one. Point it to the newly created site.

  1. Open the Team Explorer

  2. Select the team project you want to add the portal to

  3. In the menu open Team -> Team Project Settings -> Portal Settings...

  4. The same dialog as in step 2 pops up

  5. Check the option "Enable team project portal"

  6. Click on the "Configure URL" button

  7. The following dialog pops up

     

  8. In the dialog select in the combobox of the web application the TFS server

  9. Enter in the Relative site path the text "sites/[Project Collection Name]/[Team Project Name created in step 1]"

  10. Confirm the "Specify an existing SharePoint Site" with OK

  11. Check the "Reports and dashboards refer to data for this team project" option

  12. Confirm the dialog "Project Portal Settings" with OK

Step 4: Delete the temporary project you created.

  1. In Beta 1, I have found no way to delete a team project. Maybe it will be available in TFS 2010 Beta 2.


Original post

Step 1: Create new portal site

  1. Go to the sharepoint site of your project collection (/sites//default.aspx">http://<servername>/sites/<project_collection_name>/default.aspx)

  2. Click on the Site Actions at the left side of the screen and choose the option Site Settings

  3. In the site settings, choose the Sites and workspaces option

  4. Create a new site

  5. Enter the values for the Title, the description, the site address. And choose for the TFS2010 Agile Dashboard as template.

  6. Create the site, by clicking on the Create button

Step 2: Integrate portal site with team project

  1. Open Visual Studio

  2. Open the Team Explorer (View -> Team Explorer)

  3. Select in the Team Explorer tool window the Team Project for which you are create a new portal

  4. Open the Project Portal Settings (Team -> Team Project Settings -> Portal Setings...)

  5. Check the Enable team project portal checkbox

  6. Click on Configure URL...

  7. You will get a new dialog as below

  8. Enter the url to the TFS server in the web application combobox

  9. And specify the relative site path: sites/<project collection>/<site name>

  10. Confirm with OK

  11. Check in the Project Portal Settings dialog the checkbox "Reports and dashboards refer to data for this team project"

  12. Confirm the settings with OK (this takes a while...)

  13. When you now browse to the portal, you will see that the dashboards are now showing up with the data for the current team project.

Step 3: Download process template

  1. To get a copy of the documents that are default in a team project, we need to have a fresh set of files that are not attached to a team project yet. You can do that with the following steps.

  2. Start the Process Template Manager (Team -> Team Project Collection Settings -> Process Template Manager...)

  3. Choose the Agile process template and click on download

  4. Choose a folder to download

Step 4: Add Product and Iteration backlog

  1. Go to the Team Explorer in Visual Studio

  2. Make sure the team project is in the list of team projects, and expand the team project

  3. Right click the Documents node, and choose New Document Library

  4. Enter "Shared Documents", and click on Add

  5. Right click the Shared Documents node and choose Upload Document

  6. Go the the file location where you stored the process template from step 3 and then navigate to the subdirectory "Agile Process Template 5.0\MSF for Agile Software Development v5.0\Windows SharePoint Services\Shared Documents\Project Management"

  7. Select in the Open Dialog the files "Iteration Backlog" and "Product Backlog", and click Open

Step 5: Bind Iteration backlog workbook to the team project

  1. Right click on the "Iteration Backlog" file and select Edit, and confirm any warning messages

  2. Place your cursor in cell A1 of the Iteration backlog worksheet

  3. Switch to the Team ribbon and click New List.

  4. Select your Team Project and click Connect

  5. From the New List dialog, select the Iteration Backlog query in the Workbook Queries folder.

  6. The final step is to add a set of document properties that allow the workbook to communicate with the TFS reporting warehouse. Before we create the properties we need to collect some information about your project. The first piece of information comes from the table created in the previous step.  As you collect these properties, copy them into notepad so they can be used in later steps.

    Property How to retrieve the value?
    [Table name] Switch to the Design ribbon and select the Table Name value in the Properties portion of the ribbon
    [Project GUID] In the Visual Studio Team Explorer, right click your Team Project and select Properties.  Select the URL value and copy the GUID (long value with lots of characters) at the end of the URL
    [Team Project name] In the Properties dialog, select the Name field and copy the value
    [TFS server name]

    In the Properties dialog, select the Server Name field and copy the value

    [UPDATE] I have found that this is not correct: you need to specify the instance of your SQL Server. The value is used to create a connection to the TFS cube.

  7. Switch back to the Iteration Backlog workbook.

  8. Click the Office button and select Prepare – Properties.

  9. Click the Document Properties – Server drop down and select Advanced Properties.

  10. Switch to the Custom tab and add the following properties using the values you collected above.

    Variable name Value
    [Table name]_ASServerName [TFS server name]
    [Table name]_ASDatabase tfs_warehouse
    [Table name]_TeamProjectName [Team Project name]
    [Table name]_TeamProjectId [Project GUID]

  11. Click OK to close the properties dialog.

  12. It is possible that the Estimated Work (Hours) is showing the #REF! value. To resolve that change the formula with:

    =SUMIFS([Table name][Original Estimate]; [Table name][Iteration Path];CurrentIteration&"*";[Table name][Area Path];AreaPath&"*";[Table name][Work Item Type]; "Task")

    For example

    =SUMIFS(VSTS_ab392b55_6647_439a_bae4_8c66e908bc0d[Original Estimate]; VSTS_ab392b55_6647_439a_bae4_8c66e908bc0d[Iteration Path];CurrentIteration&"*";VSTS_ab392b55_6647_439a_bae4_8c66e908bc0d[Area Path];AreaPath&"*";VSTS_ab392b55_6647_439a_bae4_8c66e908bc0d[Work Item Type]; "Task")

  13. Also the Total Remaining Work in the Individual Capacity table may contain #REF! values. To resolve that change the formula with:

    =SUMIFS([Table name][Remaining Work]; [Table name][Iteration Path];CurrentIteration&"*";[Table name][Area Path];AreaPath&"*";[Table name][Assigned To];[Team Member];[Table name][Work Item Type]; "Task")

    For example

    =SUMIFS(VSTS_ab392b55_6647_439a_bae4_8c66e908bc0d[Remaining Work]; VSTS_ab392b55_6647_439a_bae4_8c66e908bc0d[Iteration Path];CurrentIteration&"*";VSTS_ab392b55_6647_439a_bae4_8c66e908bc0d[Area Path];AreaPath&"*";VSTS_ab392b55_6647_439a_bae4_8c66e908bc0d[Assigned To];[Team Member];VSTS_ab392b55_6647_439a_bae4_8c66e908bc0d[Work Item Type]; "Task")

  14. Save and close the workbook.

Step 6: Bind Product backlog workbook to the team project

  1. Repeat the steps for binding the Iteration backlog for thiw workbook too.

  2. In the worksheet Capacity, the formula of the Storypoints might be missing. You can resolve it with:

    =IF([Iteration]="";"";SUMIFS([Table name][Story Points];[Table name][Iteration Path];[Iteration]&"*"))

    Example

    =IF([Iteration]="";"";SUMIFS(VSTS_487f1e4c_db30_4302_b5e8_bd80195bc2ec[Story Points];VSTS_487f1e4c_db30_4302_b5e8_bd80195bc2ec[Iteration Path];[Iteration]&"*"))

Tags:

Portal | VSTS 2010

Make the description field formattable

by Ewald Hofman 4. August 2009 05:41

By default the description field in the work item definition (for example the Task work item), is plain text. To modify the type of the field to Html, you have to do the following:

Step Action
1 Open the command prompt (Run as Administrator)
2 Go to the folder %Program Files%\Microsoft Visual Studio 10.0\Common7\IDE
3

Export the work item with the following command:

witadmin exportwitd /s http:// <server> :<port>/<virtual directory>/<project collection> /p <team project> /n <work item type name> /f <location>
Example:
witadmin exportwitd /s http://MyTfsServer:8080/tfs/DefaultCollection /p TestProject /n Task /f c:\task.xml
4 Open the work item definition (in the example c:\task.xml) in Visual Studio or any other xml editor
5

Go to the FIELD

      <FIELD name="Description" refname="System.Description" type="PlainText">
        <HELPTEXT>What to do, pointers to resources and inputs, design notes, exit criteria</HELPTEXT>
      </FIELD>

6

You cannot change the type of an existing field, so just add a new field. Add a new FIELD section to the xml file:

      <FIELD name="DescriptionHtml" refname="Custom.DescriptionHtml" type="HTML">
        <HELPTEXT>What to do, pointers to resources and inputs, design notes, exit criteria</HELPTEXT>
      </FIELD>

7

Now change the field that is shown in the description textbox. Go to the section

<Control FieldName="System.Description" Type="HtmlFieldControl" Label="&amp;Description:" LabelPosition="Top" Dock="Fill" />

8

And change it to:

<Control FieldName="Custom.DescriptionHtml" Type="HtmlFieldControl" Label="&amp;Description:" LabelPosition="Top" Dock="Fill" />

9 Save the file
10

Import the new work item definintion with the command:

witadmin importwitd /s http:// <server> :<port>/<virtual directory>/<project collection> /p <team project> /f <location>
 
Example:
 
witadmin importwitd /s http://MyTfsServer:8080/tfs/DefaultCollection /p TestProject /f c:\task.xml

When you have completed the tasks, your new Task work item will look like:

 

Tags:

VSTS 2008 | VSTS 2010 | Work items

Add roles to the assigned To field

by Ewald Hofman 4. August 2009 01:28

When you create a new work item, you don't always know who exactly should pick up the work. In that case you want to introduce a role to the work item's assigned to field. To do this, you have to make a modification to the work item:

Step Action
1 Open the command prompt (Run as Administrator)
2 Go to the folder %Program Files%\Microsoft Visual Studio 10.0\Common7\IDE
3

Export the work item with the following command:

witadmin exportwitd /s http:// <server> :<port>/<virtual directory>/<project collection> /p <team project> /n <work item type name> /f <location>
Example:
witadmin exportwitd /s http://MyTfsServer:8080/tfs/DefaultCollection /p TestProject /n Task /f c:\task.xml
 
4 Open the work item definition (in the example c:\task.xml) in Visual Studio or any other xml editor
5

Go to the line

<FIELD name="Assigned To" refname="System.AssignedTo" type="String" syncnamechanges="true" reportable="dimension">
6

Change the line <VALIDUSER/> to

 <ALLOWEDVALUES expanditems="true">
 <LISTITEM value = "[Project]\Project Administrators" />
 <
LISTITEM value = "[Project]\Contributors" />
 <
LISTITEM value = "Role1" />
 
<LISTITEM value = "Role2" />
</ALLOWEDVALUES>

- The VALIDUSER shows all users that have access to TFS in the assigned to field.

- The expanditems attribute ensures that the assigned to field shows all users in the Project Administrators and the Contributors group. When you set the expanditems to false, then the users will not be shown, but only the 4 above groups/roles

- The [Project]\... lines adds the users in those groups to the assigned to field

- The Role1 and Role2 are new roles that are available

7 Save the file
8

Import the new work item definintion with the command:

witadmin importwitd /s http:// <server> :<port>/<virtual directory>/<project collection> /p <team project> /f <location>
 
Example:
 
witadmin importwitd /s http://MyTfsServer:8080/tfs/DefaultCollection /p TestProject /f c:\task.xml

Tags:

VSTS 2010 | Work items

Change the file masks that are excluded by Source Control

by Ewald Hofman 2. August 2009 22:32

When you add files to Source Control, some of the files are excluded automatically, such as dll files.

 

You can change the default setting by modifying one of the following registry keys:

Per-User: HKCU\Software\Microsoft\VisualStudio\<version>\TeamFoundation\SourceControl\AddOptions
Per-Machine: HKLM\Software\Microsoft\VisualStudio\<version>\TeamFoundation\SourceControl\AddOptions

where <version> is the VS version:
For TFS2008 “9.0”
For TFS2010 "10.0"
 
If the value is not already there, add a string value titled “ExcludeMasks” and set it to the exclusion list you would like to use.  If this value if found, it overrides the built-in defaults.

 

Tags:

Version Control | VSTS 2008 | VSTS 2010

Reports do not show the latest data in TFS 2010 Beta 1

by Ewald Hofman 31. July 2009 00:08

There is in the Beta 1 version a bug that blocks processing the OLAP cube when you install a fresh instance of TFS 2010. This issue is solved in Beta 2.

To workaround this, do the following:

  1. In a browser navigate to this URL: http://<servername>:<port">http://<servername>:<port number>/<virtual directory>/_tfs_resources/warehouse/v1.0/warehousecontroller.asmx

    Where it says <servername> enter the name of your Team Foundation Server. Where it says, <port number> enter the port number where Team Foundation Server listens for requests. By default this is 8080. Where it says <virtual directory>, enter the virtual directory for Team Foundation Server. Upgraded servers typically will not use the virtual directory, for fresh installs this is typically "tfs".
  2. Click UnblockOlapProcessing and then click Invoke
  3. Process the warehouse (ProcessWarehouse)
  4. Check GetWarehouseStatus() to make sure the adapters are done – refresh the results page till it goes from ProcessingAdapters to Idle
  5. ProcessOlap() with processing type ‘Full’
  6. Check GetWarehouseStatus() and wait for it to go from ProcessingOlap to Idle

 More information can be found in section 2.5.2 of the readme doc (http://download.microsoft.com/download/7/A/0/7A023209-096F-4F7D-B2BC-831ECC68FF5B/TFS2010Beta1Readme.html)

Tags:

VSTS 2010

Create Team Project failure

by Ewald Hofman 24. June 2009 22:47

When I created a Team Project under the same account as the TFS installation was performed, I was able to create a new team project.

Unfortunately, I got an error message that I did not have enough rights:

---begin Exception entry---
Time: 2009-06-23 09:28:24Z
Module: WSS
Exception Type: Microsoft.TeamFoundation.TeamFoundationServerUnauthorizedException
Exception Message: TF30063: You are not authorized to access http://<TFS SERVER>:17012/_vti_bin/TeamFoundationIntegrationService.asmx.
Stack Trace:
   at Microsoft.TeamFoundation.Client.TeamFoundationClientProxyBase.ProcessHttpResponse(HttpWebResponse response, Stream responseStream, WebException webException, XmlReader& xmlResponseReader)
   at Microsoft.TeamFoundation.Client.TeamFoundationClientProxyBase.ExecWebServiceRequest(HttpWebRequest request, XmlWriter requestXml, String methodName, HttpWebResponse& response)
   at Microsoft.TeamFoundation.Client.SharePoint.SharePointTeamFoundationIntegrationService.ActivateFeatureById(String siteUrl, Guid featureId)
   at Microsoft.VisualStudio.TeamFoundation.WssSiteCreator.HandleFeatureActivation(WssCreationContextWrapper contextWrapper, XmlNode features)
--   Inner Exception   --
Exception Type: System.Net.WebException
Exception Message: The remote server returned an error: (401) Unauthorized.
WebException: Response Status Code: Unauthorized
WebException: Response already disposed, no additional information available.
WebException: Status : ProtocolError
Stack Trace:
   at System.Net.HttpWebRequest.GetResponse()
   at Microsoft.TeamFoundation.Client.TeamFoundationClientProxyBase.AsyncWebRequest.ExecRequest(Object obj)
-- end Inner Exception --
--- end Exception entry ---

Finally managed to solve the issue by adding my user account to the web application policies. You can find these in the Sharepoint Central Administration (http://<TFSServer>:17012).

Go to the tab Application Management and choose there the option Policy for Web Application. Then add your user account that creates the team project.

Tags:

VSTS 2010

Project Velocity calculation in VSTS 2010 Beta 1

by Ewald Hofman 2. June 2009 12:41

To calculate the project velocity, TFS summarizes all remaining work of all work item types in the iteration. Imagine you have a breakdown of work items, such as at the top level a User Story, which is broken down into Tasks.

The project velocity should be calculated by summarizing the Remaining Work of all tasks. But when you open the work breakdown in MS Project and publish the results, the Remaining Work is also stored in the User Story. This causes that the Project Velocity is doubled.

Microsoft has confirmed that this is a bug in Beta 1. It will be solved in Beta 2.

Tags:

VSTS 2010

Retrieve historical data in Iteration Backlog

by Ewald Hofman 28. May 2009 03:21

I have installed on Windows XP the Visual Studio 2010 Team System Beta 1. When playing around with the iteration Backlog workbook, I was unable to retrieve the Historical Data. The VB editor popup up with the following error.

When looking at the references of the workbook, it was indicating that there was an invalid reference for the workbook.

 

The issue was solved by removing the reference and add the same file (c:\program files\common files\system\ado\msadomd.dll) again.

 

Now I am able to Retrieve the Historical data again.

Tags:

VSTS 2010

TFS 2010 Beta 1 installation

by Ewald Hofman 19. May 2009 05:43

Since a few days, the first beta of TFS 2010 is released. The installation went very smooth. Microsoft has put a lot of effort in the installation experience of TFS.

I choose the run Default Configuration wizard. At my installation on Windows Server 2008 there were some caveats:

1) The Readiness Checks told me that IIS should run in Compatibility Mode. You can install the compatibility mode as follows:

  1. Open Server Manager
  2. Clicked Web Server (IIS) in the role summary
  3. Add Role Services
  4. Checked IIS 6 Management Compatibility

2) The second blocking issue was around SSRS that was not configured correctly. You can configure SSRS correctly by opening SSRS with the link in the first screen op the TFS Configuration.

  1. Choose the Web Service URL in the bar at the left. Accept the default values by clicking on Apply
  2. Choose the Report Manager URL in the bar at the left. Accept the default values by clicking on Apply
  3. You now have to restart the Wizard, because otherwise the wizard does not pick up the new configuration

Tags:

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
1949240 visit (1042 per day)
16 users online

Recent comments

Comment RSS