L. Männer
L. Männer

Reputation: 469

Azure Pipeline use template expression with queued variables

I defined a YAML build-pipeline in azure:

variables:
  test: '${{ variables.Environment }}'

pool:
  vmImage: 'ubuntu-latest'

steps:
- script: |
    echo $(test)
  displayName: 'Show test'

I queue that pipeline with the Environment variable defined as 'abc': Environment = abc

I expect it to echo abc but instead abc is replaced with nothing - variables.Environment seems to be undefined.

Later on I want to load a different Variable Group depending on the Environment variable, which is why I do not echo $(Environment) directly in the script. It's just a simplified example.

Upvotes: 2

Views: 2699

Answers (2)

Sam Kompfner
Sam Kompfner

Reputation: 21

A variation of this problem:

TL;DR:

Group variables do not seem to be available at template compile time, e.g. when conditionally setting a template to run, based on a variable from that group - only variables explicitly set in the pipeline seem to be available.

Long version:

I have a set of variable groups; 'Group-NonProd', 'Group-Prod', etc. Each contains variable 'identifier', with differing values ("dev", "prod", for the below example).

I have a master pipeline, 'main-pipeline.yml', and in that are several stages, each corresponding to the value of 'identifier', e.g.:

- stage: NonProd
  variables:
  - group: 'Group-NonProd' ## includes the variable 'identifier' with value "nonprod"
  jobs:
  - template: nonprod.yml
    parameters:
      identifier: $(identifier)
  - script: echo "environment is $(identifier)"

- stage: Prod
  variables:
  - group: 'Group-Prod' ## includes the variable 'identifier' with value "prod"
  jobs:
  - template: prod.yml
    parameters:
      identifier: $(identifier)
  - script: echo "environment is $(identifier)"

However, when I run the pipeline, the parameters 'identifier' do not expand to the value in the group variable 'identifier' - it is blank - I see that when I try using the variable in the below conditional logic (the aim being to use this logic to determine which template to call - see commented out lines - and pass that parameter down to them):

steps:
  - ${{ if eq(parameters.identifier, 'nonprod') }}:
    # - template: nonprod.yml
    - script: echo "Using nonprod template, environment is ${{ parameters.identifier }}"
  - ${{ if not(eq(parameters.identifier, 'prod')) }}:
    # - template: prod.yml
    - script: echo "Using prod template, environment is ${{ parameters.identifier }}"

The above script always resorts to the 2nd condition, because the result is always "Using prod template, environment is " (blank).

Here's the odd thing though - if I explicitly set the variable 'identifier' at each stage, it does work!

e.g. this works:

- stage: NonProd
  variables:
  - group: 'Group-NonProd'
  - name: identifier
    value: nonprod
  jobs:
  - template: nonprod.yml
    parameters:
      identifier: $(identifier)
  - script: echo "environment is ${{ parameters.identifier }}" 

Upvotes: 2

LoLance
LoLance

Reputation: 28106

I expect it to echo abc but instead abc is replaced with nothing - variables.Environment seems to be undefined.

According to this document:

Runtime happens after template expansion. Template variables are processed at compile time, and are replaced before runtime starts. Template variables silently coalesce to empty strings when a replacement value isn't found.

So in your case echo $(test) print out nothing but empty string. Cause the queue variables are used for runtime. For this, you can consider using macro or runtime expression which is for runtime. Both test: $(Environment) and test: $[variables.Environment] work well on my side.

Later on I want to load a different Variable Group depending on the Environment variable, which is why I do not echo $(Environment) directly in the script. It's just a simplified example.

As I know, linking different variable groups depending on the dynamic Environment variable is not supported yet, here's one discussion about that topic. And this is one good workaround in that scenario.

Nowadays Azure Devops Service is rolling out the new feature runtime parameters, I think it can meet most of your requirements. It could be a better choice for you, use runtime parameters instead of not supported dynamic Environment variable.

My simple test about this option:

1.Content in yaml:

parameters:
- name: group
  displayName: Group Name
  type: string
  default: TestGroup
  values:
  - TestGroup
  - Group2
  - Group3
  - Group4

variables:
- group: ${{ parameters.group }}

steps:
- script: |
    echo $(Name)
  displayName: 'Show group name'

2.My variable group TestGroup:

enter image description here

3.Click run pipeline:

enter image description here

4.The pipeline runs well and the displays the variable defined in variable group:

enter image description here

Hope it helps :)

Upvotes: 3

Related Questions