'Variable expansion not working as expected in Azure DevOps Yaml Pipeline when stages are associated with different variable groups

I receive the error message 'Job Job1: Environment $(environmentName) could not be found. The environment does not exist or has not been authorized for use.' when I run the pipeline below.


trigger:
- main

pool:
  vmImage: ubuntu-latest

stages:
  - stage: Dev
    variables:
      - group: Config.Dev
    jobs:
      - deployment:
        environment: $(environmentName)
        strategy: 
          runOnce:
            deploy:
              steps:
              - checkout: self 
              - task: AzureCLI@2
                inputs:
                  azureSubscription: $(azureSubscriptionName)
                  scriptType: 'bash'
                  scriptLocation: 'inlineScript'
                  inlineScript: |
                    az deployment sub create --location uksouth --template-file main.bicep

  - stage: Prd
    variables:
      - group: Config.Prd
    jobs:
      - deployment:
        environment: $(environmentName)
        strategy: 
          runOnce:
            deploy:
              steps:
              - checkout: self 
              - task: AzureCLI@2
                inputs:
                  azureSubscription: $(azureSubscriptionName)
                  scriptType: 'bash'
                  scriptLocation: 'inlineScript'
                  inlineScript: |
                    az deployment sub create --location uksouth --template-file main.bicep
                



Solution 1:[1]

I solved my problem as follows.

It relies upon Environments, Service Connections and Variable Groups being named the same.

azure-pipelines.yml

trigger:
- main

pool:
  vmImage: ubuntu-latest

stages:
  - template: deploy.yml
    parameters: 
      environment: Dev
  - template: deploy.yml
    parameters: 
      environment: UAT
  - template: deploy.yml
    parameters: 
      environment: Prd

deploy.yml

parameters:
  - name: environment
    type: string

stages:
  - stage: ${{parameters.environment}}
    variables:
      - group: Simply.Infrastructure.${{parameters.environment}}    
    jobs:
      - deployment:
        environment: ${{parameters.environment}}
        strategy: 
          runOnce:
            deploy:
              steps:
              - checkout: self 
              - task: AzureCLI@2
                inputs:
                  azureSubscription: ${{parameters.environment}}
                  scriptType: 'bash'
                  scriptLocation: 'inlineScript'
                  inlineScript: |
                    az deployment sub create --location uksouth --template-file main.bicep --parameters "{ \"environmentName\": { \"value\": \"$(environmentName)\" }, \"versionNumber\": { \"value\": \"$(versionNumber)\" } }"

main.bicep

targetScope = 'subscription'

param environmentName string
param versionNumber string

resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = {
  name: 'Simply.Infrastructure.${versionNumber}'
  location: 'uksouth'
} 

module vnet './vnet.bicep' = {
  name: 'vnet'
  scope: resourceGroup   
  params: {
    name: 'smplyinf${toLower(environmentName)}${versionNumber}'
  }
}

Solution 2:[2]

You can't do that. It has to be yaml variable. This is limitation which you cannot overcome. So you need to define your variable in YAML, or hardcode directly envrionment name.

Solution 3:[3]

Is there a reason you are not hard coding the environment name? If the intent is to to keep your code DRY, I would recommend putting your deploy stage into a template file. Then call the template for each deployment passing in the environment name as a parameter.

azure-pipelines.yml

trigger:
- main

pool:
  vmImage: ubuntu-latest

stages:
  - template: deploy.yml
    parameters: 
      environment: Dev
  - template: deploy.yml
    parameters: 
      environment: Prd

deploy.yml

parameters:
  - name: environment
    type: string

stages:
 - stage: ${{parameters.environment}}
    variables:
      - group: Config.${{parameters.environment}}
    jobs:
      - deployment:
        environment: ${{parameters.environment}}
        strategy: 
          runOnce:
            deploy:
              steps:
              - checkout: self 
              - task: AzureCLI@2
                inputs:
                  azureSubscription: AzureSub.${{parameters.environment}}
                  scriptType: 'bash'
                  scriptLocation: 'inlineScript'
                  inlineScript: |
                    az deployment sub create --location uksouth --template-file main.bicep

You would have to update your subscription names to have a standard naming convention like your variable groups. This would keep code dry and make it easy to add environments. It also uses template expression, so the environment name expands before run time.

Solution 4:[4]

First, the error occurs because you don't have the permission to create environments. In your issue, it searches an environment named "$(environmentName)" but can't find and can't create the environment.

enter image description here

Please check the Security here. The creator can create environments.

enter image description here


Second, as the other answers explain, you can't use $(environmentName) to get the value in variables. It will run on the environment named "$(environmentName)" like this screenshot.

enter image description here

Solution 5:[5]

Please remove restriction from variable group in the library of variables. It will fix the issue and all user/schedule can resolve the variable for its run.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Selig Drahcir
Solution 2 Krzysztof Madej
Solution 3 Brittan DeYoung
Solution 4 unknown
Solution 5 developerprashant