lower() function does not seem to work in Azure DevOps YAML pipeline

Viewed 4156

I'm trying to use the lower() function in a YAML template, but do not understand the behavior. I've a variable group named Infra.Environment.ShortName with the value "Dev". In my YAML template, I've defined a variable from a variable group:

  variables:
  - name: environmentShortName
    value: $(Infra.Environment.ShortName)

In a task, I refer to this variable:

- task: AzureResourceGroupDeployment@2
  displayName: 'Deploy Storage Account'
  inputs:
    azureSubscription: ${{ parameters.subscription }}
    resourceGroupName: mst-${{ lower(variables.environmentShortName) }}-infra
    location: '$(Infra.Environment.Region.Primary)'
    csmFile: '$(Pipeline.Workspace)/$(Build.DefinitionName)/Resources/infra-storageAccount.json'
    csmParametersFile: '$(Pipeline.Workspace)/$(Build.DefinitionName)/Resources/infra-storageAccount.parameters.json'
    deploymentOutputs: ArmOutputs

I've experimented with different expressions, but do not understand why I cannot convert the variable group value to lowercase:

resourceGroupName: mst-${{ lower(variables.environmentShortName) }}-infra

=> mst-Dev-infra (lower does not seem to work)

resourceGroupName: ${{ format('mst-{0}-infra', lower(variables.environmentShortName)) }}

=> mst-Dev-infra (format works, but lower does not)

resourceGroupName: $[format('mst-{0}-infra', lower(variables.environmentShortName))]

=> $[format('mst-{0}-infra', lower(variables.environmentShortName))] (expression not evaluated)

resourceGroupName: mst-${{ lower(variables['Infra.Environment.ShortName']) }}-infra

=> mst--infra (empty value)

resourceGroupName: mst-${{ lower('Dev') }}-infra

=> mst-dev-infra (lower works with a constant value)

2 Answers

The solution was to use runtime variables as the variable group is not resolved at compile time. Runtime expressions have some limitations, but the following works:

  - name: environmentShortName
    value: $[lower(variables['Infra.Environment.ShortName'])]

    resourceGroupName: mst-$(environmentShortName)-infra

Following snippet will work correctly and write "mst-test-infra" as the output:

variables:
  environmentShortName: TEST

steps:
- powershell: Write-Host "${{ format('mst-{0}-infra', lower(variables.environmentShortName)) }}"

This is because the variable set to literal value and the value is known on a compile time.

If the value of the environmentShortName is dependant on another variable, like:

environmentShortName: $(System.TeamProject)

The lower() will not work correctly and behaves just like you described. There is (my) logical explanation: the expression ${{ variables.environmentShortName}} is resolves at compile time and perhaps your variable value is not ready yet to be resolved.

To deal with a such behaviour, consider to change a location where lower() is applied and move it to a variable declaration part:

variables:
  environmentShortName: ${{ lower(variables['System.TeamProject'] ) }}

steps:
- powershell: Write-Host "mst-$(environmentShortName)-infra"
Related