TFS BuildHttpClient UpdateDefinition C# example

team-foundation-server

I need to update a vNext Build Definition programmatically. The reason for the need to programmatically update the build definition is that we are running the RTM version of Team Foundation Server 2015, and as of that release certain parts of the vNext Build Definitions are not exposed to the web GUI, and there is (as yet) no other way to change them. (Assuming that you want to keep your database in a supported state, and refuse to modify the database directly.)

Our corporate environment and all machines recently went through a domain change. The TFS server was moved to the new domain with no issues. However, the vNext Build definition has an internal reference to the old server name in the URL field, which still has the old domain name inside it.

So far, I have the following code which should update the URL of each build definition of a certain project. The call to GetDefinitonsAsync clearly returns the proper build DefinitionReferences to me, but UpdateDefinitionAsync does not seem to have any effect.

   List<DefinitionReference> bds = new List<DefinitionReference>();
.
.
.
   {
        Uri tfsURI = new Uri("http://<tfsserver>:8080/tfs/<collection>");
        WindowsCredential wc = new WindowsCredential(true);
        BuildHttpClient bhc = new BuildHttpClient(tfsURI, new VssCredentials(wc));

        var task = Task.Run(async () => { bds = await bhc.GetDefinitionsAsync(project: "projectname"); });
        task.Wait();

        foreach (var bd in bds)
        {
            BuildDefinition b = (BuildDefinition)bd;
            b.Url = b.Url.Replace("<server>.<olddomain>", "<server>.<newdomain>");

            var task1 = Task.Run(async () => { await bhc.UpdateDefinitionAsync(b); });
            task1.Wait();
        }

    }

This code snippet compiles and runs without error. However, when I examine the build definition afterward, it has not been updated and remains as before. There are no exceptions seen by the debugger, and there are no event viewer or DebugView messages of relevance.

Regarding the above code snippet, I am uncertain about whether I am suppose to obtain the BuildDefinition that I need to pass to UpdateDefinition by casting the DefinitionReference (subclass) to BuildDefinition or not, but I see nothing close in the BuildHttpClient class that will give me a BuildDefiniton from a DefinitonReference.

Any help would be appreciated. Thanks!

Best Answer

To elaborate on my last comment with code,

public partial class Form1 : Form
{
    List<DefinitionReference> bds = new List<DefinitionReference>();
    List<BuildDefinitionRevision> bdrs = new List<BuildDefinitionRevision>();
    Dictionary<string, BuildDefinition> defs = new Dictionary<string, BuildDefinition>();

    public Form1()
    {
        InitializeComponent();

        //Connect to TFS vNext API
        Uri tfsURI = new Uri("http://<servername>:8080/tfs/<collectionname>");
        WindowsCredential wc = new WindowsCredential(true);
        Microsoft.TeamFoundation.Build.WebApi.BuildHttpClient bhc = new Microsoft.TeamFoundation.Build.WebApi.BuildHttpClient(tfsURI, new VssCredentials(wc));

        //Populate builddefinitionreference list for the project
        var task = Task.Run(async () => { bds = await bhc.GetDefinitionsAsync(project: "<projectname>"); });
        task.Wait();

        foreach (var bd in bds)
        {
            Log(bd.Revision.ToString());
            Log(bd.Url);

            //Populate the definition revision reference list for this one build definition
            var task1 = Task.Run(async () => { bdrs = await bhc.GetDefinitionRevisionsAsync(project: bd.Project.Id, definitionId: bd.Id); });
            task1.Wait();

            //Go through the revisions of this one builddefinition.   In this case I am only interested
            //In updating the latest revision so I'm saving a copy of the last one.
            string LastDefinitionUrl = "";
            foreach (var bdr in bdrs)
            {
                Log(string.Format("Name: {0}, Revision: {1}, Comment: {2}, Url: {3}", bdr.Name, bdr.Revision, bdr.Comment, bdr.DefinitionUrl));
                LastDefinitionUrl = bdr.DefinitionUrl;
            }

            //Get the JSON for the complete BuildDefinition class.   The list above only contains
            //DefinitonReference class.
            var client = new WebClient();
            client.UseDefaultCredentials = true;
            var json = client.DownloadString(LastDefinitionUrl);

            //Convert the JSON to an actual builddefinition
            BuildDefinition result = JsonConvert.DeserializeObject<BuildDefinition>(json);

            //modify result here, if desired...

            //Save the builddefinition classes in a dictionary for this project as I construct them
            defs.Add(bd.Name, result);

            //Save the changes.  (i.e. this creates a new revision)
            var task2 = Task.Run(async () => { await bhc.UpdateDefinitionAsync(result, definitionId: bd.Id, project: bd.Project.Id); });
            task2.Wait();
        }

}

Related Topic