TFS 2015 clone/import/export build definition between team projects
By Mirek on (tags: build definition, clone, tfs, VSO, categories: tools, infrastructure, code)While exploring features of the new Visual Studio Team Foundation Server 2015 I found that it is not possible to reuse a build definition created in one team project into another team project. Since this is a feature that I am going to use frequently, well, every time I start a new project, this is a must have functionality. In this post I will give you a complete solution I’ve came up with.
This is by the way quite strange that you have a possibility to save build definition as a template for future use, but such template is then available only in the same team project. So basically it is usefull when you are going to have many build definitions in one team project. But when you want to reuse a build definition in other projects, because for instance you use many build steps, many variables and setting and many of them are the same for all of your projects, then you have to deal with this limitation.
Fortunatelly the Visual Studio Online and TFS 2015 comes with Team Services API which you can access and which allows you to programatically perform various actions on your build system. It also allows you to manage all build definitions. There are .net libraries created by Microsoft which facilitates working with the api and which I am going to use.
Lets create new console app project in Visual Studio 2015, name it TfsCloneBuildDef and add following nuget pakages
Microsoft.TeamFoundationServer.Client
Microsoft.VisualStudio.Services.Client
When I wrote this post both of above packages are available in stable version of 14.89.0. Now we can implement our application. For the sake of the simplicity I will skip negligible code and focus on the most important part, as you can download whole solution from the attachement of this post. So the core method which will clone the build definition will look like this
1: var cred = new VssCredentials(new WindowsCredential(new NetworkCredential(username, password)));
2: var buildClient = new BuildHttpClient(new Uri(collectionURL, UriKind.Absolute), cred);
3:
4: var buildDef = (await buildClient.GetDefinitionAsync(sourceProj, buildDefId)) as BuildDefinition;
5:
6: buildDef.Project = null;
7: buildDef.Name += "_clone";
8:
9: await buildClient.CreateDefinitionAsync(buildDef, targetProj);
In the first line the credentials to the team server are created. Here you must provide your TFS user and password. Next we build a BuildHttpClient providing the projects collection url and the credentials object. The url should be in form like this one http://mytsfserver:8080/tfs/DefaultCollection. Then in line number 4 we retreive the build definition object from the source project providing the project name and the build definition id. Where to get the build definition id from? Well, you can easilly read it from the url when you select the build definition in VSO web portal. For instance here: ../tfs/DefaultCollection/TestProject/_build#definitionId=6&_a=completed the definition id is 6.
In the next step we change the name of the build definition so it is clearly seen that this is a clone. We also need to remove the reference to the project. Since build definition contains a reference to the project it would not be possible to import it into a different project. Finally we create new build definition in target project providing the definition object we retreived from previous project.
Important note: the build definition contains more project specific settings which you will need to change manually in the VSO by editing the build definition. This is for instance Repository section
or the Triggers section
But we can handle this automatically as well, which I will show you later.
Now we can test our application. Let’s assume I have team project called TestProject with a build definition with name dev and id equal 6. I also have project called TestProject2 which I want to have the same build definition as the former one. Then all I need is to do this
TfsCloneBuildDef.exe http://mytfsserver:8080/tfs/DefaultCollection "user" "pass" "TestProject" "TestProject2" 6
And when I check the build definitions in TestProject2 there is new build definition called dev_clone. That’s it.
The next step is to export the build definition to a file so we can latter import it. That would be nice so we can have sort of backup for the build definitions or we could even import it in a different build server later on. Since BuildDefinition object is a part of api it is well serializable and we are going to use this property. Lets break the method, which we used to clone the build definitions between two projects, in two methods. One will be the export and he second will be the import part. Also let's use a json serializer to serialize the build definition and save it to a file.
1: var buildDef = (await buildClient.GetDefinitionAsync(project, buildDefId)) as BuildDefinition;
2: buildDef.Project = null;
3: File.WriteAllText(filePath, JsonConvert.SerializeObject(buildDef));
Quite easy, isn’t it? Now we can add an import method as well.
1: if (!File.Exists(filePath))
2: throw new FileNotFoundException("File does not exist!", filePath);
3: Console.WriteLine($"Importing build definition from file '{filePath}' to '{project}' project.");
4: var buildDef = JsonConvert.DeserializeObject<BuildDefinition>(File.ReadAllText(filePath));
5: buildDef.Name = newBuildName;
6: await buildClient.CreateDefinitionAsync(buildDef, project);
Sajan
5/6/2017 4:25 AM
Hi, Thanks for the example above. I'm looking at cloning the build & release definition in vs2017 and I was able to follow your example and all works fine, but the artifacts link to source [from release def] is not getting set and throws exception as Bad request when i try to set it. Step-1: I clone a build definition, change the name post it back, store the new build-id for step2 Step-2: I clone a release definition, change name and other properties, but it does not allow me this below clonedef.artifacts[0].definitionReference.artifactSourceDefinitionUrl.name = appName; clonedef.artifacts[0].definitionReference.definition.id = newBuildDefId.ToString(); // ERROR Any help is appreciated. thanks, SMHari
7/30/2018 4:13 PM
Thanks for sharing code with Clone Build defintion in TFS 2015. Can you share sample for Clone Release defnintions in TFS 2015? I couldn't find clone release defintion anywhere?Tom
2/8/2019 1:20 AM
Thanks for the code, however - it appears that this does not clone the steps, or I could be missing something. Been searching for days trying to resolve this. I came across this thread https://translate.googleusercontent.com/translate_c?depth=1&hl=en&prev=search&rurl=translate.google.com&sl=pt-BR&sp=nmt4&u=https://dennisdel.com/blog/getting-build-steps-with-visual-studio-team-services-.net-api/&xid=17259,15700002,15700022,15700186,15700191,15700248&usg=ALkJrhiLTEaHs6IwweUVvyznIVF52YPSGw but still have had no luck cloning the steps. In my case, I'm just trying to clone the build defs to build from a release branch so the only thing I need to change is the build def name and the source code location to a new branch.Tom
2/8/2019 1:25 AM
That link in my last post goes nowhere...google: DEN DELIMARSKY "GETTING BUILD STEPS WITH VISUAL STUDIO TEAM SERVICES .NET API" and he shows the namespaces but I'm not sure how to implement it.