2

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 }}'
Ed Randall
  • 6,887
  • 2
  • 50
  • 45
  • Reconsider whether or not you want to have a single, very complex pipeline containing a lot of conditional logic versus smaller, single-purpose pipelines that are easy to extend and maintain. – Daniel Mann Apr 19 '21 at 14:20
  • @DanielMann yes I did consider this, and concluded that (a) the very complex pipeline isn't, just a single case statement to set these variables and (b) Proliferation of pipelines is also bad - it's easier for the users to find and select the correct pipeline if there's only one for them to choose from, and (c) simpler for me to maintain in just one place rather than 3 or 4. – Ed Randall Apr 19 '21 at 14:24
  • Similar question: https://stackoverflow.com/questions/54246102/azure-pipelines-passing-a-variable-as-a-parameter-to-a-template – Ed Randall Apr 24 '21 at 12:27

1 Answers1

1

I just found one solution (which is arguably simpler than using variables) using the ${{ if eq(...) }}: 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
    ${{ if eq(parameters.buildType, 'type2') }}:
      parameters:
        config: config_two
        profile: profile_two
    ${{ if eq(parameters.buildType, 'type3') }}:
      parameters:
        config: config_three
        profile: profile_three

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

Ed Randall
  • 6,887
  • 2
  • 50
  • 45