Managing a CI/CD Pipeline from another Pipeline - Azure Devops - azure-devops

I have a pipeline(Say A). In it, I have written a PowerShell script which helps me to update a particular package in the solution. After merging the changed code with the master branch using this PowerShell script, it automatically triggers another pipeline(say B) whose triggering depends on the changes in master. I have to control the triggering of this pipeline B from Pipeline A - like get the status of the triggered pipeline B, disable the trigger of pipeline B from A, etc. Please help me with this scenario.

You can use a powershell task to call build rest api to get the status of another pipeline(ie. Pipeline B).
First to get the latest build of Pipeline B, you can use below rest api.
GET https://dev.azure.com/{organization}/{project}/_apis/build/builds?definitions={definitions}&$top={$top}&api-version=5.1
Below is the inline script example in the powershell task to get the build status.
$uri = "$(System.TeamFoundationCollectionUri)$(System.TeamProject)/_apis/build/builds?definitions={definitionId}&`$top=1&api-version=5.1"
 
$result =Invoke-WebRequest -Uri $uri -Method Get -ContentType "application/json" -Headers $headers = #{ Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"}
$status = $result.value[0].status
$env:SYSTEM_ACCESSTOKEN is the predefined variable with which you can refer to the access token directly in the scripts.
To cancel pipeline B in pipeline A you can call update Build rest api. See below example. First get the build from above api, then update the status to cancelling
$build = $result.value[0]
$uriupdate = "$(System.TeamFoundationCollectionUri)$(System.TeamProject)/_apis/build/builds/$($build.id)?api-version=5.1"
$build.status = "cancelling"
$body = $build | ConvertTo-Json -Depth 10
$update = Invoke-RestMethod -Uri $uriupdate -Headers #{Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"} -ContentType "application/json" -Method patch -Body $body
To skip a build when pushing the changes, you can just include [skip ci] in the commit message as Shamrai mentioned.
git commit -m message [skip ci]

I have to control the triggering of this pipeline B from Pipeline A -
like get the status of the triggered pipeline B, disable the trigger
of pipeline B from A, etc.
You can use REST API with PowerShell to control your builds: Builds - List.
To disable the trigger, add scip ci into your commit message: Skipping CI for individual commits

You can use output variable in powershell task. And based on that you can control the next job to execute. This way you don't have to use multiple build pipelines instead multiple jobs in a single pipeline.
You can refer the Microsoft document here

Related

Azure DevOps YAML Pipelines prevent newer runs if old one queued

I have a pipeline with a number of stages, e.g.:
Canary -> Dev -> UAT -> Prod
For each stage we have approvals set so a team member has to allow a build to proceed to the next stage. Sometimes we have long periods between stages being approved (e.g. someone needs to do some testing and feedback outside of devops we can proceed), therefore it can be hard to remember we have an old run pending approval unless we specifically check - which is prone to human error.
But if I have one build say queued at UAT awaiting push to production how can I prevent a second run which includes the changes from the first run (as they are both running off master) being allowed to proceeded.
E.g. I need newer jobs to be aware of older runs still pending approval to proceed.
Thanks!
There is no default way to prevent newer runs if old one queued, but you can try the following workaround:
You could add a script in the pipeline to check state of the latest pipeline run. If the state is inProgress, cancel the build. If the state is completed, proceed the build.
You should use Runs - List api to get state of the latest pipeline run. The script looks like:
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
$uri = "https://dev.azure.com/$org/$projectName/_apis/pipelines/$pipelineid/runs?api-version=6.0-preview.1"
$result = Invoke-RestMethod -Uri $uri -Method Get -Body $json -ContentType "application/json" -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
$latestrun = $result.value.state[0]
Write-Host "$latestrun"
Then you could refer the following case to cancel the build if $latestrun is inProgress:
Is it possible to cancel a Azure DevOps pipeline Job programmatically?

Azure cli: clone pipeline

Looking at az pipelines documentation it seems it's not possible to clone a pipeline using cli.
I've looked at getting the yaml (az pipelines show -name=x > x_orig.yaml) and then trying to change json and create pipeline from modified yaml, but that feels like a lot of work that could break after next update.
Is there a way to clone a pipline without going the the Web UI?
Currently, there indeed is not available Azure CLI that can clone or export/import a pipeline to create a new pipeline.
I also searched and tried the Azure DevOps REST API for Pipelines, but did not find the available API.
Ideally, the Azure CLI "az pipelines create" can provide an input parameter that allows users specify an existing pipeline as a starting point for the new pipeline.
If your projects really need this feature, I recommend that you can directly report a feature request on the "Azure/azure-cli" repository to ask adding the parameter like as above mentioned. That will allow you directly interact with the appropriate engineering team, and make it more convenient for the engineering team to collect and categorize your suggestions.
As a workaround, we could clone the build definition via power shell script to call REST API.
Note: We need to change the original build definition name.
REST API
Get build definition:
GET https://dev.azure.com/{organization}/{project}/_apis/build/definitions/{definitionId}?api-version=6.0
Create build definition
POST https://dev.azure.com/{organization}/{project}/_apis/build/definitions?api-version=6.0
Power shell script
$connectionToken="{pat}"
$base64AuthInfo= [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($connectionToken)"))
$BuildDefinitionInfoURL = "https://dev.azure.com/{org name}/{project name}/_apis/build/definitions/386"
$BuildDefinitionInfo = Invoke-RestMethod -Uri $BuildDefinitionInfoURL -Headers #{authorization = "Basic $base64AuthInfo"} -Method Get
Write-Host $BuildDefinitionInfo.name
$BuildDefinitionInfo.name = $BuildDefinitionInfo.name +" clone"
Write-Host $BuildDefinitionInfo.name
$body = $BuildDefinitionInfo | ConvertTo-Json -Depth 99
$createBuildDefinitionURL = "https://dev.azure.com/{org name}/{project name}/_apis/build/definitions?api-version=6.0"
$response = Invoke-RestMethod -Uri $createBuildDefinitionURL -ContentType "application/json" -Body $body -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} -Method POST
Write-Host $response.id
Result:

How to trigger release in second release definition when a stage passes in first release definition in azure devops

I have two release definitions release-def-1 and release-def-2 in azure devops.
I want to trigger a release in second one(release-def-2) once the deployment in first(release-def-1) succeeds.
Is there a way to achieve this?
I tried to find several trigger settings in release definition triggers but could not find anything relevant to what I need.
I know I can add multiple stages in the same release definition but that not what I am looking for.
As a workaround, you can add a Trigger Azure DevOps Pipeline task at the end of the job and set the task running conditions: Only when all previous tasks have succeeded. In this way, when the first release pipeline is successfully deployed, the second release pipeline will be automatically triggered.
We could not configure it in the release trigger.
As a workaround, we could open release-def-1 add task power shell at the end of the job and call the REST API to trigger release pipeline(release-def-2).
Power shell script:
$token = "{PAT}"
$url = "https://vsrm.dev.azure.com/{Org name}/{Project name}/_apis/Release/releases?api-version=5.0"
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($token)"))
$JSON = #"
{
"definitionId": {release-def-2 definition ID}
}
"#
$response = Invoke-RestMethod -Uri $url -Headers #{Authorization = "Basic $token"} -Method Post -ContentType application/json -body $JSON
}

Azure DevOps integration in Sentry: Associate commits

Did someone manage to integrate Azure DevOps in Sentry (sentry.io)? I stuck on "Associate commits with a Release" (see: https://docs.sentry.io/workflow/releases/?platform=browser#associate-commits-with-a-release)
I can not figure out a way how I can tell Sentry (by API) which commit ids are associated with a current release/deploy. How can I add a task to the pipeline which will post the commit ids to Sentry API? Or is there some other way to do it?
In azure devops, the Powershell task also support curl. So, you can execute the api in powershell task of VSTS pipeline directly.
In release pipeline, there has a pre-defined release variable, it stores the commit id which is associated with the current release pipeline: $(Release.Artifacts.{alias}.SourceVersion). Here alias is the artifacts name, and you can get it by getting $(Release.PrimaryArtifactSourceAlias).
First, create variables like this:
Then you can apply the variable $(id) into that API, and execute the api in powershell task:
"refs": [{
"commit":"$(id)"
}]
Now, the commit id could be packed into the body of this api, and send to the Sentry server.
If there has multiple commits associate with this release, since the variable $(Release.Artifacts.{alias}.SourceVersion) I mentioned above only store the latest commit message, here you may need add additional scripts to get what you want by Build id.
In release pipeline, with $(Build.BuildId) you can get the corresponding buildid which associate with this release. And then, you could get the commits(changes) by using this API:
GET https://dev.azure.com/{organization}/{project}/_apis/build/changes?fromBuildId={fromBuildId}&toBuildId={toBuildId}&api-version=5.1-preview.2
You could apply these powershell script into your task without change anything because this script is universal among powershell-ise, powershell command line and powershell task in VSTS.
$token = "{PAT token}"
$url="https://dev.azure.com/{org name}/{project name}/_apis/build/changes?fromBuildId={id1}&toBuildId={id2}"
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($token)"))
$response = Invoke-RestMethod -Uri $url -Headers #{Authorization = "Basic $token"} -Method Get
Write-Host "results = $($response.value.id | ConvertTo-Json -Depth 100)"
Now, you could get the list of commits which associate with the build and corresponding release.

How to set the Description of an Azure DevOps Release via script?

In Azure DevOps I'm trying to set the release description via PowerShell / CMD in order to have a dynamic description of my releases based on the input of the artifacts from the build step.
I've tried setting the release variables via powershell like:
Write-Host "##vso[task.setvariable variable=release.releasedescription;]bar"
Write-Host "##vso[task.setvariable variable=RELEASE_RELEASEDESCRIPTION;]bar"
But that didn't work and the description field remains always empty.
Is there any tweak / setting that would help achieve this behavior?
What you tried to do is just to set the environment variable that contains the release description data and not set the "real" release description, so after the release finished the description not changed.
If you want to set the release description during the release you can try to do it with Azure DevOps Rest API - Update Release.
So add a PowerShell task that executes the Rest API with Invoke-RestMethod, get the current release with GET method and then update the release with PUT, in the body change the description to the new one.
You could do this too:
- bash: |
echo "Updating pipeline job Run description"
echo "##vso[build.updatebuildnumber]$(Build.BuildNumber) $(App_Name)"
displayName: "Set pipeline job Run description for Azure DevOps console"
For anyone who simply wants to set the name of an Azure Pipelines run, you can find the description here.
TLDR: Set the top-level name: attribute.
Here is the PowerShell script to set release description in DevOps. Before the stage that need approval, add a PowerShell task to invoke REST API to change the release description. Please use your own orgName, projectName, PAT and modify the release description.
$url = https://vsrm.dev.azure.com/<orgName>/<ProjectName>/_apis/release/releases/$(Release.ReleaseId)?api-version=6.0
$token="PAT"
$base64AuthInfo= [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($token)"))
$head = #{ Authorization =" Basic $base64AuthInfo" }
$pipeline = Invoke-RestMethod -Uri $url -Headers $head -Method Get
$Pipeline.description = "<Modify the release description>"
$body = $Pipeline | ConvertTo-Json -Depth 100
$url2=https://vsrm.dev.azure.com/<orgName>/<ProjectName>/_apis/release/releases/$(Release.ReleaseId)?api-version=6.0
$resp = Invoke-RestMethod -Uri $url2 -Method Put -Headers $head -Body $body -ContentType application/json