1

I have a simple yaml pipeline that calls a template analyze-and-deploy.yml.

I concatenate ${{ parameters.Environment }}_USERNAME to create a username parameter dynamically and pass it when calling template analyze-and-deploy.yml. I want to then retrieve the value of dynamically created USERNAME from a "library" in my Azure DevOps project and run a script as a step in analyze-and-deploy.yml.

I can pass the value as parameter e.g. if environment is "Dev", then I can see DEV_USERNAME is passed to analyze-and-deploy.yml, but how do I expand this dynamic variable with actual value from library named "VG1"?

In VG1, I have variables DEV_USERNAME, QA_USERNAME and I want it to get value depending on the environment.

resources:
  repositories:
    - repository: templates
      type: git
      name: sharedpipelines
      ref: refs/heads/main

parameters:
  - name: sourceDirectory
    type: string
    default: 'core'
  - name: Environment
    type: string
    values:
      - DEV
      - QA
    default: DEV 

variables:
- group: "VG1"

stages:

  -  ${{ if ne(parameters.workstream, '') }}:
      - template: templates/analyze-and-deploy.yml@templates
            my_username: "${{ parameters.FromEnvironment }}_USERNAME"

1 Answer 1

1

Strongly recommend reviewing the pipeline run sequence to understand what's happening, but here's a few key points to remember:

  • Variables $(<variable-name>) are evaluated at runtime.
  • Expressions ${{<exp>}} are evaluated at compile-time

When you use a template, the system expands everything into a single YAML document before the pipeline runs. This is the compile-time step. Templates aren't like functions that are called at runtime. To illustrate this, there's a new feature in Azure Pipelines that allows you to view the fully expanded YAML template. Just navigate to the Pipeline run and select "See full YAML" from the context menu.

See full YAML

It's perfectly valid to pass variables as template parameters as long as you aren't expecting these values to be present in compile-time conditions. Note that only a handful of predefined variables are available at compile-time, so if you attempt to specify a variable for something that is used during the compile-time step it will be empty.

For example, the stage name is something that must be known before the pipeline runs, so using a variable here is invalid:

stages:
  # MyVariable won't have a value at compile-time, so you'll get an error
- stage: $(MyVariable)

In your case, you want to pass either $(DEV_USERNAME) or (QA_USERNAME) from your variable group into your template. You can construct the variable name using a compile-time expression:

$(${{ parameters.Environment}}_USERNAME}}).

The following illustrates this:

# pipeline.yml
trigger: none

parameters:
- name: Environment
  type: string
  default: 'DEV'
  values:
  - DEV
  - QA

variables:
# VG1 contains $(DEV_USERNAME) and $(QA_USERNAME)
- group: VG1

stages:
- template: template.yml
  parameters:
    username: $(${{ parameters.Environment}}_USERNAME)
# template.yml

parameters:
- name: username
  type: string

stages:
- stage: example
  jobs:
  - job: example
    steps:
    - pwsh: |
        # this will write out the value of either $(DEV_USERNAME) or $(QA_USERNAME)
        write-host $env:Username

      displayName: Show username
      env:
        # - parameters.username will be either $(DEV_USERNAME) or $(QA_USERNAME)
        # - By passing it through the env it is available in powershell
        #   as an environment variable at runtime
        Username: ${{ parameters.username }}
Sign up to request clarification or add additional context in comments.

1 Comment

@ryanbcook, great answer. worked like charm. Many Thanks

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.