1

I have two tasks in my pipeline- the first of which is a powershell-based task from the marketplace. It updates a build variable, using a logging command (e.g. Write-Host '##vso[task.setvariable variable=test]abc') which is persisted across build runs. You can see it, and its value, in the "Variables" section of the build in Azure DevOps.

The second task is a powershell task and uses the value of the variable set in the previous task and performs an operation using its value. It uses the powershell environment syntax, e.g. $env:TEST.

The problem I'm having is, even though the first task correctly updates the variable, the powershell task appears to still get the old value (as it was before the first task ran).

What do I need to do in order for my powershell task to correctly read the new value of the variable?

Also, here is the actual code for my powershell task (I'm trying to tag the latest git commit with the version variable set by the AutoVersion task as you can probably tell):

  - powershell: |
      git tag $env:AUTOVERSION
      git push origin $env:AUTOVERSION
    workingDirectory: $(Build.SourcesDirectory)
    displayName: 'Tag Sources'
Adam Drewery
  • 1,508
  • 1
  • 17
  • 25

1 Answers1

4

OK. Let's unpack this.

When using ##vso[task.setvariable..., you have two options for creating the variable (forgetting secret for this discussion) - isOutput=true, and not. If isOutput=true, this is added to the job's outputs (by its job and step name). If not, it's set up as an environment variable for subsequent steps in the same job.

Without isOutput=true, it's not available to other jobs or stages. With or without it, the variable is not available until you're outside the task in which it's written to the console (because the variables are processed by scraping the console output).

Try creating a pipeline from the following - it shows how to use output vs environment variables, how to communicate between steps in the same job, as well as between jobs:

jobs:
  - job: Job1
    steps:
      - pwsh: |
          
          # isOutput=true makes the variable name accessible via StepName.VarName macro syntax
          Write-Host "##vso[task.setvariable variable=SomeVar;isOutput=true]Hello (output), job 1, step 1"

          # not using isOutput=true makes the variable accessible from the environment
          Write-Host "##vso[task.setvariable variable=SomeEnvVar]Hello (environment), job 1, step 1"
        name: Step1
      - pwsh: |

          Write-Host "##vso[task.setvariable variable=SomeVar;isOutput=true]Hello (output), job 1, step 2"
         
          # This works because Step1.SomeVar has isOutput=true
          Write-Host "Job1Step1OutputVar is $(Step1.SomeVar)"
          
          # The next would fail the step because it doesn't have isOutput=true
          # Write-Host "Job1Step1EnvVar is $(Step1.SomeEnvVar)"
          
          # This works because SomeEnvVar is not declared isOutput=true
          Write-Host "Job1Step1EnvVar is $($Env:SomeEnvVar)"

          # This fails silently (step succeeeds, no value) because SomeVar is declared isOutput=true
          Write-Host "Job1Step1OutputVarAsEnvVar is $($Env:SomeVar)"

        name: Step2
  - job: Job2
    # Prevent the job from running in parallel with Job1
    dependsOn: Job1 
    # you have to map other jobs' outputs into your job with variables
    variables: 
      Job1Step1Var: $[dependencies.Job1.outputs['Step1.SomeVar']]
      Job1Step2Var: $[dependencies.Job1.outputs['Step2.SomeVar']]
    steps:
      - pwsh: |
          Write-Host "##vso[task.setvariable variable=SomeVar;isOutput=true]Hello (output), job 2, step 1"
        name: Step1
      - pwsh: |
          Write-Host "##vso[task.setvariable variable=SomeVar;isOutput=true]Hello (output), job 2, step 2"
          Write-Host "Job1Step1Var is $(Job1Step1Var)"
          Write-Host "Job1Step2Var is $(Job1Step2Var)"
          Write-Host "Job2Step1Var is $(Step1.SomeVar)"
        name: Step2
  - job: Job3
    dependsOn: 
      # Even though Job1 is a dependency of Job2, we have to declare it here to access its output!
      - Job1 
      - Job2
    # you have to map other jobs' outputs into your job with variables
    variables: 
      Job1Step1Var: $[dependencies.Job1.outputs['Step1.SomeVar']]
      Job1Step2Var: $[dependencies.Job1.outputs['Step2.SomeVar']]
      Job2Step1Var: $[dependencies.Job2.outputs['Step1.SomeVar']]
      Job2Step2Var: $[dependencies.Job2.outputs['Step2.SomeVar']]
    steps:
      - pwsh: Write-Host "##vso[task.setvariable variable=SomeVar]Hello (environment), job 3, step 1"
        name: Step1
      - pwsh: |
          Write-Host "Job1Step1Var is $(Job1Step1Var)"
          Write-Host "Job1Step2Var is $(Job1Step2Var)"
          Write-Host "Job2Step1Var is $(Job2Step1Var)"
          Write-Host "Job2Step2Var is $(Job2Step2Var)"
          Write-Host "Job3Step1Var is $($Env:SomeVar)"
        name: Step2 
WaitingForGuacamole
  • 3,744
  • 1
  • 8
  • 22
  • Thanks, it turns out I've managed to work around the problem by retrieving the variable via the API, in the same way the "AutoVersion" task does. It feels a bit convoluted but it works. – Adam Drewery Apr 28 '21 at 08:53