1

I have a scenario where I need to have both:

  1. runtime parameters, so that the pipeline can be triggered manually from the UI, where users triggering it can choose from a predefined set of options (defined in YAML)

  2. variables, so that the pipeline can be invoked via REST APIs

Regarding runtime parameters, I was able to create the following sample pipeline:

parameters:
- name: image
  displayName: Pool Image
  type: string
  default: ubuntu-latest
  values:
  - windows-latest
  - ubuntu-latest

trigger: none

stages:
- stage: A
  jobs:
  - job: A
    steps:
    - pwsh: |
        echo "This should be triggering against image: $MY_IMAGE_NAME"
      env:
        MY_IMAGE_NAME: ${{ parameters.image }}

When I run it, I can see the dropdown list where I can choose the image name and it is reflected in the output message of the PowerShell script.

Regarding variables, I have defined one called "image" here (notice the value is empty):

pipeline variable

The idea now is to invoke the pipeline from REST APIs and have the image name replaced by the value coming from the variable:

{
    "definition": {
        "id": 1
    },
    "sourceBranch": "master",
    "parameters":  "{\"image\": \"windows-latest\" }"
}

In order to make the step print the value I'm passing here, I need to correct the environment variable in some way. I thought it would be sufficient to write something like:

env:
  MY_IMAGE_NAME: ${{ coalesce(variables.image, parameters.image) }}

That's because I want to give the priority to the variables, then to parameters, so that in case none is specified, I always have a default value the pipeline can use.

However, this approach doesn't work, probably because we're dealing with different expansion times for variables, but I don't really know what I should be writing instead (if there is a viable option, of course).

What I also tried is:

env:
  MY_IMAGE_NAME: ${{ coalesce($(image), parameters.image) }}
  MY_IMAGE_NAME: ${{ coalesce('$(image)', parameters.image) }}
  MY_IMAGE_NAME: $[ coalesce(variables.image, parameters.image) ]
  MY_IMAGE_NAME: $[ coalesce($(image), parameters.image) ]

None of those are working, so I suspect this may not be feasible at all.

There is a workaround that I'm currently thinking of, which is to create two different pipelines so that those can be invoked independently, but while this is quite easy for me to accomplish, given I'm using a lot of templates, I don't find it the right way to proceed, so I'm open to any suggestion.

xTuMiOx
  • 433
  • 5
  • 18

1 Answers1

1

I tested and found you might need to define a variable and assign the parameter's value to it (eg. Mimage: ${{parameters.image}}). And define another variable(eg. Vimage) and assign $[coalesce(variables.image, variables.Vimage)] to it. Then refer to $(Vimage) in the env field of powershell task. Please check out below yaml.

parameters:
- name: image
  displayName: Pool Image
  type: string
  default: ubuntu-latest
  values:
  - windows-latest
  - ubuntu-latest

trigger: none

stages:

- stage: A
  jobs:
  - job: A
    variables:
      Mimage: ${{parameters.image}}
      Vimage: $[coalesce(variables.image, variables.Mimage)]

    steps:
    - pwsh: |
        echo "This should be triggering against image: $env:MY_IMAGE_NAME"
      env:
        MY_IMAGE_NAME: $(Vimage)

Env field of powershell task is usually for mapping secret variables. You can directly refer to $(Vimage) in the powershell script: echo "This should be triggering against image: $(Vimage).

Note: To queue a build via REST API with provided parameters, you need to check Let users override this value when running this pipeline to make the varilabe to be settable at queue time.

enter image description here

Update:

You can try passing the variables to the parameters of the template to make the parameters for template dynamic. Please check below simple yaml.

 jobs:
  - template: template.yaml
    parameters:
      MTimage: ${{parameters.image}}
      VTimage: $(Vimage)

template.yaml:

parameters:
  MTimage: 
  VTimage:  

jobs:
- job: buildjob
  steps:
  - powershell: |
      echo "${{parameters.VTimage}}"
      echo "${{parameters.MTimage}}"
Levi Lu-MSFT
  • 27,483
  • 2
  • 31
  • 43
  • Thanks for providing the info! The solution you proposed works, but I'm unsure how to make this fit with templates as well. Do templates support dynamic parameters like in this scenario? Is there a workaround for that as well? – xTuMiOx May 09 '20 at 17:28
  • I am not sure if i understand you correctly. You can try passing the variables to the parameters of the template. Please check above update. If it is not your case, Could you please describe in detail the scenario for template usage. – Levi Lu-MSFT May 11 '20 at 02:00
  • **See also:** https://stackoverflow.com/questions/61557016/how-can-i-invoke-a-yaml-pipeline-that-has-both-variables-and-runtime-parameters – dreftymac Apr 01 '21 at 03:53