Change Azure DevOps Variables from Within the Build

Koen van Zeijl
October 21, 2020 5 min read
Koen van Zeijl
https://images.unsplash.com/photo-1507823690283-48b0929e727b

Introduction

In my previous blog 'Embed Your Instagram Feed in 2020', I found out that the Instagram API for fetching your feed was changed. What a bummer! So I found a way to fetch your Instagram feed (The subject of my next blog). Unfortunately, this requires you to use a token that is only valid for 60 days. You can request a new token in the Facebook portal but this has another downside. You’ll need to do a commit every 60 days to keep your feed working. This made me curious if it was possible to automatically fetch a new token during a build so that your feed stays alive.

A disadvantage of this method is that the token that is returned from the Facebook portal must be saved, as it must be used again to retrieve the next (new) token. After all, the currently valid token cannot be used to generate a new token after 60 days. I will do this by adding a variable to my Azure DevOps pipeline that I will update on every build that gets triggered.

In this blog, I’ll explain how you can adjust Azure DevOps pipeline variables from within the pipeline. To clarify my method, I‘ll use the Instagram example.

What do we need?

To follow this blog, you only need an Azure DevOps pipeline. In this pipeline, we will use the dotnet-json tool for reading and writing JSON.

Pipeline variabele

Do you already have your variable that you want to change in the pipeline? Then you can skip this step and move on to the next chapter.

If you don’t, you can do this while adjusting the pipeline. Press the variables button at the top right to open the variables overview. Then click add variable to add a new variable. You will see the following form:

Create a variable

Remember the name of your variable, you will need it later.

Edit the pipeline

In the pipeline, we will use a bash task. Azure DevOps hosted agents will have this task installed by default. Do you host an agent yourself? Then you may need to install bash first.

The following pipeline adjustments will update the token variable:

azure-pipelines.yml
- task: Bash@3
  inputs:
    targetType: 'inline'
    script: |
      dotnet tool update -g dotnet-json
      access_token=$(curl -s "https://graph.instagram.com/refresh_access_token?grant_type=ig_refresh_token&access_token=$(instatoken)" | dotnet json get - access_token)
      pipeline=$(curl -H "Authorization: Bearer $(System.AccessToken)" "$(System.TeamFoundationCollectionUri)/$(System.TeamProject)/_apis/build/definitions/$(System.DefinitionId)?api-version=5.0" | dotnet json set - variables:instatoken:value $access_token)
      curl -X PUT -H "Authorization: Bearer $(System.AccessToken)" -H "Content-Type: application/json" --data "$pipeline" "$(System.TeamFoundationCollectionUri)/$(System.TeamProject)/_apis/build/definitions/$(System.DefinitionId)?api-version=5.0"
      sed -i "s/placeholder_token/$access_token/" '$(Build.SourcesDirectory)/nuxt.config.js'

The explanation

But what exactly does it all do? Below I explain every step.

The set-up

The first 4 lines indicate that a bash script needs to run, the code after the pipe | indicates which script needs to run.

Install dotnet-json

dotnet tool update -g dotnet-json: ensures that the latest version of dotnet-json is installed. This is needed to read and update a JSON object.

Fetch the variable

The next line is used to fetch a new token from the Instagram API.

The command to make a curl request to the Instagram API looks like, curl -s "https://graph.instagram.com/refresh_access_token?grant_type=ig_refresh_token&access_token=$(instatoken) The old pipeline variable $(instatoken) is used to fetch a new token.

After receiving a result from the API I use dotnet json get to extract my token from this result. By placing a - after the get, the default input is used as the input for dotnet-json. The | after the curl request makes sure that the API result is considered the default input. Finally, you’ll need to indicate which value of the JSON result you want to get, in my case this was access_token.

To make the code easier readable I will store the value of access_token in a bash variable. This can easily be done by placing the curl request and the result parsing inside $(...) and assigning it to the variable access_token.

Fetch current pipeline

The current pipeline can easily be retrieved via a URL where the token of the pipeline ($(System.AccessToken), this is a default DevOps variable) is being used for authorization. All other tokens in the following string are also default in every Azure DevOps pipeline, so you can literally copy and paste it into your pipeline. curl -H "Authorization: Bearer $(System.AccessToken)" "$(System.TeamFoundationCollectionUri)/$(System.TeamProject)/_apis/build/definitions/$(System.DefinitionId)?api-version=5.0".

After receiving a result from the API, I adjusted this pipeline by replacing the current variable with my new token. Once again this is done by the help of dotnet-json. To accomplish this I used the following string: dotnet json set - variables:instatoken:value $access_token. In my case instatokenis the name of the chosen variable. Again I’ll save my new pipeline using a bash variable.

Update the pipeline

Now we just have to update the stored pipeline within Azure DevOps. This time we need to do a curl PUT request to send it back to Azure DevOps. curl -X PUT -H "Authorization: Bearer $(System.AccessToken)" -H "Content-Type: application/json" --data "$pipeline" "$(System.TeamFoundationCollectionUri)/$(System.TeamProject)/_apis/build/definitions/$(System.DefinitionId)?api-version=5.0".

The variable $(System.AccessToken) is provided as a header to authorize the request. The second header Content-Type: application/json indicates that JSON will be sent as the data type. The $pipeline variable is provided to the --data argument to send the new pipeline JSON. Finally, the URL is used to define where the PUT request is sent to.

Use your variable

In the last line of my script, I make use of the newly acquired token by modifying a file with the token so that it can be used in the publishing step of the pipeline. Of course, this is not the goal for everyone, so replace that line with the script you need for your pipeline.

Conclusie

So it is definitely possible to adjust your pipeline from within the pipeline itself. If you are trying to adjust the pipeline yourself and you are running into problems, please let me know and maybe I can help you to fix them.

Did you succeed in changing the pipeline? Super cool, let me know in the comments what you are using it for.