How get the latest value in pick list - azure-devops

I'm trying to develop an extension/pipeline task for Azure DevOps for release gates. Not getting how to bind the the latest value to the pick list as shown here:
Each time a build completes, pick list should have latest build Id as the selected value.
Here is the code snippet i tried,
This creates a pick list
{
"name": "buildId",
"type": "pickList",
"label": "Artifact",
"required": true,
"defaultValue": "Latest",
"properties": {
"DisableManageLink": "True",
"EditableOptions": "True"
}
"helpMarkDown": "Build Artifacts"
},
this binds the values for the picklist
{
"target": "buildId",
"endpointId": "tfs:teamfoundation",
"endpointUrl": "{{endpoint.url}}/{{system.teamProject}}/_apis/build/builds?api-version=5.0",
"resultSelector": "jsonpath:$.value[*]",
"resultTemplate": "{ \"Value\" : \"{{{id}}}\", \"DisplayValue\" : \"{{{buildNumber}}} \" }"
}
Let me know if there are any way to get this.

I afraid you will need to implement your own code methods to bind latest value to the latest buildid.
For example in Publish build artifacts task. The latest build id is retrieved according to the selected value(ie. latest) of field buildVersionToDownload: See below:
buildVersionToDownload has three options.
{
"name": "buildVersionToDownload",
"type": "pickList",
"label": "Build version to download",
"defaultValue": "latest",
"visibleRule": "buildType == specific",
"required": true,
"options": {
"latest": "Latest",
"latestFromBranch": "Latest from specific branch and specified Build Tags",
"specific": "Specific version"
}
}
If the buildVersionToDownload value is selected as specific. Then it is required to select the build id in the Build picklist.
{
"name": "buildId",
"type": "pickList",
"label": "Build",
"defaultValue": "",
"required": true,
"visibleRule": "buildType == specific && buildVersionToDownload == specific",
"properties": {
"EditableOptions": "True",
"DisableManageLink": "True"
},
"helpMarkDown": "The build from which to download the artifacts"
}
buildVersionToDownload is not bound to dataSource, only buildId is bound:
{
"endpointId": "tfs:teamfoundation",
"target": "buildId",
"endpointUrl": "{{endpoint.url}}/{{project}}/_apis/build/builds?definitions={{definition}}&resultFilter=succeeded,partiallySucceeded&$top=200",
"resultSelector": "jsonpath:$.value[*]",
"parameters": {
"project": "$(project)",
"definition": "$(definition)"
},
"resultTemplate": "{ \"Value\" : \"{{{id}}}\", \"DisplayValue\" : \"{{{buildNumber}}}\" }"
}
See here for more information.
If buildVersionToDownload is selected as latest. Then the latest build id is retrieved via code. See code example here
So that in your custom task. When the Default Version is latest. You can get the latest build id in your code methods. And when Default Version is not latest. Then make the Artifact visible to select a build id from the picklist.

Related

Arm template deployment fail with 409 error for one specific storage account

I use arm template to deploy a storage account. However, I got an error saying: StorageAccountAlreadyExists: The storage account named xxx already exists.
My release pipeline is set to incremental, so shouldn't really show this error.
I changed storage account name to a new one, not only it worked the first time, but I can keep on deploying the same pipeline and no error ever thrown out.
Looks like it is something specific to this account, however, I can't see anything special. The arm template we use is also quite normal (something we got from official examples before).
{
"$schema": "http://schema.management.azure.com/schemas/2019-06-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"StorageDescriptor": {
"type": "string",
"defaultValue": "StorageAccount",
"metadata": {}
},
"StorageAccountName": {
"type": "string",
"defaultValue": "[toLower(concat(parameters('StorageDescriptor'), resourceGroup().name))]",
"metadata": { "Description": "Override name for the storage account" }
},
"StorageType": {
"type": "string",
"defaultValue": "Standard_LRS",
"allowedValues": [
"Standard_LRS",
"Standard_ZRS",
"Standard_GRS",
"Standard_RAGRS",
"Premium_LRS"
]
},
"Environment": {
"type": "string",
"defaultValue": "PreProd",
"metadata": { "description": "PreProd or Prod" }
}
},
"variables": {
},
"resources": [
{
"name": "[parameters('StorageAccountName')]",
"type": "Microsoft.Storage/storageAccounts",
"location": "[resourceGroup().location]",
"apiVersion": "2019-06-01",
"dependsOn": [],
"tags": {
"displayName": "Web Job Storage Account"
},
"properties": {
"accountType": "[parameters('StorageType')]"
}
}
],
"outputs": {
}
}
Even though your release pipeline is set to incremental, the storage account name must be unique every time you deploy. Refer to: here.
Arm template deployment fail with 409 error for one specific storage account
You need to check if the storage account attributes have been changed through the Azure/PowerShell portal by somebody else, and are different than the ones specified on the ARM template.
To resolve this issue, please try to export the template and update it in the Azure devops repo:
Then, we could update this new exported template file as you want and deploy with it.
As test, I could keep on deploying the same pipeline and no error ever thrown out.

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"
}
}
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}}}\"}"
},

Task.Json triggers validation on invisible only fields

I am trying to create a Azure DevOps Pipelines Custom extension. I have a task.json where fields are visible on certain conditions.
For example:
{
"name": "actions",
"type": "picklist",
"label": "Actions",
"defaultValue": "Select",
"required": true,
"helpMarkDown": "Select an Action from the dropdown as per your requirement.",
"options": {
"New": "Add",
"Delete": "Delete"
}
},
{
"name": "backEndIPAddress",
"type": "string",
"label": "IP Address",
"required": true,
"defaultValue": "",
"helpMarkDown": "",
"visibleRule": "actions = New",
"validation": {
"expression": "isMatch(value,'^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?){0,15}$','IgnoreCase')",
"message": "Invalid IP Address. Please try again!"
}
}
The issue when the IPAddress field is hidden, the validation is still tried and it fails. How to ensure that the fields are validated only if they are visible?
A few options:
Set a default value for the input
Update the regex to include ^$| at the start to allow empty values ('require':true will take care of the requiredness)
Remember that there should be a default isIpV4Address(value: string) function so you don't have to specify the regex.
From the docs it looks like there is an upcoming when clause which will dictate when the set of rules should trigger, I suppose this may be causing the currently unwanted behavior.
See also:
https://github.com/Microsoft/vsts-tasks/blob/1d75fa8f66aa1cf7a9cb62946939f30f087b2969/docs/taskinputvalidation.md

TFS 2015 Rest API - Create Build Definition

I'm trying to create a build definition in TFS using his api rest for it.
This is the microsoft docs for TFS Api Rest
I get status code 200 but...
This is what i get when I look into Tfs build definition
Anyone knows why this is happening?
Your second link provided a screenshot that a build definition with no tasks. It seems you had created a build definition successfully, but you didn't add tasks in the build definition.
Check your rest api to see whether you have "build": [] parameter with "task" in it as the following example shows:
"build": [
{
"enabled": true,
"continueOnError": false,
"alwaysRun": false,
"displayName": "Build solution **\\*.sln",
"task": {
"id": "71a9a2d3-a98a-4caa-96ab-affca411ecda",
"versionSpec": "*"
},
"inputs": {
"solution": "**\\*.sln",
"msbuildArgs": "",
"platform": "$(platform)",
"configuration": "$(config)",
"clean": "false",
"restoreNugetPackages": "true",
"vsLocationMethod": "version",
"vsVersion": "latest",
"vsLocation": "",
"msbuildLocationMethod": "version",
"msbuildVersion": "latest",
"msbuildArchitecture": "x86",
"msbuildLocation": "",
"logProjectEvents": "true"
}
},
{
"enabled": true,
"continueOnError": false,
"alwaysRun": false,
"displayName": "Test Assemblies **\\*test*.dll;-:**\\obj\\**",
"task": {
"id": "ef087383-ee5e-42c7-9a53-ab56c98420f9",
"versionSpec": "*"
},
"inputs": {
"testAssembly": "**\\*test*.dll;-:**\\obj\\**",
"testFiltercriteria": "",
"runSettingsFile": "",
"codeCoverageEnabled": "true",
"otherConsoleOptions": "",
"vsTestVersion": "14.0",
"pathtoCustomTestAdapters": ""
}
}
],

TFS 2015.3 custom build step not sending variables to the script

I've followed closely the design guidance found here, here and here, but I keep getting this PowerShell error:
Cannot process command because of one or more missing mandatory parameters: SourcePath FilePattern BuildRegex.
The relevant config data is below.
I've checked and double-checked to make sure that the variables are present in my task.json file. I've also looked at the config for other working tasks (e.g. VSBuild) and there's no significant difference in the variable declaration and PowerShell execution syntax.
What could be going wrong here? This is a very simple architecture—there's not much to break. But clearly something has done just that.
From task.json:
"inputs": [
{
"name": "SourcePath",
"type": "filePath",
"label": "Source path",
"defaultValue": "",
"required": true,
"helpMarkDown": "Path in which to search for version files (like AssemblyInfo.* files). NOTE: this is case sensitive for non-Windows systems."
},
{
"name": "FilePattern",
"type": "string",
"label": "File pattern",
"defaultValue": "AssemblyInfo.*",
"required": true,
"helpMarkDown": "File filter to replace version info. The version number pattern should exist somewhere in the file(s). Supports minimatch. NOTE: this is casese sensitive for non-Windows systems."
},
{
"name": "BuildRegEx",
"type": "string",
"label": "Build RegEx pattern",
"defaultValue": "\\d+\\.\\d+\\.\\d+\\.\\d+",
"required": true,
"helpMarkDown": "Regular Expression to extract version from build number. This is also the default replace RegEx (unless otherwise specified in Advanced settings)."
},
{
"name": "BuildRegExIndex",
"type": "string",
"label": "Build RegEx group index",
"defaultValue": "0",
"required": false,
"helpMarkDown": "Index of the group in the Build RegEx that you want to use as the version number. Leave as 0 if you have no groups.",
"groupName": "advanced"
},
{
"name": "ReplaceRegEx",
"type": "string",
"label": "RegEx replace pattern",
"defaultValue": "",
"required": false,
"helpMarkDown": "RegEx to replace with in files. Leave blank to use the Build RegEx Pattern.",
"groupName": "advanced"
},
{
"name": "ReplacePrefix",
"type": "string",
"label": "Prefix for replacements",
"defaultValue": "",
"required": false,
"helpMarkDown": "Prefix for the RegEx result string.",
"groupName": "advanced"
},
{
"name": "ReplaceSuffix",
"type": "string",
"label": "Suffix for replacements",
"defaultValue": "",
"required": false,
"helpMarkDown": "Suffix for the RegEx result string.",
"groupName": "advanced"
},
{
"name": "FailIfNoMatchFound",
"type": "boolean",
"label": "Fail if no target match found",
"defaultValue": "false",
"required": false,
"helpMarkDown": "Fail the build if no match is found for the replace RegEx in the target file(s).",
"groupName": "advanced"
}
],
"execution": {
"PowerShell3": {
"target": "VersionAssembly.ps1"
}
}
From VersionAssembly.ps1:
[CmdletBinding()]
param(
[string][Parameter(Mandatory=$True)][ValidateNotNullOrEmpty()] $SourcePath,
[string][Parameter(Mandatory=$True)][ValidateNotNullOrEmpty()] $FilePattern,
[string][Parameter(Mandatory=$True)][ValidateNotNullOrEmpty()] $BuildRegex,
[string]$BuildRegexIndex,
[string]$ReplaceRegex,
[string]$ReplacePrefix,
[string]$ReplaceSuffix,
[string]$FailIfNoMatchFound,
[string]$BuildNumber = $ENV:BUILD_BUILDNUMBER
)
Apparently I wasn't following closely enough... I missed the warning on this page:
Words of warning
Tasks can be versioned, use this to your advantage. All build definitions use the latest available version of a specific task, you can’t change this behavior from the web interface, so always assume the latest version is being used.
If you don’t change the version number of your task when updating it, the build agents that have previously used your task will not download the newer version because the version number is still the same. This means that if you change the behavior of your task, you should always update the version number!
Once I got that all straightened out, everything worked fine.
Possibly the examples accepting inputs in the param section are out of date. It appears that you now need to use the Vsts-task-lib commands from your PowerShell script to get the input parameters.
[CmdletBinding()]
param()
$myParam = Get-VstsInput -Name myParam -Require