Search code examples
azure-devopsazure-pipelinesazure-pipelines-build-taskpicklist

Populate picklist dynamically based on filepath type in Azure Devops?


In Azure Devops, I am building one extension with build task where input picklist field is dependent on the another input filepath field. When the user provides an input filepath, I wanted to dynamically read and populate the picklist with new items. I tried to search and implement but couldn't find a way. Any help or guidance will be appreciated. I found the below example to help me out for static values.

{
   "name": "action",
   "type": "pickList",
   "label": "Action",
   "defaultValue": "Publish",
   "required": true,
   "helpMarkDown": "Select the Action to perform",
   "options": {
     "Publish": "Publish Changes",
     "Script": "Script Changes",
     "DeployReport": "Generate Deployment Report"
   }
 }

Solution

  • The out-of-box tasks are open source, so you can take a look through the repository to get some ideas of the patterns they use. Here is an example from the Download Build Artifacts task. The build definition is dependent on the project that is defined.

    {
            "name": "project",
            "type": "pickList",
            "label": "Project",
            "defaultValue": "",
            "required": true,
            "visibleRule": "buildType == specific",
            "properties": {
                "EditableOptions": "True",
                "DisableManageLink": "True"
            },
            "helpMarkDown": "The project from which to download the build artifacts"
        },
        {
            "name": "definition",
            "aliases": [
                "pipeline"
            ],
            "type": "pickList",
            "label": "Build pipeline",
            "defaultValue": "",
            "required": true,
            "visibleRule": "buildType == specific",
            "properties": {
                "EditableOptions": "True",
                "DisableManageLink": "True",
                "IsSearchable": "True"
            },
            "helpMarkDown": "Select the build pipeline name"
        },
    

    Then in the dataSourceBindings section believe it uses the target from the previous selection as a parameter input.

    "dataSourceBindings": [
        {
            "endpointId": "tfs:teamfoundation",
            "target": "project",
            "endpointUrl": "{{endpoint.url}}/_apis/projects?$skip={{skip}}&$top=1000",
            "resultSelector": "jsonpath:$.value[?(@.state=='wellFormed')]",
            "resultTemplate": "{ \"Value\" : \"{{{id}}}\", \"DisplayValue\" : \"{{{name}}}\" }",
            "callbackContextTemplate": "{\"skip\": \"{{add skip 1000}}\"}",
            "callbackRequiredTemplate": "{{isEqualNumber result.count 1000}}",
            "initialContextTemplate": "{\"skip\": \"0\"}"
        },
        {
            "endpointId": "tfs:teamfoundation",
            "target": "definition",
            "endpointUrl": "{{endpoint.url}}/{{project}}/_apis/build/definitions?api-version=3.0-preview&$top=500&continuationToken={{{continuationToken}}}&name=*{{name}}*&queryOrder=2",
            "resultSelector": "jsonpath:$.value[?(@.quality=='definition')]",
            "parameters": {
                "project": "$(project)",
                "name": "$(name)"
            },
            "resultTemplate": "{ \"Value\" : \"{{{id}}}\", \"DisplayValue\" : \"{{{name}}}\" }",
            "callbackContextTemplate": "{\"continuationToken\" : \"{{{headers.x-ms-continuationtoken}}}\"}",
            "callbackRequiredTemplate": "{{{#headers.x-ms-continuationtoken}}}true{{{/headers.x-ms-continuationtoken}}}",
            "initialContextTemplate": "{\"continuationToken\" : \"{{{system.utcNow}}}\"}"
        },