Azure DevOps REST API to create a release definition - azure-devops

I'm trying to create a release definition by using Azure DevOps REST API. I've created a json file which has configuration details for the request. I'm getting the below error, while creating the release definition.
{
"$id": "1",
"innerException": null,
"message": "Workflow of deploy job 'Run on the agent' in release pipeline stage 'development' is invalid. Add valid tasks and try again.",
"typeName": "Microsoft.VisualStudio.Services.ReleaseManagement.Data.Exceptions.InvalidRequestException, Microsoft.VisualStudio.Services.ReleaseManagement2.Data",
"typeKey": "InvalidRequestException",
"errorCode": 0,
"eventId": 3000
}
I'm using the below request body to create a new release definition in Azure cloud.
{
"name": "myreleasedefn1",
"artifacts": [{
"type": "DockerHub",
"alias": "_dockerusername_mydockerimage",
"definitionReference": {
"connection": {
"id": "dd986f4a-123k-45d5-b8e6-fc4fds23rce",
"name": "dockerservice"
},
"defaultVersionType": {
"id": "selectDuringReleaseCreationType",
"name": "Specify at the time of release creation"
},
"definition": {
"id": "dockerusername/mydockerimage",
"name": "dockerusername/mydockerimage"
},
"namespaces": {
"id": "dockerusername",
"name": "dockerusername"
}
},
"isPrimary": true,
"isRetained": false
}],
"releaseNameFormat": "Release-$(rev:r)",
"environments": [{
"name": "development",
"rank": 1,
"retentionPolicy": {
"daysToKeep": 30,
"releasesToKeep": 3,
"retainBuild": true
},
"preDeployApprovals": {
"approvals": [
{
"rank": 1,
"isAutomated": true,
"isNotificationOn": false,
"id": 10
}
],
"approvalOptions": {
"requiredApproverCount": null,
"releaseCreatorCanBeApprover": false,
"autoTriggeredAndPreviousEnvironmentApprovedCanBeSkipped": false,
"enforceIdentityRevalidation": false,
"timeoutInMinutes": 0,
"executionOrder": "beforeGates"
}
},
"postDeployApprovals": {
"approvals": [
{
"rank": 1,
"isAutomated": true,
"isNotificationOn": false,
"id": 12
}
],
"approvalOptions": {
"requiredApproverCount": null,
"releaseCreatorCanBeApprover": false,
"autoTriggeredAndPreviousEnvironmentApprovedCanBeSkipped": false,
"enforceIdentityRevalidation": false,
"timeoutInMinutes": 0,
"executionOrder": "afterSuccessfulGates"
}
},
"deployPhases": [{
"deploymentInput": {
"parallelExecution": {
"parallelExecutionType": "none"
},
"agentSpecification": {
"identifier": "ubuntu-16.04"
},
"skipArtifactsDownload": false,
"artifactsDownloadInput": {
"downloadInputs": []
},
"queueId": 9,
"demands": [],
"enableAccessToken": false,
"timeoutInMinutes": 0,
"jobCancelTimeoutInMinutes": 1,
"condition": "succeeded()",
"overrideInputs": {}
},
"rank": 1,
"phaseType": "agentBasedDeployment",
"name": "Run on the agent",
"workflowTasks": [{
"version": "4.*",
"name": "Deploy Azure App Service",
"refName": "",
"enabled": true,
"alwaysRun": false,
"continueOnError": false,
"timeoutInMinutes": 0,
"overrideInputs": {},
"condition": "succeeded()",
"inputs": {
"ConnectionType": "AzureRM",
"WebAppKind": "webAppContainer",
"WebAppName": "azureappservice1",
"DeployToSlotOrASEFlag": "false",
"ResourceGroupName": "",
"SlotName": "production",
"DockerNamespace": "dockerusername",
"DockerRepository": "mydockerimage",
"DockerImageTag": "10"
}
}]
}]
}]
}
It would be very helpful if you share an example template for the same request.
Please help!!!

Azure DevOps REST API to create a release definition
According to the error message:
"Workflow of deploy job 'Run on the agent' in release pipeline stage 'development' is invalid.
We could to know the task Deploy Azure App Service in the workflowTasks is invalid, we need to provide the correct request body for that task.
As I answered your previous post How to create new build pipeline using Azure DevOps REST API, this is very difficult and error-prone, if we add a huge request body completely manually. Usually, we use REST API Definitions - Get to get the Response Body from the similar release pipeline, then we update the corresponding properties by modifying the Response Body.
As test, I add the task Deploy Azure App Service in my release pipeline, then I use the REST API:
GET https://vsrm.dev.azure.com/{organization}/{project}/_apis/release/definitions/{definitionId}?api-version=5.0
to get the Response Body:
"workflowTasks": [
{
"environment": {},
"taskId": "497d490f-eea7-4f2b-ab94-48d9c1acdcb1",
"version": "4.*",
"name": "Azure App Service Deploy: xxxx",
"refName": "",
"enabled": true,
"alwaysRun": false,
"continueOnError": false,
"timeoutInMinutes": 0,
"definitionType": "task",
"overrideInputs": {},
"condition": "succeeded()",
"inputs": {
"ConnectionType": "AzureRM",
"ConnectedServiceName": "xxxxx",
"PublishProfilePath": "$(System.DefaultWorkingDirectory)/**/*.pubxml",
"PublishProfilePassword": "",
"WebAppKind": "webApp",
"WebAppName": "xxxx",
"DeployToSlotOrASEFlag": "false",
"ResourceGroupName": "",
"SlotName": "production",
"DockerNamespace": "",
"DockerRepository": "",
"DockerImageTag": "",
"VirtualApplication": "",
"Package": "$(System.DefaultWorkingDirectory)/**/*.zip",
"RuntimeStack": "",
"RuntimeStackFunction": "",
"StartupCommand": "",
"ScriptType": "",
"InlineScript": ":: You can provide your deployment commands here. One command per line.",
"ScriptPath": "",
"WebConfigParameters": "",
"AppSettings": "",
"ConfigurationSettings": "",
"UseWebDeploy": "false",
"DeploymentType": "webDeploy",
"TakeAppOfflineFlag": "true",
"SetParametersFile": "",
"RemoveAdditionalFilesFlag": "false",
"ExcludeFilesFromAppDataFlag": "true",
"AdditionalArguments": "-retryAttempts:6 -retryInterval:10000",
"RenameFilesFlag": "true",
"XmlTransformation": "false",
"XmlVariableSubstitution": "false",
"JSONFiles": ""
}
}
]
You could use this response body, and overwrite those properties you want to change.
Where can I get taskId in Azure portal?
You could check the source code of the task from Github,it is generally on the first line of task.json. Or you can use REST API/F12 to get it.
Can we use 'AzureContainerRegistry' as artifact type in the request
body?
The answer should be yes (not test it by a sample). You could add following request body in the body:
"artifacts": [
{
"sourceId": "xxxxxxxxxxxxxxx",
"type": "AzureContainerRepository",
"alias": "xxx",
"definitionReference": {
"connection": {
"id": "xxxxxx",
"name": "xxxx"
},
"defaultVersionType": {
"id": "latestType",
"name": "Latest"
},
"definition": {
"id": "xx",
"name": "xx"
},
"registryurl": {
"id": "22",
"name": "22"
},
"resourcegroup": {
"id": "xx",
"name": "xx"
}
},
"isPrimary": true,
"isRetained": false
}
],
Hope this helps.

I can help here. In workflowTasks You need to include the "taskId": "497d490f-eea7-4f2b-ab94-48d9c1acdcb1" which is id of the AzureRmWebAppDeploymentV4.
"workflowTasks": [
{
"taskId": "497d490f-eea7-4f2b-ab94-48d9c1acdcb1",
"version": "4.*",
"name": "Deploy Azure App Service",
"refName": "",
"enabled": true,
"alwaysRun": false,
"continueOnError": false,
"timeoutInMinutes": 0,
"definitionType": null,
"overrideInputs": {},
"condition": "succeeded()",
"inputs": {
"ConnectionType": "AzureRM",
"WebAppKind": "webAppContainer",
"WebAppName": "azureappservice1",
"DeployToSlotOrASEFlag": "false",
"ResourceGroupName": "",
"SlotName": "production",
"DockerNamespace": "dockerusername",
"DockerRepository": "mydockerimage",
"DockerImageTag": "10"
}
Once I added that I was able to create the release definition with your request body.

Related

azure function 404 not found when deployed from ARM, works fine when deployed from visual studio

I have an azure function that works when manually deployed via visual studio.
I then exported the ARM template from Azure portal and used this in a DevOps release pipeline.
The release pipeline succeeds after creating storage a hosting plan the function app and deploying the code to the function app.
When trying to access the function app however it throws a 404 not found error.
I've tried in postman and in the "code + test" section of the azure portal, but I get the same 404 error.
I assume the ARM template exported from azure portal is incorrect somehow but I cannot see how, as it deploys successfully.
Has anyone experienced this issue?
In case it is useful, below is the ARM template, almost as it was exported from the portal. I have changed function name and urls just to prevent any potential attacks.
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"sites_myFuncName_name": {
"defaultValue": "myFuncName",
"type": "String"
},
"serverfarms_FuncsPlan_externalid": {
"defaultValue": "/subscriptions/2sdr7sec-8sd7-78sd-a628-78asfd89sfed/resourceGroups/myResourceGroup/providers/Microsoft.Web/serverfarms/hostingPlanName",
"type": "String"
}
},
"variables": {},
"resources": [
{
"type": "Microsoft.Web/sites",
"apiVersion": "2022-03-01",
"name": "[parameters('sites_myFuncName_name')]",
"location": "North Europe",
"kind": "functionapp",
"properties": {
"enabled": true,
"hostNameSslStates": [
{
"name": "myFuncName.azurewebsites.net",
"sslState": "Disabled",
"hostType": "Standard"
},
{
"name": "myFuncName.scm.azurewebsites.net",
"sslState": "Disabled",
"hostType": "Repository"
}
],
"serverFarmId": "[parameters('serverfarms_FuncsPlan_externalid')]",
"reserved": false,
"isXenon": false,
"hyperV": false,
"vnetRouteAllEnabled": false,
"vnetImagePullEnabled": false,
"vnetContentShareEnabled": false,
"siteConfig": {
"numberOfWorkers": 1,
"acrUseManagedIdentityCreds": false,
"alwaysOn": false,
"http20Enabled": false,
"functionAppScaleLimit": 200,
"minimumElasticInstanceCount": 0
},
"scmSiteAlsoStopped": false,
"clientAffinityEnabled": false,
"clientCertEnabled": false,
"clientCertMode": "Required",
"hostNamesDisabled": false,
"customDomainVerificationId": "XXXXX",
"containerSize": 1536,
"dailyMemoryTimeQuota": 0,
"httpsOnly": true,
"redundancyMode": "None",
"storageAccountRequired": false,
"keyVaultReferenceIdentity": "SystemAssigned"
}
},
{
"type": "Microsoft.Web/sites/basicPublishingCredentialsPolicies",
"apiVersion": "2022-03-01",
"name": "[concat(parameters('sites_myFuncName_name'), '/ftp')]",
"location": "North Europe",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', parameters('sites_myFuncName_name'))]"
],
"properties": {
"allow": true
}
},
{
"type": "Microsoft.Web/sites/basicPublishingCredentialsPolicies",
"apiVersion": "2022-03-01",
"name": "[concat(parameters('sites_myFuncName_name'), '/scm')]",
"location": "North Europe",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', parameters('sites_myFuncName_name'))]"
],
"properties": {
"allow": true
}
},
{
"type": "Microsoft.Web/sites/config",
"apiVersion": "2022-03-01",
"name": "[concat(parameters('sites_myFuncName_name'), '/web')]",
"location": "North Europe",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', parameters('sites_myFuncName_name'))]"
],
"properties": {
"numberOfWorkers": 1,
"defaultDocuments": [
"Default.htm",
"Default.html",
"Default.asp",
"index.htm",
"index.html",
"iisstart.htm",
"default.aspx",
"index.php"
],
"netFrameworkVersion": "v6.0",
"requestTracingEnabled": false,
"remoteDebuggingEnabled": false,
"remoteDebuggingVersion": "VS2019",
"httpLoggingEnabled": false,
"acrUseManagedIdentityCreds": false,
"logsDirectorySizeLimit": 35,
"detailedErrorLoggingEnabled": false,
"publishingUsername": "$myFuncName",
"scmType": "VSTSRM",
"use32BitWorkerProcess": true,
"webSocketsEnabled": false,
"alwaysOn": false,
"managedPipelineMode": "Integrated",
"virtualApplications": [
{
"virtualPath": "/",
"physicalPath": "site\\wwwroot",
"preloadEnabled": false
}
],
"loadBalancing": "LeastRequests",
"experiments": {
"rampUpRules": []
},
"autoHealEnabled": false,
"vnetRouteAllEnabled": false,
"vnetPrivatePortsCount": 0,
"localMySqlEnabled": false,
"ipSecurityRestrictions": [
{
"ipAddress": "Any",
"action": "Allow",
"priority": 2147483647,
"name": "Allow all",
"description": "Allow all access"
}
],
"scmIpSecurityRestrictions": [
{
"ipAddress": "Any",
"action": "Allow",
"priority": 2147483647,
"name": "Allow all",
"description": "Allow all access"
}
],
"scmIpSecurityRestrictionsUseMain": false,
"http20Enabled": false,
"minTlsVersion": "1.2",
"scmMinTlsVersion": "1.2",
"ftpsState": "FtpsOnly",
"preWarmedInstanceCount": 0,
"functionAppScaleLimit": 200,
"functionsRuntimeScaleMonitoringEnabled": false,
"minimumElasticInstanceCount": 0,
"azureStorageAccounts": {}
}
},
{
"type": "Microsoft.Web/sites/functions",
"apiVersion": "2022-03-01",
"name": "[concat(parameters('sites_myFuncName_name'), '/FuncName')]",
"location": "North Europe",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', parameters('sites_myFuncName_name'))]"
],
"properties": {
"script_root_path_href": "https://myFuncName.scm.azurewebsites.net/api/vfs/site/wwwroot/FuncName/",
"script_href": "https://myFuncName.scm.azurewebsites.net/api/vfs/site/wwwroot/bin/MyFuncName.dll",
"config_href": "https://myFuncName.scm.azurewebsites.net/api/vfs/site/wwwroot/FuncName/function.json",
"test_data_href": "https://myFuncName.scm.azurewebsites.net/api/vfs/data/Functions/sampledata/FuncName.dat",
"href": "https://myFuncName.scm.azurewebsites.net/api/functions/FuncName",
"config": {},
"invoke_url_template": "https://myFuncName.azurewebsites.net/api/FuncName",
"language": "DotNetAssembly",
"isDisabled": false
}
},
{
"type": "Microsoft.Web/sites/hostNameBindings",
"apiVersion": "2022-03-01",
"name": "[concat(parameters('sites_myFuncName_name'), '/', parameters('sites_myFuncName_name'), '.azurewebsites.net')]",
"location": "North Europe",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', parameters('sites_myFuncName_name'))]"
],
"properties": {
"siteName": "myFuncName",
"hostNameType": "Verified"
}
}
]
}

deploy web apps /create Stages by api to run new deployments

It’ possible to create a deploment stage by Azure DevOps API? We want to create a new stage and want to deploy a web app on the webserver. What is the best approach to release a new web app including the configuration of iis by azure devops API?
Kind Regards,
Dominik
If you mean creating release definition with stages and specific tasks, then you can call the Definitions - Create REST API.
For example to add a stage with the IIS Web App Deploy task:
POST : https://vsrm.dev.azure.com/{organization}/{project}/_apis/release/definitions?api-version=6.0
Request Body: (Of course, you need to replace the parameters accordingly. You can also capture the Request Body(Payload) by pressing F12 when creating a release definition from the UI)
{
"id": 0,
"name": "RESTAPI-WEB",
"source": 2,
"comment": "",
"createdOn": "2022-04-20T08:36:03.598Z",
"createdBy": null,
"modifiedBy": null,
"modifiedOn": "2022-04-20T08:36:03.598Z",
"environments": [
{
"id": -3,
"name": "Stage 1",
"rank": 1,
"variables": {},
"variableGroups": [],
"preDeployApprovals": {
"approvals": [
{
"rank": 1,
"isAutomated": true,
"isNotificationOn": false,
"id": 0
}
],
"approvalOptions": {
"executionOrder": 1
}
},
"deployStep": {
"tasks": [],
"id": 0
},
"postDeployApprovals": {
"approvals": [
{
"rank": 1,
"isAutomated": true,
"isNotificationOn": false,
"id": 0
}
],
"approvalOptions": {
"executionOrder": 2
}
},
"deployPhases": [
{
"deploymentInput": {
"parallelExecution": {
"parallelExecutionType": 0
},
"agentSpecification": null,
"skipArtifactsDownload": false,
"artifactsDownloadInput": {},
"queueId": 158,
"demands": [],
"enableAccessToken": false,
"timeoutInMinutes": 0,
"jobCancelTimeoutInMinutes": 1,
"condition": "succeeded()",
"overrideInputs": {},
"dependencies": []
},
"rank": 1,
"phaseType": 1,
"name": "Agent job",
"refName": null,
"workflowTasks": [
{
"name": "Deploy IIS Website/App: ",
"refName": null,
"enabled": true,
"timeoutInMinutes": 0,
"inputs": {
"WebSiteName": "TestSite",
"VirtualApplication": "",
"Package": "$(System.DefaultWorkingDirectory)\\**\\*.zip",
"SetParametersFile": "",
"RemoveAdditionalFilesFlag": "true",
"ExcludeFilesFromAppDataFlag": "true",
"TakeAppOfflineFlag": "false",
"AdditionalArguments": "",
"XmlTransformation": "false",
"XmlVariableSubstitution": "false",
"JSONFiles": ""
},
"taskId": "1b467810-6725-4b6d-accd-886174c09bba",
"version": "0.*",
"definitionType": "task",
"alwaysRun": false,
"continueOnError": false,
"overrideInputs": {},
"condition": "succeeded()",
"environment": {},
"retryCountOnTaskFailure": 0
}
],
"phaseInputs": {}
}
],
"runOptions": {},
"environmentOptions": {
"emailNotificationType": "OnlyOnFailure",
"emailRecipients": "release.environment.owner;release.creator",
"skipArtifactsDownload": false,
"timeoutInMinutes": 0,
"enableAccessToken": false,
"publishDeploymentStatus": true,
"badgeEnabled": false,
"autoLinkWorkItems": false,
"pullRequestDeploymentEnabled": false
},
"demands": [],
"conditions": [
{
"conditionType": 1,
"name": "ReleaseStarted",
"value": ""
}
],
"executionPolicy": {
"concurrencyCount": 1,
"queueDepthCount": 0
},
"schedules": [],
"properties": {
"LinkBoardsWorkItems": false,
"BoardsEnvironmentType": "unmapped"
},
"preDeploymentGates": {
"id": 0,
"gatesOptions": null,
"gates": []
},
"postDeploymentGates": {
"id": 0,
"gatesOptions": null,
"gates": []
},
"retentionPolicy": {
"daysToKeep": 30,
"releasesToKeep": 3,
"retainBuild": true
},
"processParameters": {}
}
],
"artifacts": [
{
"type": "Build",
"definitionReference": {
"IsMultiDefinitionType": {
"name": "False",
"id": "False"
},
"project": {
"name": "AzureFunction",
"id": "4da2f07a-ac7b-43a0-b764-459af8a4d9df"
},
"repository": {
"name": "",
"id": ""
},
"definitions": {
"name": "",
"id": ""
},
"definition": {
"name": "AzureFunctions_CI",
"id": "172"
},
"defaultVersionType": {
"name": "Latest",
"id": "latestType"
},
"defaultVersionBranch": {
"name": "",
"id": ""
},
"defaultVersionTags": {
"name": "",
"id": ""
},
"defaultVersionSpecific": {
"name": "",
"id": ""
}
},
"alias": "_AzureFunctions_CI",
"isPrimary": true,
"sourceId": "",
"isRetained": false
}
],
"variables": {},
"variableGroups": [],
"triggers": [],
"lastRelease": null,
"tags": [],
"path": "\\",
"properties": {
"DefinitionCreationSource": "ReleaseNew",
"IntegrateJiraWorkItems": "false",
"IntegrateBoardsWorkItems": false
},
"releaseNameFormat": "Release-$(rev:r)",
"description": ""
}
To deploy the webapp, please refer to Deploy your Web Deploy package to IIS servers using WinRM and Deploy an Azure Web App for details.

How to set deployment group in release Pipeline by api

I try to create a release pipeline via Azure devops api. As phaseType I want to use machineGroupBasedDeployment (Deployment Group). But how can I set the Deployment group in the deployment phase? If I use the json below as request the deployment group is always empty. Has anybody an idea or an sample how I can set the deployment group?
"deployPhases": [
{
"deploymentInput": {
"healthPercent": 0,
"deploymentHealthOption": "Custom",
"tags": [],
"skipArtifactsDownload": false,
"artifactsDownloadInput": {
"downloadInputs": [
{
"alias": "_xxx ch",
"artifactType": "Build",
"artifactDownloadMode": "All",
"artifactItems": []
}
]
},
"queueId": 129,
"demands": [],
"enableAccessToken": false,
"timeoutInMinutes": 10,
"jobCancelTimeoutInMinutes": 1,
"condition": "succeeded()",
"overrideInputs": {}
},
"rank": 1,
"phaseType": 4,
"name": "IIS Deployment111",
"refName": null,
"workflowTasks": [
{
"environment": {},
"taskId": "1b2aec60-dc49-11e6-9b76-63056e018cac",
"version": "0.*",
"name": "IIS Web App Manage",
"refName": "",
"enabled": true,
"alwaysRun": false,
"continueOnError": false,
"timeoutInMinutes": 10,
"retryCountOnTaskFailure": 0,
"definitionType": null,
"overrideInputs": {},
"condition": "succeeded()",
"inputs": {
....
how can I set the Deployment group in the deployment phase?
In the RequestBody, you can define the Deployment Group Id in the queueId field and the phaseType is machineGroupBasedDeployment.
For example:
"deployPhases": [
{
"deploymentInput": {
"healthPercent": 0,
"deploymentHealthOption": "Custom",
"tags": [],
"skipArtifactsDownload": false,
"artifactsDownloadInput": {
"downloadInputs": []
},
"queueId": {DeploymentGroupID},
"demands": [],
"enableAccessToken": false,
"timeoutInMinutes": 0,
"jobCancelTimeoutInMinutes": 1,
"condition": "succeeded()",
"overrideInputs": {}
},
"rank": 1,
"phaseType": "machineGroupBasedDeployment",
"name": "Deployment1 group job",
"refName": null,
"workflowTasks": [
{
"environment": {},
"taskId": "e213ff0f-5d5c-4791-802d-52ea3e7be1f1",
"version": "2.*",
"name": "PowerShell Script",
"refName": "",
"enabled": true,
"alwaysRun": false,
"continueOnError": false,
"timeoutInMinutes": 0,
"retryCountOnTaskFailure": 0,
"definitionType": "task",
"overrideInputs": {},
"condition": "succeeded()",
"inputs": {
"targetType": "inline",
"filePath": "",
"arguments": "",
"script": "# Write your PowerShell commands here.\n\nWrite-Host \"Hello World\"\n",
"errorActionPreference": "stop",
"warningPreference": "default",
"informationPreference": "default",
"verbosePreference": "default",
"debugPreference": "default",
"failOnStderr": "false",
"showWarnings": "false",
"ignoreLASTEXITCODE": "false",
"pwsh": "false",
"workingDirectory": "",
"runScriptInSeparateScope": "false"
}
}
]
}
],
To get the Deployment Group ID, you can navigate to Pipelines -> Deployment Groups -> Target Deployment Group and check the mgid in the url.
On the other hand, you can also use this Rest API: Definitions - Get to get the definition of an existing release pipeline and check the response to get the required request body content

Commit Status not working with Continuous Deployment Trigger in Azure Release via API

We have an Azure Repository which triggers a Release-Pipeline every time something is pushed to the main branch.
When a Release is triggered it shows its status (succeeded) on the right side in the commits in Azure Repos like on the following Picture:
It even shows which stage is already promoted etc. which is awesome. This all works fine when configuring the Release Pipeline Manually with the following CD-Trigger Configuration:
Even when exporting the Pipeline JSON file and reimporting it everything works as expected.
However, when creating the Release with the exact same Settings via API i don't see the Status of the Release. The trigger itself works as expected but the status in the commits is simply not there:
Does someone know which exact Setting in the Release-Pipeline.json is responsible for this status?
Here are some parts of the json body I send via API which might be missing something?
Edit: A few more information needed i guess. I use a cli-tool to create the body and send the api request. The values are templated.
The template gets its values either from previous api calls or from user inputs. Here is the complete template. I created it based on the manually configured relase-pipeline JSON (Which works fine and shows the status i want).
{
"name": "{{.BuildProjectName}}/{{.BuildServiceName}}",
"path": "\\",
"isDeleted": false,
"source": "restApi",
"releaseNameFormat": "{{.BuildServiceName}}-$(rev:r)",
"properties": {
"DefinitionCreationSource": {
"$type": "System.String",
"$value": "ReleaseNew"
},
"IntegrateBoardsWorkItems": {
"$type": "System.String",
"$value": "False"
},
"IntegrateJiraWorkItems": {
"$type": "System.String",
"$value": "false"
}
},
"artifacts": [
{
"sourceId": "{{.BuildProjectID}}:{{.BuildRepoID}}",
"type": "Git",
"alias": "BuildRepo",
"definitionReference": {
"branches": {
"id": "{{.BuildRepoDefaultBranch}}",
"name": "{{.BuildRepoDefaultBranch}}"
},
"checkoutNestedSubmodules": {
"id": "True",
"name": "Any nested submodules within"
},
"defaultVersionType": {
"id": "latestFromBranchType",
"name": "Latest from the default branch"
},
"definition": {
"id": "{{.BuildRepoID}}",
"name": "{{.BuildServiceName}}"
},
"project": {
"id": "{{.BuildProjectID}}",
"name": "{{.BuildProjectName}}"
}
},
"isPrimary": true,
"isRetained": false
},
{
"type": "Git",
"alias": "FluxDeployScript",
"definitionReference": {
"branches": {
"id": "master",
"name": "master"
},
"checkoutNestedSubmodules": {
"id": "True",
"name": "Any nested submodules within"
},
"defaultVersionType": {
"id": "latestFromBranchType",
"name": "Latest from the default branch"
},
"definition": {
"id": "black-washed",
"name": "azure-pipeline-templates"
},
"project": {
"id": "black-washed",
"name": "Operations"
}
},
"isRetained": false
},
{
"type": "Build",
"alias": "BuildPipeline",
"definitionReference": {
"defaultVersionType": {
"id": "latestType",
"name": "Latest"
},
"definition": {
"id": "{{.BuildPipelineID}}",
"name": "{{.BuildServiceName}}"
},
"IsMultiDefinitionType": {
"id": "False",
"name": "False"
},
"project": {
"id": "{{.BuildProjectID}}",
"name": "{{.BuildProjectName}}"
}
},
"isRetained": false
}
],
"environments": [
{
"name": "dev",
"rank": 1,
"conditions": [
{
"name": "ReleaseStarted",
"conditionType": 1,
"value": ""
}
],
"deployPhases": [
{
"rank": 1,
"phaseType": 1,
"name": "Agent job",
"refName": null,
"deploymentInput": {
"queueId": "{{.QueueID}}",
"agentSpecification": {
"identifier": "ubuntu-20.04"
}
},
"workflowTasks": [
{
"environment": {},
"taskId": "2a6ca863-f2ce-4f4d-8bcb-15e64608ec4b",
"version": "1.*",
"name": "Download flux creds",
"refName": "fluxCreds",
"enabled": true,
"alwaysRun": false,
"continueOnError": false,
"timeoutInMinutes": 0,
"definitionType": "task",
"overrideInputs": {},
"condition": "succeeded()",
"inputs": {
"secureFile": "black-washed",
"retryCount": "8",
"socketTimeout": ""
}
},
{
"environment": {
"USER_EMAIL": "{{.ApproverMail}}",
"ENVIRONMENT": "$(Release.EnvironmentName)",
"DESCRIPTION": "$(Release.ReleaseDescription)",
"URL": "$(Release.ReleaseWebURL)",
"PROJECT": "{{.BuildProjectName}}",
"CONTAINER": "{{.BuildServiceName}}",
"TAG": "$(Release.Artifacts.BuildPipeline.BuildNumber)",
"REPOSITORY": "finodigital.azurecr.io",
"WORKLOAD_TYPE": "deployment",
"NAMESPACE": "{{.BuildProjectName}}",
"WORKLOAD_NAME": "{{.BuildProjectName}}-{{.BuildServiceName}}",
"USER_NAME": "{{.ApproverName}}",
"FLUX_CREDS": "$(fluxCreds.secureFilePath)"
},
"taskId": "6c731c3c-3c68-459a-a5c9-bde6e6595b5b",
"version": "3.*",
"name": "Bash Script",
"refName": "",
"enabled": true,
"alwaysRun": false,
"continueOnError": false,
"timeoutInMinutes": 0,
"definitionType": "task",
"overrideInputs": {},
"condition": "succeeded()",
"inputs": {
"targetType": "filePath",
"filePath": "$(System.DefaultWorkingDirectory)/FluxDeployScript/flux-release.sh",
"arguments": "",
"workingDirectory": "",
"failOnStderr": "false",
"noProfile": "true",
"noRc": "true"
}
}
]
}
],
"retentionPolicy": {
"daysToKeep": 30,
"releasesToKeep": 3,
"retainBuild": true
},
"preDeployApprovals": {
"approvals": [
{
"rank": 1,
"isAutomated": true,
"isNotificationOn": false
}
],
"approvalOptions": {
"requiredApproverCount": null,
"releaseCreatorCanBeApprover": false,
"autoTriggeredAndPreviousEnvironmentApprovedCanBeSkipped": false,
"enforceIdentityRevalidation": false,
"timeoutInMinutes": 0,
"executionOrder": 1
}
},
"postDeployApprovals": {
"approvals": [
{
"rank": 1,
"isAutomated": true,
"isNotificationOn": false
}
],
"approvalOptions": {
"requiredApproverCount": null,
"releaseCreatorCanBeApprover": false,
"autoTriggeredAndPreviousEnvironmentApprovedCanBeSkipped": false,
"enforceIdentityRevalidation": false,
"timeoutInMinutes": 0,
"executionOrder": 2
}
}
},
{
"name": "test",
"rank": 2,
"conditions": [
{
"name": "dev",
"conditionType": 2,
"value": "4"
}
],
"deployPhases": [
{
"rank": 1,
"phaseType": 1,
"name": "Agent job",
"refName": null,
"deploymentInput": {
"queueId": "{{.QueueID}}",
"agentSpecification": {
"identifier": "ubuntu-20.04"
}
},
"workflowTasks": [
{
"environment": {},
"taskId": "2a6ca863-f2ce-4f4d-8bcb-15e64608ec4b",
"version": "1.*",
"name": "Download flux creds",
"refName": "fluxCreds",
"enabled": true,
"alwaysRun": false,
"continueOnError": false,
"timeoutInMinutes": 0,
"definitionType": "task",
"overrideInputs": {},
"condition": "succeeded()",
"inputs": {
"secureFile": "black-washed",
"retryCount": "8",
"socketTimeout": ""
}
},
{
"environment": {
"USER_EMAIL": "{{.ApproverMail}}",
"ENVIRONMENT": "$(Release.EnvironmentName)",
"DESCRIPTION": "$(Release.ReleaseDescription)",
"URL": "$(Release.ReleaseWebURL)",
"PROJECT": "{{.BuildProjectName}}",
"CONTAINER": "{{.BuildServiceName}}",
"TAG": "$(Release.Artifacts.BuildPipeline.BuildNumber)",
"REPOSITORY": "finodigital.azurecr.io",
"WORKLOAD_TYPE": "deployment",
"NAMESPACE": "{{.BuildProjectName}}",
"WORKLOAD_NAME": "{{.BuildProjectName}}-{{.BuildServiceName}}",
"USER_NAME": "{{.ApproverName}}",
"FLUX_CREDS": "$(fluxCreds.secureFilePath)"
},
"taskId": "6c731c3c-3c68-459a-a5c9-bde6e6595b5b",
"version": "3.*",
"name": "Bash Script",
"refName": "",
"enabled": true,
"alwaysRun": false,
"continueOnError": false,
"timeoutInMinutes": 0,
"definitionType": "task",
"overrideInputs": {},
"condition": "succeeded()",
"inputs": {
"targetType": "filePath",
"filePath": "$(System.DefaultWorkingDirectory)/FluxDeployScript/flux-release.sh",
"arguments": "",
"workingDirectory": "",
"failOnStderr": "false",
"noProfile": "true",
"noRc": "true"
}
}
]
}
],
"retentionPolicy": {
"daysToKeep": 30,
"releasesToKeep": 3,
"retainBuild": true
},
"preDeployApprovals": {
"approvals": [
{
"rank": 1,
"isAutomated": false,
"isNotificationOn": false,
"approver": {
"displayName": null,
"id": "{{.ApproverID}}"
}
}
],
"approvalOptions": {
"requiredApproverCount": null,
"releaseCreatorCanBeApprover": false,
"autoTriggeredAndPreviousEnvironmentApprovedCanBeSkipped": false,
"enforceIdentityRevalidation": false,
"timeoutInMinutes": 0,
"executionOrder": 1
}
},
"postDeployApprovals": {
"approvals": [
{
"rank": 1,
"isAutomated": true,
"isNotificationOn": false
}
],
"approvalOptions": {
"requiredApproverCount": null,
"releaseCreatorCanBeApprover": false,
"autoTriggeredAndPreviousEnvironmentApprovedCanBeSkipped": false,
"enforceIdentityRevalidation": false,
"timeoutInMinutes": 0,
"executionOrder": 2
}
}
},
{
"name": "prod",
"rank": 3,
"conditions": [
{
"name": "test",
"conditionType": 2,
"value": "4"
}
],
"deployPhases": [
{
"rank": 1,
"phaseType": 1,
"name": "Agent job",
"refName": null,
"deploymentInput": {
"queueId": "{{.QueueID}}",
"agentSpecification": {
"identifier": "ubuntu-20.04"
}
},
"workflowTasks": [
{
"environment": {},
"taskId": "2a6ca863-f2ce-4f4d-8bcb-15e64608ec4b",
"version": "1.*",
"name": "Download flux creds",
"refName": "fluxCreds",
"enabled": true,
"alwaysRun": false,
"continueOnError": false,
"timeoutInMinutes": 0,
"definitionType": "task",
"overrideInputs": {},
"condition": "succeeded()",
"inputs": {
"secureFile": "black-wahsed",
"retryCount": "8",
"socketTimeout": ""
}
},
{
"environment": {
"USER_EMAIL": "{{.ApproverMail}}",
"ENVIRONMENT": "$(Release.EnvironmentName)",
"DESCRIPTION": "$(Release.ReleaseDescription)",
"URL": "$(Release.ReleaseWebURL)",
"PROJECT": "{{.BuildProjectName}}",
"CONTAINER": "{{.BuildServiceName}}",
"TAG": "$(Release.Artifacts.BuildPipeline.BuildNumber)",
"REPOSITORY": "finodigital.azurecr.io",
"WORKLOAD_TYPE": "deployment",
"NAMESPACE": "{{.BuildProjectName}}",
"WORKLOAD_NAME": "{{.BuildProjectName}}-{{.BuildServiceName}}",
"USER_NAME": "{{.ApproverName}}",
"FLUX_CREDS": "$(fluxCreds.secureFilePath)"
},
"taskId": "6c731c3c-3c68-459a-a5c9-bde6e6595b5b",
"version": "3.*",
"name": "Bash Script",
"refName": "",
"enabled": true,
"alwaysRun": false,
"continueOnError": false,
"timeoutInMinutes": 0,
"definitionType": "task",
"overrideInputs": {},
"condition": "succeeded()",
"inputs": {
"targetType": "filePath",
"filePath": "$(System.DefaultWorkingDirectory)/FluxDeployScript/flux-release.sh",
"arguments": "",
"workingDirectory": "",
"failOnStderr": "false",
"noProfile": "true",
"noRc": "true"
}
}
]
}
],
"retentionPolicy": {
"daysToKeep": 30,
"releasesToKeep": 3,
"retainBuild": true
},
"preDeployApprovals": {
"approvals": [
{
"rank": 1,
"isAutomated": false,
"isNotificationOn": false,
"approver": {
"displayName": null,
"id": "{{.ApproverID}}"
}
}
],
"approvalOptions": {
"requiredApproverCount": null,
"releaseCreatorCanBeApprover": false,
"autoTriggeredAndPreviousEnvironmentApprovedCanBeSkipped": false,
"enforceIdentityRevalidation": false,
"timeoutInMinutes": 0,
"executionOrder": 1
}
},
"postDeployApprovals": {
"approvals": [
{
"rank": 1,
"isAutomated": true,
"isNotificationOn": false
}
],
"approvalOptions": {
"requiredApproverCount": null,
"releaseCreatorCanBeApprover": false,
"autoTriggeredAndPreviousEnvironmentApprovedCanBeSkipped": false,
"enforceIdentityRevalidation": false,
"timeoutInMinutes": 0,
"executionOrder": 2
}
}
}
],
"triggers": [
{
"branchFilters": [
"{{.BuildRepoDefaultBranch}}"
],
"alias": "BuildRepo",
"triggerType": 3
}
]
According to your description, I tested it and everything works as expected.
Steps:
Get the release definition via the REST API Definitions - Get and copy the response body.
GET https://vsrm.dev.azure.com/{organization}/{project}/_apis/release/definitions/{definitionId}?api-version=6.1-preview.4
Create the new release pipeline via the REST API Definitions - Create
POST https://vsrm.dev.azure.com/{organization}/{project}/_apis/release/definitions?api-version=6.1-preview.4
Copy the response body and rename the field name to New release pipeline2, then mark it as request body.
I am using PostMan.
Result:
Update1
It seems that you are missing the field environmentOptions field in the request body, which contains publishDeploymentStatus, which controls the feature you are missing.
If you do not configure it or set the value to false, you will not see the Status of the Release in the commit page.
"environmentOptions": {
"emailNotificationType": "OnlyOnFailure",
"emailRecipients": "release.environment.owner;release.creator",
"skipArtifactsDownload": false,
"timeoutInMinutes": 0,
"enableAccessToken": false,
"publishDeploymentStatus": false,
"badgeEnabled": false,
"autoLinkWorkItems": false,
"pullRequestDeploymentEnabled": false
},
Result:

Maintain password for TFS Release Management

I'm developing Release pipeline for our internal LOB applications using TFS 2015 Update2 Release Management. There are various tasks like "Windows Machine File Copy" and "Run PowerShell on Target machines" which needs admin credentials to be passed as input parameters. These admin credentials have Administrative access on target nodes. I'm using Windows service accounts for these. We have an organizational security policy to rotate passwords every year.
With that in mind, it is cumbersome to update hundreds of TFS release definitions for new password every year.
Do you have a better idea to handle this?
Thanks for your help and suggestions.
You can update release definitions programmatically via the REST API, which is well-documented and fairly straightforward.
Ex (note that this is for Update 3 and later, per the documentation, the API in TFS 2015.2 may differ slightly):
PUT https://fabfiber.vsrm.visualstudio.com/DefaultCollection/ff213d65-d61d-447c-b39d-d16f21b18364/_apis/release/definitions/28?api-version=3.0-preview.1
Content-Type: application/json
{
"id": 28,
"name": "Fabrikam.CD",
"createdOn": "2016-04-11T11:04:05.197Z",
"createdBy": {
"id": "52a5bc8d-4730-400a-95c7-7276d4ae5953",
"displayName": "Chuck Reinhart",
"uniqueName": "chuckreinhart#outlook.com",
"url": "https://fabfiber.vssps.visualstudio.com/_apis/Identities/52a5bc8d-4730-400a-95c7-7276d4ae5953",
"imageUrl": "https://fabfiber.visualstudio.com/DefaultCollection/_api/_common/identityImage?id=52a5bc8d-4730-400a-95c7-7276d4ae5953"
},
"environments": [
{
"name": "Dev",
"rank": 1,
"deployStep": {
"tasks": []
},
"owner": {
"id": "52a5bc8d-4730-400a-95c7-7276d4ae5953",
"displayName": "Chuck Reinhart",
"uniqueName": "chuckreinhart#outlook.com",
"url": "https://fabfiber.vssps.visualstudio.com/_apis/Identities/52a5bc8d-4730-400a-95c7-7276d4ae5953",
"imageUrl": "https://fabfiber.visualstudio.com/DefaultCollection/_api/_common/identityImage?id=52a5bc8d-4730-400a-95c7-7276d4ae5953"
},
"queueId": 2,
"demands": [],
"conditions": [],
"variables": {},
"runOptions": {},
"environmentOptions": {
"emailNotificationType": "Always",
"skipArtifactsDownload": false,
"timeoutInMinutes": 0
},
"executionPolicy": {
"concurrencyCount": 0,
"queueDepthCount": 0
},
"preDeployApprovals": {
"approvals": [
{
"rank": 1,
"isAutomated": true,
"isNotificationOn": false
}
],
"approvalOptions": null
},
"postDeployApprovals": {
"approvals": [
{
"rank": 1,
"isAutomated": true,
"isNotificationOn": false
}
],
"approvalOptions": null
}
}
],
"artifacts": [
{
"alias": "FabrikamCI",
"type": "Build",
"definitionReference": {
"project": {
"name": "Fabrikam",
"id": "ff213d65-d61d-447c-b39d-d16f21b18364"
},
"definition": {
"name": "Fabrikam.CI",
"id": "1"
}
},
"isPrimary": false
}
],
"variables": {},
"triggers": [],
"revision": 1,
"releaseNameFormat": "",
"retentionPolicy": {
"daysToKeep": 60
}
}