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"
Strongly recommend reviewing the pipeline run sequence to understand what's happening, but here's a few key points to remember:
$(<variable-name>) are evaluated at runtime.${{<exp>}} are evaluated at compile-timeWhen 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.
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 }}