DEV Community

Deyan Petrov
Deyan Petrov

Posted on

Running and Approving Azure DevOps Pipelines from the terminal

TLDR; This bash script will allow you to start and approve (multiple) Azure DevOps pipelines from the terminal.

Introduction

If you are using Azure DevOps Pipelines (similar to Github Actions) you might be going to the browser, navigating to the list of pipelines, selecting one, and clicking on the "Run pipeline" + "Run" buttons. If you want to start 10 pipelines (e.g. for 10 microservices) at once, you need to do the above clicking 10x2 times.

Once the builds have reached a stage guarded by an approval, you have to go into the build, click the "Review" + "Approve" buttons ... which would be another 10x2 clicks.

Wouldn't it be better to trigger the above from the terminal/CLI? You are happy to find the az pipelines run az cli extension command, however things become very tricky when it comes to the approvals ...

The rest of this post is referring to a pipeline with 3 Stages - Build, Deploy to test and Deploy to prod

Image description

The az rest .. --resource .. command

Before we get to solving the approval problem, there is one very useful command that will help us immensely - az rest. This command allows us to invoke various Azure DevOps (and probably other) APIs without any personal access tokens (PATs) or similar. The important attribute to pass is --resource "https://management.core.windows.net/", which reuses our Azure DevOps session.

For example, a much faster alternative to az pipelines run is the following command:

az rest --uri "https://dev.azure.com/$org/$project/_apis/pipelines?api-version=7.1" --resource "https://management.core.windows.net/"
Enter fullscreen mode Exit fullscreen mode

Pretty neat solution to the generally very nasty authentication topic, which usually requires some awkward token handling!

Resource Model and Relations, or how to find the Approval

In order to implement the approval action, one has to first understand how to get to it, which requires navigation through a couple of Azure DevOps resources, namely:

  1. Pipeline
  2. Last Build
  3. Build Timeline and 3 specific records
  4. Approval

Pipeline

So first we find the pipelineId by pipeline name:

pipelineId=$(az rest --uri "$adoBaseUrl/pipelines?api-version=7.1" --resource $resource | jq -c ".value.[] | select( .name == \"$pipeline\" ).id")

Enter fullscreen mode Exit fullscreen mode

where adoBaseUrl=https://dev.azure.com/$org/$project/_apis/ and resource=https://management.core.windows.net/

Last Build

Next we find the last build for this pipeline:

build=$(az rest --uri "$adoBaseUrl/build/builds?api-version=7.1&definitions=$pipelineId&queryOrder=startTimeDescending&\$top=1" --resource $resource)
Enter fullscreen mode Exit fullscreen mode

and from it we extract the timeline url:

timelineUrl=$(echo $build | jq -r '.value[0]._links.timeline.href')
Enter fullscreen mode Exit fullscreen mode

Build Timeline

Getting the contents of the pipeline is easy:

timeline=$(az rest --uri "$timelineUrl" --resource $resource)
Enter fullscreen mode Exit fullscreen mode

however it contains tons of records - depending on the pipeline definition, each one having parent record. We need to find the record corresponding to the approval stage, and for that we need to traverse (at least in my particular case) 3 records:

  • deploy Stage record
  • Checkpoint record
  • Checkpoint.Approval record

This is done in the following way:

deployStageRecordId=$(echo $timeline | jq -r ".records[] | select( .identifier == \"$deployStageRecordIdentifier\" and .type == \"Stage\" ).id")

checkpointRecordId=$(echo $timeline | jq -r ".records[] | select( .parentId == \"$deployStageRecordId\" and .type == \"Checkpoint\" ).id")

approvalId=$(echo $timeline | jq -r ".records[] | select( .parentId == \"$checkpointRecordId\" and .type == \"Checkpoint.Approval\" ).id")
Enter fullscreen mode Exit fullscreen mode

The last one gives us the approvalId!

Approval

Once we have the approvalId we can get for example its status, so that we approve only if the status is pending:

approvalStatus=$(az rest --uri "$adoBaseUrl/pipelines/approvals/$approvalId?api-version=7.1" --resource $resource | jq -r ".status")
Enter fullscreen mode Exit fullscreen mode

Finally, approve!

Once the approvalId is found, the following POST command must be issued to Review/Approve it:

az rest --method PATCH --uri "$adoBaseUrl/pipelines/approvals?api-version=7.1" --resource $resource --body "[ { \"approvalId\":\"$approvalId\", \"comment\":\"cli\", \"status\":\"approved\" } ]"
Enter fullscreen mode Exit fullscreen mode

The full script can be found at https://github.com/deyanp/adopipelines/blob/main/pipeplines.sh

References

Heroku

Build apps, not infrastructure.

Dealing with servers, hardware, and infrastructure can take up your valuable time. Discover the benefits of Heroku, the PaaS of choice for developers since 2007.

Visit Site

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs