Search code examples
azure-devopsazure-pipelinescicdazure-pipelines-yaml

Passing output variable, known only at runtime, from job1 to template job2 in an AzureDevOps pipeline


I have an azure devops pipeline that has a job template.

I need to pass a variable from a previous job into the job template.

Within a job you can export a variable:

echo "##vso[task.setvariable variable=runtimevar1]test"

Across jobs you can set a flag, and import it inside variables in the next job:

    variables:
      var1: $[ dependencies.job1.outputs['setvars.runtimevar2'] ]

echo "##vso[task.setvariable variable=runtimevar2;isOutput=true]test2"

However, when using a template this does not work, since you cannot pass a variable block to the template

Is there a simple way to pass an output variable (that is only known at run time) from job1 to job2 when job2 is a template?



Full example:

  • primary pipeline:
# ################################################################
# Update the network packages

# Push new network JSON to Topdesk
# Triggers whenever connectivityJSON is updated in main branch
# ################################################################

name: testing-passing-vars

trigger: none

stages:
- stage: stage1
  jobs:
  - job: job1
    steps:
    - checkout: self

    # set a variable
    - script: |
        echo "##vso[task.setvariable variable=runtimevar1]test"
        echo "##vso[task.setvariable variable=runtimevar2;isoutput=true]test2"
      name: setvars
      displayName: 'set vars'

    - script: |
        echo "within a job local var is available"
        echo runtimevar1: $(runtimevar1) # this works
        echo runtimevar2: $(runtimevar2) # this does not work
      displayName: echovars

  - job: job2
    dependsOn: job1
    variables:
      var2: "$[ dependencies.job1.outputs['setvars.runtimevar2'] ]"
    steps:
    - checkout: self

    - script: |
        echo "between jobs only the explicitely exported var is available and using the dependencies keyword in variable block op job"
        # echo runtimevar1: $(runtimevar1) # this will not work
        echo "var2: $(var2)" # this works
      displayName: echovars

  # this does not work
  - template: ./templates/jobs/test-job.yaml
    parameters:
      var1: "$[ dependencies.job1.outputs['setvars.runtimevar2'] ]"
      var2: "empty"
      dependson: job1
   
  # # this is not allowed
  # - template: ./templates/jobs/test-job-variables-template.yaml
  #   variables:
  #     var2: $[ dependencies.job1.outputs['setvars.runtimevar2'] ]
  #   parameters:
  #     var1: $(var2)
  #     var2: "empty"

  • template inside "templates/jobs/test-job.yaml"
parameters:
  - name: var1
    type: string

  - name: var2
    type: string

  - name: dependson
    type: string

jobs:
  - job: testjob
    displayName: testjob-template1
    dependsOn: ${{ parameters.dependson }}
    variables:
      - name: localvar1
        value: "localvar"
      - name: remotevar
        value: "$[ dependencies.job1.outputs['setvars.runtimevar2'] ]"

    steps:
    - checkout: self

    - script: |
        echo param1 var1 ${{ parameters.var1 }}
        echo param2 var2 ${{ parameters.var2 }}
        echo local var ${{ variables.localvar1 }}
        echo remote var ${{ variables.remotevar }}
      displayName: 'echo vars'

Solution

  • You can't pass output variables via parameters. Parameters need to be given in advance, can't be the runtime produced.

    But you can define the variable in template jobs using $[ dependencies.job1.outputs['setvars.runtimevar2'] ] as in your sample code, and then use it echo remote var $(remotevar) instead of ${{ variables.remotevar }}

    I think you are following the right approach, but some errors occurred when using variables

    Here is your sample code with some minor modifications.

    main.yml

    stages:
    - stage: stage1
      jobs:
      - job: job1
        steps:
        # set a variable
        - script: |
            echo "##vso[task.setvariable variable=runtimevar1]test"
            echo "##vso[task.setvariable variable=runtimevar2;isoutput=true]test2"
          name: setvars
          displayName: 'set vars'
    
        - script: |
            echo runtimevar1: $(runtimevar1)
            echo runtimevar2: $(setvars.runtimevar2)
          displayName: echovars
    
      - job: job2
        dependsOn: job1
        variables:
          var2: $[ dependencies.job1.outputs['setvars.runtimevar2'] ]
        steps:
        - script: |
            echo "var2: $(var2)"
          displayName: echovars
    
      # this does not work
      - template: ./test-job.yaml
        parameters:
          var1: "hello world"
    

    test-job.yml

    parameters:
    - name: var1
      type: string
    
    jobs:
    - job: testjob
      displayName: testjob-template1
      dependsOn: job1
      variables:
      - name: remotevar
        value: $[ dependencies.job1.outputs['setvars.runtimevar2'] ]
    
      steps:
      # Get the Azure credentials for this environment
      - script: |
          echo param1 var1 ${{ parameters.var1 }}
          echo remote var $(remotevar)
        displayName: 'echo vars'
    

    Please note the relative path of my file