Sometimes as part of your pull request process, you may want to include outputs, checks, or other relevant information as comments after your pipeline runs on various stages and tasks. In this blog post we will look and how this can be achieved using a bash task and Azure DevOps API
Prerequisites
I will be using a service connection within my pipeline that will be running the task to write a comment using the Azure DevOps API. This connection will need to have the configuration: Contribute to pull requests
set to Allow
for the specific Azure DevOps repository
The Bash script
As mentioned in the above, I will be using bash to interact with the Azure DevOps API, here is the script:
COMMENT=$(echo "Test PR comment from Azure DevOps Pipeline")
ADO_API=$(echo "$(System.CollectionUri)$(System.TeamProject)/_apis/git/repositories/$(Build.Repository.Name)/pullRequests/$(System.PullRequest.PullRequestId)/threads?api-version=7.1-preview.1")
PR_COMMENT=$(jq --arg comment "$COMMENT" '.comments[0].content = $comment' <<< '{"comments": [{"parentCommentId": 0,"content": "","commentType": 1}],"status": 1}')
curl --request POST "$ADO_API" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "Authorization: Bearer $SYSTEM_ACCESSTOKEN" \
--data "$PR_COMMENT" \
--verbose
Bash Script Breakdown
COMMENT=$(echo "Test PR comment from Azure DevOps Pipeline")
COMMENT
variable will be the value that is going to be added on the Azure Repo Pull Request comment
ADO_API=$(echo "$(System.CollectionUri)$(System.TeamProject)/_apis/git/repositories/$(Build.Repository.Name)/pullRequests/$(System.PullRequest.PullRequestId)/threads?api-version=7.1-preview.1")
ADO_API
variable is used to build the concatenated Azure DevOps API endpoint URL. The values System.CollectionUri
, System.TeamProject
, Build.Repository.Name
, and System.PullRequest.PullRequestId
are predefined Azure DevOps variables as documented here
PR_COMMENT=$(jq --arg comment "$COMMENT" '.comments[0].content = $comment' <<< '{"comments": [{"parentCommentId": 0,"content": "","commentType": 1}],"status": 1}')
PR_COMMENT
variable modifies the json structure using jq that the API endpoint will understand. Example output:
{
"comments": [
{
"parentCommentId": 0,
"content": "Test PR comment from Azure DevOps Pipeline",
"commentType": 1
}
],
"status": 1
}
curl --request POST "$ADO_API" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "Authorization: Bearer $SYSTEM_ACCESSTOKEN" \
--data "$PR_COMMENT" \
--verbose
Finally the curl command that will send a POST
request to Azure DevOps API with the required $PR_COMMENT
, authorisation uses $SYSTEM_ACCESSTOKEN
which I will discuss in the below Azure DevOps pipeline
Azure DevOps Pipeline
Here is the example Azure DevOps pipeline:
- task: Bash@3
displayName: 'Example PR Comment'
inputs:
targetType: 'inline'
script: |
COMMENT=$(echo "Test PR comment from Azure DevOps Pipeline")
ADO_API=$(echo "$(System.CollectionUri)$(System.TeamProject)/_apis/git/repositories/$(Build.Repository.Name)/pullRequests/$(System.PullRequest.PullRequestId)/threads?api-version=7.1-preview.1")
PR_COMMENT=$(jq --arg comment "$COMMENT" '.comments[0].content = $comment' <<< '{"comments": [{"parentCommentId": 0,"content": "","commentType": 1}],"status": 1}')
curl --request POST "$ADO_API" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "Authorization: Bearer $SYSTEM_ACCESSTOKEN" \
--data "$PR_COMMENT" \
--verbose
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
Notice the environment variable SYSTEM_ACCESSTOKEN
highlighted above?
https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml#systemaccesstoken
System.AccessToken
is a special variable that carries the security token used by the running build.
Another value to note is: $(System.PullRequest.PullRequestId)
System.PullRequest.PullRequestId | The ID of the pull request that caused this build. For example: 17 . (This variable is initialized only if the build ran because of a Git PR affected by a branch policy). |
Awesome, running this will show the example below. We can see the automated comment from Azure DevOps pipeline
Full Azure DevOps pipeline example:
name: $(BuildDefinitionName)_$(date:yyyyMMdd)$(rev:.r)
trigger: none
pr: none
stages :
- stage: example
jobs:
- job: example
continueOnError: false
steps:
- task: Bash@3
displayName: 'Example PR Comment'
inputs:
targetType: 'inline'
script: |
COMMENT=$(echo "Test PR comment from Azure DevOps Pipeline")
ADO_API=$(echo "$(System.CollectionUri)$(System.TeamProject)/_apis/git/repositories/$(Build.Repository.Name)/pullRequests/$(System.PullRequest.PullRequestId)/threads?api-version=7.1-preview.1")
PR_COMMENT=$(jq --arg comment "$COMMENT" '.comments[0].content = $comment' <<< '{"comments": [{"parentCommentId": 0,"content": "","commentType": 1}],"status": 1}')
curl --request POST "$ADO_API" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "Authorization: Bearer $SYSTEM_ACCESSTOKEN" \
--data "$PR_COMMENT" \
--verbose
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
Azure DevOps Pipeline example can be found in GitHub here