Passing variables between jobs for Azure DevOps pipelines

Using Azure DevOps, you can create pipeline variables dynamically. Out of the box, most dynamic variables are scoped to the job. But, if you need to, you can reference pipeline variables defined in other jobs. For example, if you have a stage that has multiple jobs because you need something done in Linux and something in Windows, then you can consume a dynamic pipeline variable created by another job.

Background

You might be familiar with how to set static pipeline variables through YAML.

variables:
  someName: someValue

But, what if you want to create this variable using data from a task? For example, you want to dynamically provision Azure resources using a Terraform or ARM Template task. Then, you also want to set pipeline variables to represent the names of the resources so that you can deploy to that infrastructure.

You can set a dynamic pipeline variable by writing to the host console.

Powershell:

powershell: |
  Write-Host "##vso[task.setvariable variable=someName;]someValue"

Bash:

bash: |
  echo "##vso[task.setvariable variable=someName;]someValue"

Now, you will be able to use this like a regular pipeline variable.

powershell: |
  Write-Host "The value of the pipeline variable is $(someName)"

But, you won’t be able to use this variable from a different job… yet. By default, it’s scoped to the job.

Variables from another job

Note: Shoutout to Maikel who caught a regression in the syntax and fixed the example below.

To make a variable accessible from another job, there’s a couple of things you want to do. Microsoft also has some documentation on this feature called output variables.

First, when creating the dynamic pipeline variable, specify that it’s an output variable.

powershell: |
  Write-Host "##vso[task.setvariable variable=someName;isOutput=true;]someValue"

Then assuming you have multiple jobs, add a dependency from one job to another.

- job: job_deploy_code
  displayName: Deploy Some Code
  dependsOn: ['job_deploy_infrastructure']

Then define some a variable scoped to the job.

variables: 
  someName: $[ dependencies.job_deploy_infrastructure.outputs['setVariable.someName'] ]

Putting it all together

stages:
- stage: stage_deploy
  displayName: Production
  jobs: 
  - job: job_deploy_infrastructure
    displayName: Deploy Some Infrastructure
    steps:
    - bash: |
        SOMEVALUE="bleh"
        echo "##vso[task.setvariable variable=someName;isOutput=true;]$SOMEVALUE"
        echo "variable value is $(someName)"
  - job: job_deploy_code
    displayName: Deploy Some Code
    dependsOn: ['job_deploy_infrastructure']
    variables: 
      someName: $[ dependencies.job_deploy_infrastructure.outputs['setVariable.someName'] ]
    steps: 
    - bash: |
        "the variable value is $(someName)"