Writing a ReleaseManagement extension for cloning an existing release definition

Code shared :- https://github.com/openalm/vsts-rm-extensions/tree/master/rd-export-import-clone-TFS2015U2

How to make Changes:-

Step1: Clone the repository using the link https://github.com/openalm/vsts-rm-extensions.git

Step2: Open a command prompt and go till folder 'rd-export-import-clone-TFS2015U2'

Step3: Run 'bower install' [ pre-requsite for running 'bower' can be referred https://github.com/Microsoft/vsts-extension-samples] which will download 1.95.2 version of VSS.SDK.js

Step4: Make your changes

Step5:  Run 'tfx extension create' to generate .vsix package in the current directory.  [Refer 'Try the extension in Visual Studio Team Services' section https://github.com/Microsoft/vsts-extension-samples]

Step6: Done!!!!

How to add 'Clone' as contextmenu item for ReleaseDefinition

[A generic how to add item in context menu is explained https://www.visualstudio.com/en-us/integrate/extensions/develop/add-action, below steps will explain similarly in context of ReleaseManagement]

Changes required  in vss-extension.json [ Refer above shared code ]

Step1: Add below as "scopes" in vss-extension.json  [Read more about ReleaseManagement scopes under 'Scopes' section in https://www.visualstudio.com/en-us/integrate/extensions/develop/manifest

"scopes": ["vso.release_execute"]

Step2: As we wanted to add one more item in the release definition context menu hence we will add one contribution (as below) in the vss-extension.json targeting "ms.vss-releaseManagement-web.release-definition-explorer-toolbar-menu" [ to learn more release management contribution point refer https://www.visualstudio.com/integrate/extensions/reference/targets/overview ]

{
"id": "importDefinitionToolbarMenu",
"type": "ms.vss-web.action",
"description": "Import definition(s) menu",
"targets": [
"ms.vss-releaseManagement-web.release-definition-explorer-toolbar-menu"
],
"properties": {
"title": "Import release definition",
"icon": "images/icon-import-16.png",
"group": "actions",
"uri": "main.html"
}
}

===========================

Note:-   In case you are calling RM REST API from any contribution point outside RM hub then you may either of two approach :-

Approach1:- Add '"includes": [ "ms.vss-releaseManagement-web.release-service-data-external" ],' as well. Refer the link https://github.com/Microsoft/vss-web-extension-sdk/issues/35 

This will cause RM account to be provisioned.

Approach2:- Add

"properties": {

"content": {

"contributionIds": ["ms.vss-releaseManagement-web.release-service-data-external"]

}

Approach2 is the recommended way and will work for VSTS and TFS2018 onwards.

===========================

Changes required  in main.js [ Refer method cloneDefinitionContextMenu() in above shared code ]

Step1:- Create a rmClient using

var rmClient = VSS_Service.getCollectionClient(RM_WebApi.ReleaseHttpClient);

Step2: Make a getReleaseDefinition() call to get the definition object for the given id

rmClient.getReleaseDefinition(vsoContext.project.id,sourceItemContext.definition.id)

Step3: Update the definition name

definition.name = newDefinitionName;

Step4: Create a new definition using updated definition object in Step#3 above

rmClient.createReleaseDefinition(definition, vsoContext.project.id)

Step5: Refresh the UI to show the newly created definition

sourceItemContext.view.refresh();

Step6: Done!!!!

 

Complete code for quick reference :-

 var cloneDefinitionContextMenu = (function () {
    "use strict";

    return {
        execute: function (sourceItemContext) {
            // Load VSTS controls and REST client
            VSS.require(["VSS/Controls", "VSS/Service", "ReleaseManagement/Core/RestClient"],
            function (Controls, VSS_Service, RM_WebApi) {
                var newDefinitionName = prompt("New definition name:", sourceItemContext.definition.name + " - Copy");
                if (newDefinitionName != null)
                {
                    sourceItemContext.view.logMessage("Creating " + newDefinitionName + "...");
                    var vsoContext = VSS.getWebContext();
                    // Get a RM client to make REST calls
                    var rmClient = VSS_Service.getCollectionClient(RM_WebApi.ReleaseHttpClient);
                    rmClient.getReleaseDefinition(vsoContext.project.id,sourceItemContext.definition.id).then(function(definition){
                        definition.name = newDefinitionName;
                     rmClient.createReleaseDefinition(definition, vsoContext.project.id).then(() => {
                            sourceItemContext.view.refresh();
                            sourceItemContext.view.logMessage("Cloned \'"+ sourceItemContext.definition.name +"\' and created \'" + newDefinitionName + "\'");
                        }, function(error){
                            sourceItemContext.view.logError(error);
                        });
                    }, function(error){
                        sourceItemContext.view.logError(error);
                    });
                }
            });
        }
    }
}());