TFS2010 - Queuing a Build (from code) With Custom Process Parameter Values

I got a question today on how to access the process parameters of a build definition in 2010. If you haven’t looked at that property, yet, you might be surprised to find out it is just a string. Unfortunately, we chose to do it this way for various reasons. It would more naturally be a dictionary of name value pairs. Well, in fact, it is just that. We simply took the dictionary and serialized it into a string.

So, the question becomes… How do I deserialize this thing change it and serialize it back into a definition, build request, or other objects that it hangs off of?

The easiest thing to do is simply show you the code. In this example, I am queuing a build from code and setting the Verbosity process parameter to Diagnostic. Here’s the code:

 using System;
using System.Collections.Generic;
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.Build.Workflow;
using Microsoft.TeamFoundation.Client;

namespace ManageBuildTemplates
{
    class Program
    {
        static void Main(string[] args)
        {
            TfsTeamProjectCollection collection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri("https://jpricket-test:8080/tfs/collection0"));
            IBuildServer buildServer = collection.GetService<IBuildServer>();

            IBuildDefinition definition = buildServer.GetBuildDefinition("UnitTests", "Definition1");

            IBuildRequest request = definition.CreateBuildRequest();
            request.ProcessParameters = UpdateVerbosity(request.ProcessParameters, BuildVerbosity.Diagnostic);

            buildServer.QueueBuild(request);
        }

        private static string UpdateVerbosity(string processParameters, BuildVerbosity buildVerbosity)
        {
            IDictionary<String, Object> paramValues = WorkflowHelpers.DeserializeProcessParameters(processParameters);
            paramValues[ProcessParameterMetadata.StandardParameterNames.Verbosity] = buildVerbosity;
            return WorkflowHelpers.SerializeProcessParameters(paramValues);
        }
    }
}

In the example you can see that the UpdateVerbosity method does the deserialization and serialization using the WorkflowHelpers class. These are public methods and they are the same ones we use internally.

Note that if you want to add custom types as process parameters, they MUST be serializable using the XAML serialization engine.

Code away!

UPDATE:

I should have mentioned this the first time, but here is some additional information you may want to know about process parameters. Values for process parameters exist in several places: in the XAML template as default values, on the definition, as part of the build request (seen here), and eventually on the build detail. So, which values matter? When the build machine loads the process template (XAML) it first overrides any process parameter values with the values from the definition. Therefore, if you assign a value to a process parameter on the definition (this will bold the value in the property grid of the definition), the definition value will be used. The build machine then overrides the process parameter values with the value from the build request. So, if you specified a value in the XAML, in the definition, and in the build request, ONLY the value in the build request will be used.

And now to answer the original question: Why are the build request process paramters empty? Shouldn't they be a copy of the definition? To save on space (and for other reasons), only the values overriden at each level are saved at that level. We don't copy the values from the XAML to the definition, or from the definition to the process parameters. So, if you wanted to change the value of a process parameter based on the value already stored on the definition in the above example, you would deserialize the definition's process parameters instead of the build request's.