EvilWeebl
EvilWeebl

Reputation: 701

Devops passing output from one job template step to another job template step

I have a template for running a terraform plan or apply depending on command parameter passed into the template.

The stage and template files looks like this (slimmed down for context).

  - stage: terraform_${{ parameters.environment }}
    displayName: "Stage1"
    jobs:
      - job: "TFPlan"
        steps:
          - template: ../steps/terraform-steps.yml
            parameters:
              command: plan
              subscription: ${{ variables['Terraform.Subscription'] }}

      - job: "TFApply"
        variables:
          changesPresent: $[ dependencies.TFPlan.outputs['Terraformplan.changesPresent'] ]
        steps:
          - template: ../steps/terraform-steps.yml
            parameters:
              command: apply
              subscription: ${{ variables['Terraform.Subscription'] }}
              changesPresent: $(changesPresent)
parameters:
  - name: command
    displayName: Terraform Command
    type: string
    default: plan
    values:
      - plan
      - apply

  - name: subscription
    displayName: Azure Subscription
    type: string

  - name: changesPresent
    displayName: Changes changesPresent
    type: string
    default: "false"

steps:
  - ${{ if eq(parameters.command, 'apply') }}:
    - powershell: |
        Write-Host "command = ${{parameters.command}}"
        Write-Host "changesPresent = ${{parameters.changesPresent}}"
        Write-Host "equals commandIsApply = ${{ eq(parameters.command, 'apply') }}"
        Write-Host "equals changesPresentisFalse = ${{ eq(parameters.changesPresent, 'false') }}"
        Write-Host "equals changesPresentisFalse = ${{ eq(parameters.changesPresent, false) }}"
        Write-Host "equals changesPresentisFalse = ${{ eq(parameters.changesPresent, False) }}"
        Write-Host "equals changesPresentisTrue = ${{ eq(parameters.changesPresent, 'true') }}"
        Write-Host "equals changesPresentisTrue = ${{ eq(parameters.changesPresent, true) }}"
        Write-Host "equals changesPresentisTrue = ${{ eq(parameters.changesPresent, True) }}"

  - ${{ if not(and(eq(parameters.command, 'apply'), eq(parameters.changesPresent, 'false'))) }}:
    - task: TerraformTaskV4@4
      name: Terraform${{ parameters.command }}
      displayName: Terraform ${{ parameters.command }}
      inputs:
        provider: azurerm
        command: ${{ parameters.command }}
        environmentServiceNameAzureRM: ${{ parameters.subscription }}

The TerraformTaskV4@4 step has an output of changesPresent (doc). I'm trying to access this output var from the first job that runs terraform plan and pass it into the second job to determine if it needs bother to run the terraform apply depending on whether there are any changes present.

As you can see from all the debug output in the template I'm trying to verify that when changesPresent is passed into the template as a parameter it is set to the value I expect.

Strangely the following line shows a value of false:

Write-Host "changesPresent = ${{parameters.changesPresent}}"

And yet every following line that tries to confirm that value with an eq() returns a False value. This is the output I'm getting:

command = apply
changesPresent = false
equals commandIsApply = True
equals changesPresentisFalse = False
equals changesPresentisFalse = False
equals changesPresentisFalse = False
equals changesPresentisTrue = False
equals changesPresentisTrue = False
equals changesPresentisTrue = False

It correctly equates the command parameter to "apply" but not the changesPresent parameter to "false". I'm sure it has something to do with the compile/runtime/macro syntax madness but I can't figure out how to make it work. Any help much appreciated.

Upvotes: 0

Views: 175

Answers (2)

Bright Ran-MSFT
Bright Ran-MSFT

Reputation: 13834

In the TFApply job, both of the expressions "${{ parameters.changesPresent }}" and "$(changesPresent)" can output the correct values passed from the TFPlan job.

But the following command lines always output the 'False' result that is same as your pipeline.

Write-Host "equals parameters.changesPresent = ${{ eq(parameters.changesPresent, false) }}"
Write-Host "equals parameters.changesPresent = ${{ eq(parameters.changesPresent, False) }}"
Write-Host "equals parameters.changesPresent = ${{ eq(parameters.changesPresent, 'true') }}"
Write-Host "equals parameters.changesPresent = ${{ eq(parameters.changesPresent, true) }}"
Write-Host "equals parameters.changesPresent = ${{ eq(parameters.changesPresent, True) }}"

Write-Host "equals variables.changesPresent = ${{ eq(variables.changesPresent, 'false') }}"
Write-Host "equals variables.changesPresent = ${{ eq(variables.changesPresent, false) }}"
Write-Host "equals variables.changesPresent = ${{ eq(variables.changesPresent, False) }}"
Write-Host "equals variables.changesPresent = ${{ eq(variables.changesPresent, 'true') }}"
Write-Host "equals variables.changesPresent = ${{ eq(variables.changesPresent, true) }}"
Write-Host "equals variables.changesPresent = ${{ eq(variables.changesPresent, True) }}"

However, the following command lines can identify the correct values using the PowerShell if...else statement.

if ("${{ parameters.changesPresent }}" -eq "true") {
  Write-Host "The value of parameters.changesPresent is true."
}
else {
  Write-Host "The value of parameters.changesPresent is false."
}

if ("$(changesPresent)" -eq "true") {
  Write-Host "The value of variables.changesPresent is true."
}
else {
  Write-Host "The value of variables.changesPresent is false."
}

Upvotes: 0

Vince Bowdren
Vince Bowdren

Reputation: 9208

You're trying to pass in a runtime variable as a parameter value when you call the template:

changesPresent: $(changesPresent)

This won't work. Parameter values have to be known at compile time, before the pipeline starts running at all.

I suggest you try a different approach:

  1. remove the changesPresent parameter
  2. instead of referring to parameters.changesPresent, just refer to the variable directly @(changesPresent). It's accessible even within the template.
  3. if any of your tasks need to be conditional on a runtime variable like changesPresent, implement this as a task condition instead of using conditional insertion.

Upvotes: 0

Related Questions