Search code examples
azure-devopsazure-pipelines

AzureDevops set variables based on parameter and pass to template at next stage


In Azure DevOps, I'm trying to create a pipeline which offers a simple selection of pre-set options to the user running it. These options will be converted into different combinations of parameters as specified by a templated stage (the definition of which, I have no control over). The idea of my pipeline is that frequently-used build configurations are easy to select correctly, rather than having to manually set 3 or 4 different parameters.

I need the "Build.Setup" from immutable_pipeline to print config_one, profile_one when the first radio is selected (buildType=type1), config_two, profile_two when buildType=type2, and so on.

Unfortunately I'm really struggling to get any variable value into the templated stage other than the defaults. Are ADO variables even mutable variables at all - or just constants? I've read the MS docs extensively and understand the meaings of the different macro declaration types. I've tried many different combinations of syntaxes ${{...}}, $(...) and $[...], all behave differently but none seems able to deliver what's needed. Is this even possible? Is there a simple solution someone can suggest?

Pipeline:

name: $(Date:yyyyMMdd).$(Rev:r)

parameters:
  - name: buildType
    displayName: 'Type of build'
    type: string
    default: 'type3'
    values: ['type1', 'type2', 'type3']

pool:
  name: default

variables:
  - name: config
    value: 'defaultConfig'
  - name: profile
    value: 'defaultProfile'

stages:
  - stage: Stage1
    displayName: Prepare build config

    jobs:
      - job: Job1_1
        steps:
          - checkout: none
          - task: Bash@3
            name: SetVariables
            inputs:
              targetType: inline
              script: |
                p1='${{ parameters.buildType }}'
                v1='$(config)'
                v2='$(profile)'
                echo -e "BEFORE: p1='${p1}'\n    v1='${v1}'\n    v2='${v2}'"
                case ${p1} in
                  type1)
                    v1='config_one'
                    v2='profile_one'
                    ;;
                  type2)
                    v1='config_two'
                    v2='profile_two'
                    ;;
                  type3)
                    v1='config_three'
                    v2='profile_three'
                    ;;
                esac
                echo -e "AFTER: p1='${p1}'\n    v1='${v1}'\n    v2='${v2}'"
                echo "##vso[task.setvariable variable=config]${v1}"
                echo "##vso[task.setvariable variable=profile;isOutput=True]${v2}"

      - job: Job1_2
        dependsOn: Job1_1
        variables:
          - name: variable1
            value: $(config)
          - name: variable2
            value: $[ dependencies.Job1_1.outputs['SetVariables.profile']]
        steps:
          - task: Bash@3
            name: GetVariables2
            inputs:
              targetType: inline
              script: |
                echo -e 'SAME STAGE: v1="$(variable1)"\n    v2="$(variable2)"'

    # Next stage - use computed values for "config" and "profile"
  - template: templates/immutable_pipeline.yml
    parameters:
      config: $(config)
      profile: ${{ variables.profile }}

templates/immutable_pipeline.yml:

Note that I don't have access to change this, I can't make it dependsOn: Stage1.Job1_1.


parameters:
  - name: config
    displayName: 'Config'
    type: string
    default: 'unset'
  - name: profile
    displayName: 'Profile'
    type: string
    default: 'unset'

stages:
  - stage: Build
    displayName: Templated build
    jobs:
      - job: Setup
        pool:
          name: default
          demands:
            - Agent.OS -equals Linux
        steps:
          - checkout: none
          - script: |
              echo '##[info] parameters.config=${{ parameters.config }}'
              echo '##[info] parameters.profile=${{ parameters.profile }}'

Solution

  • I just found one solution (which is arguably simpler than using variables) using the ${{ if eq(...) }}: conditional insertion syntax:

    name: $(Date:yyyyMMdd).$(Rev:r)
    
    parameters:
      - name: buildType
        displayName: 'Type of build'
        type: string
        default: 'type3'
        values: ['type1', 'type2', 'type3']
    
    pool:
      name: default
    
    stages:
      - template: templates/immutable_pipeline.yml
        ${{ if eq(parameters.buildType, 'type1') }}:
          parameters:
            config: config_one
            profile: profile_one
        ${{ elseif eq(parameters.buildType, 'type2') }}:
          parameters:
            config: config_two
            profile: profile_two
        ${{ elseif eq(parameters.buildType, 'type3') }}:
          parameters:
            config: config_three
            profile: profile_three
        ${{ else }}:
          parameters:
            config: config_default
            profile: profile_default
    

    Still interested in whether the original approach of setting variables is even possible, if only beause I've spent so much time on it.