Sharing information between releases in Azure Dev Ops - azure

I have an ADO release pipeline, which has multiple releases.
I want to share information between releases. Basically the new release needs to know the details about the last release. Is there a way to do that?
I was thinking of using artifacts to share this information, but looks like "Publish Pipeline Artifacts" is not supported for the release pipeline : https://github.com/Microsoft/azure-pipelines-tasks/issues/8812
What is a good way to achieve this capability?

To let the new release know the details about the last release. You can add a powershell task in your release pipeline to call azure devops rest api.
You can use below restful api get the the release information.
GET https://vsrm.dev.azure.com/{organization}/{project}/_apis/release/releases/{releaseId}?api-version=5.1
Below is an example in powershell script.
$lastRelease =$(Release.ReleaseId) -1
$url = "https://vsrm.dev.azure.com/{org}/{proj}/_apis/release/releases/$($lastRelease)?api-version=5.1"
$result = Invoke-RestMethod -Uri $url -Headers #{authorization = "Bearer $(System.AccessToken)"} -Method get
echo $result
Note:
To run above script in your release pipeline powershell task, You need to go to Agent Job and make sure allow scripts access to the OAthen token is checked

Related

Retrieve Release information from a deployment job

I am running an azure pipeline to deploy applications to the cloud.
Before deploying I want to check if the current version deployed on the cloud is not same as the version the user wants to deploy.
I was looking into getting release name of the build which was deployed before.
I am using Azure devops git as my repository.
Is there any way I can get the desired information using the Azure Devops Rest API?
Thanks in advance.
I was looking into getting release name of the build which was deployed before. I am using Azure devops git as my repository.
We could use the REST API Releases - List with argument $top to get the latest release pipeline:
GET https://vsrm.dev.azure.com/{organization}/{project}/_apis/release/releases?definitionId={definitionId}&`$top={$top}&api-version=6.0
We could get the latest release pipeline Id:
$connectionToken="Your PAT Here"
$base64AuthInfo= [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($connectionToken)"))
$ReleasePipelineUrl = "https://vsrm.dev.azure.com/{organization}/{project}/_apis/release/releases?definitionId={definitionId}&`$top={$top}&api-version=6.0"
Write-Host "URL: $ReleasePipelineUrl"
$ReleasePipelineInfo = (Invoke-RestMethod -Uri $ReleasePipelineUrl -Method Get -UseDefaultCredential -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)})
$LatestReleaseId = $ReleasePipelineInfo.value.id | ConvertTo-Json -Depth 100
Write-Host "LatestReleaseId = $LatestReleaseId"
After getting the LatestReleaseId, we could use the REST API Releases - Get Release:
GET https://vsrm.dev.azure.com/{organization}/{project}/_apis/release/releases/{releaseId}?api-version=6.0
to get the detailed info, like artifact name about the latest pipeline:
$connectionToken="Your PAT Here"
$base64AuthInfo= [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($connectionToken)"))
$ReleaseArtifactUrl = "https://vsrm.dev.azure.com/{organization}/{project}/_apis/release/releases/$($LatestReleaseId)?api-version=5.1"
Write-Host "URL: $ReleaseArtifactUrl"
$ReleaseArtifactInfo = (Invoke-RestMethod -Uri $ReleaseArtifactUrl -Method Get -UseDefaultCredential -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)})
$ReleaseArtifactName = $ReleaseArtifactInfo.artifacts.definitionReference.version.name | ConvertTo-Json -Depth 100
Write-Host "ReleaseArtifactName = $ReleaseArtifactName"
Now, we get the release name of the build which was deployed latest time.
To resolve your question, we could add a powershell task in your build pipeline to invoke above REST API to check the Release name.
And add another task to compare whether the release name is the same as the artifact name generated by this build, we could use REST API to get it Artifacts - Get Artifact. If they are different, call the REST API to trigger the release pipeline. If they are the same, do nothing.
Therefore, we can judge whether there is an update by the name or version of each artifact generated, but it seems difficult to do it if we want to directly compare the version of the app. Unless we throw out this information about the app when building our pipeline, and then use the REST API to get it, for example, store it in a file. In any case, these methods require a bit of familiarity with the REST API and hope to help you.

In Azure Release Pipelines is it possible to manually trigger multiple release pipelines at once?

In our organization we have each repo set up with a complete pipeline (build in yaml and release using the ui which we have to do to use deployment groups). We have to keep the repos separate via pipelines as we often do a release just for that service, sometimes however we are releasing several services at once (this is known way in advance of the release).
Currently we just have the list of release pipelines to run and we run each one manually.
I was wondering if there was a way to setup something so that multiple release pipelines can be run off one click after the initial setup?
Below are the steps id ideally like to take:
Determine which pipelines need to be released (this usually happens before the sprint in a planning meeting)
Create "something" (another release pipeline that is only used for this release, another azure option I'm unaware of) that basically brings all the release pipelines that need to be included in one place.
Trigger all the release pipelines so they run (as if I ran each one manually)
You may use Trigger Azure DevOps Pipeline and then create another pipeline:
You can create a variable for each release to indicate which version of artifact you want to deploy.
In that way all what you need is to edit variables before running this release once you define it.
As another workaround, you could add a PowerShell task to create multiple releases for different release definition by REST API.
POST https://vsrm.dev.azure.com/{organization}/{project}/_apis/release/releases?api-version=5.0
Sample powershell script to create releases as below:
#Define the variable and enter the release definition id that you want to trigger. For example, I want to manually trigger release pipelines 1 and 2 at once.
$ReleaseDefinitionID = 1,2
ForEach ($ID in $ReleaseDefinitionID)
{
Write-host "ID is" $ID
$token = "pat"
$url = "https://vsrm.dev.azure.com/{organization}/{project}/_apis/Release/releases?api-version=5.0"
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($token)"))
$JSON = #"
{
"definitionId": $ID
}
"#
$response = Invoke-RestMethod -Uri $url -Headers #{Authorization = "Basic $token"} -Method Post -ContentType application/json -body $JSON
}

Can't change service connection in Azure DevOps release pipeline task

I have a release pipeline in Azure DevOps with one stage. The stage contains a task "Kubectl" to login to an AKS cluster. It expects a service connection as a parameter. My problem is that I get the service connection from the previous task which reads the value from "App Configuration". The value I get from App Configuration is set as an environment variable that I then pass on this way echo "##vso[task.setvariable variable=SC]$AKS_SERVICECONNECTION". So the variable is SC, and I set the service connection in "Kubectl"-login with $(SC). $AKS_SERVICECONNECTION has the correct value, I printed it out to check.
This doesn't work. The value is not set even though the environment variable SC has now the correct value. So, I tested it with the namespace parameter, and that works, just not with service connection. My question and assumption is that a service connection has to be set at execution-time, and can not be set in a previous task that a following task will use?
It seems that the service connection for Kubectl task is retrieved at compile time before the task being executed.
I created a testing variable on the release pipeline Variables section, and i changed the testing variable value in a script task using echo "##vso[task.setvariable... I saw in the task log that the original value for the testing variable was always picked.
See this similar issue here.
However, you can use the rest api as workaround. See below steps:
1, Add a second stage in your release pipeline. Select the trigger as Manual Only. Move the Kubectl task and related tasks in the second stage(ie. Kubetcl stage in below screenshot)
2, Define a variable ServiceCon in the Variables section. Select the variable Scope to the Second stage(ie.Kubetcl). Check Settable at release time
3, Add a script task to call update release environment rest api in the first stage (ie. SetServiceCon stage). See below inline powershell script: The variable SC is assigned the service connection name in the previous task.
$url = "https://vsrm.dev.azure.com/Org/Project/_apis/Release/releases/$(Release.ReleaseId)/environments/$($(Release.EnvironmentId)+1)?api-version=6.1-preview.7"
#override the variable ServiceCon by referencing to variable $(SC) from your previous task
$body = #{
status= "inProgress";
variables= #{ ServiceCon= #{value= $(SC)}}
}
Invoke-RestMethod -Uri $url -Headers #{Authorization = "Bearer $(System.AccessToken)"} -Method patch -Body (ConvertTo-Json $body) -ContentType "application/json"
Above script will trigger the second stage (ie. kubetcl stage) with the updated service connection name
4, In order the token $(System.AccessToken) can be accessed in above step, you need to go to the edit page of first stage and check the option Allow scripts to access the OAuth token See below screenshot.
5, You also need to allow the Manage deployments and edit release stage permission for the build service account. See below screenshot.
In your release pipeline edit page. Click the 3 dots on the top right corner. And select Security.
Allow the Manage deployments and edit release stage permission for the (ProjectName)build service (OrgName) account.
After complete above steps, and when your release pieline is triggerred, the first stage will be executed first and the script task will call the update release environment rest api. Then the second stage will be triggered with the updated service connection name

In an Azure DevOps release pipeline how do you deploy to multiple VMs a deployment group with different target folders

I started out with a release pipeline setup in azure DevOps to deploy a windows service to a deployment group which had only a single VM with an agent set up. I have a variable set in the pipeline for the deployment folder.
I'm now trying to expand this to deploy to 2 servers. I've added the second server into the deployment group and the registration has worked. On this server, the deployment needs to go to a different drive.
There doesn't seem to be a way to specify a different value for the variable by an agent.
I've tried googling and trawling around in the ui and so far I've found nothing. I'm wondering if variables are even the right thing?
Im going to answer my own question as the solution is actually a combination of the answers kindly provided by #Martin A #Tomasz Kaniewski and #Vito Liu-MSFT with a fair amount trial and error. I hope this will help others.
Environment Variables are the key to identifying the deployment folder so I set up a system environment variable called AutomationDeploymentRoot on each of my VM's
You must restart the Azure Pipelines Agent windows service on each VM before changes to environment variables are picked up!!
I found that the support for environment variables to be quite inconsistent between the different tasks - they seem to work well in script tasks but not so well in others such as CopyFiles.
The most reliable approach was to copy the environment variable into a pipeline variable (deployment.root) which I set up on the variable tab like so
And then set the variable from script as suggested by Thomasz and Vito
steps:
- script: |
#echo ##vso[task.setvariable variable=deployment.root]%AutomationDeploymentRoot%
displayName: 'Set Deployment Folder'
when this runs the c:\temp\deploy is replaced by the correct folder for the target machine and everything goes green!
You can set a variable from the script: https://learn.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&tabs=classic%2Cpowershell#set-variables-in-scripts
Write a script that will be able to determine on which machine it is running and assign a proper value to a variable.
Agree with Tomasz.
We can set the variable via the power script Write-Host "##vso[task.setvariable variable={variable name}]{variable value}", then we can call the variable in the another task.
Please refer this answer for more details
In addition, we can update the release pipeline variable via this API Update a release definition.
a. Open the release pipeline and add a new variable test and grant test Build Service (xxx) account the Edit release pipeline permission. (open the release pipeline--> ... --> Security --> Edit release pipeline set to Allow).
b. Open pipeline, enable the feature Allow scripts to access the OAuth token (Click Agent Job Name=>Additional options) add task powershell and enter the script below to update the release variable test value.
$url = "https://vsrm.dev.azure.com/{org name}/{project name}/_apis/release/definitions/{release definition ID}?api-version=6.0-preview.4"
Write-Host "URL: $url"
$pipeline = Invoke-RestMethod -Uri $url -Headers #{
Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
}
Write-Host "Pipeline = $($pipeline | ConvertTo-Json -Depth 100)"
# Update an existing variable named test to its new value
$pipeline.variables.test.value= {new variable value}
####****************** update the modified object **************************
$json = #($pipeline) | ConvertTo-Json -Depth 99
$updatedef = Invoke-RestMethod -Uri $url -Method Put -Body $json -ContentType "application/json" -Headers #{Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"}
write-host "=========================================================="
Write-host "The value of Varialbe 'test' is updated to" $updatedef.variables.test.value
write-host "=========================================================="

expression validation if a specific artifact is triggered azure devops

I have multiple artifacts and i would detect if one of these artifacts is triggered after build and deploy it to its respective agent
or(succeeded(), eq(variables['Build.SourceBranch'], '$_Multi-Country/SSIS_FileDrop/Dev/DEV'))
Since you can have multiple artifacts sources tied to one release definition, there's no such pre-defined variable exists could achieve the artifacts name.
Though artifacts source is not unique for release pipeline, but the build id which relevant with the artifacts is unique in release, and it can be got with one pre-defined variable Build.Buildid.
So, here agree with #MarTin's comment, you could use this api to achieve the artifacts name firstly.
Below is the powershell script sample:
$url = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)$env:SYSTEM_TEAMPROJECTID/_apis/build/builds/$env:BUILD_BUILDID/artifacts?api-version=4.1"
$pipeline = Invoke-RestMethod -Uri $url -Headers #{
Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
} -Method Get
Write-Host "artifactName:" ($artifactName = $Pipeline.value.name)
Write-Host "##vso[task.setvariable variable=artifactName]$artifactName"
In this script, use environments SYSTEM_TEAMFOUNDATIONCOLLECTIONURI and SYSTEM_TEAMPROJECTID to get the current org name and project name. Also, the latest version that supports this api is 4.1.
You can add this powershell task in the first step of the agent job. Then, you will be able to use the variable artifactName in the condition expression to validate whether the trigger artifact name is the specific one.

Resources