Beefcake
Beefcake

Reputation: 801

Passing parameters through nested templates (or declaring IF conditions on variables)

I would like to be able to pass a pipeline parameter all the way through my YAML pipeline without having to define a parameter in each and every YAML file.

Essentially I have a main YAML file which calls a stage YAML, that has multiple nested jobs YAML, which in turn calls nested steps YAML; essentially building up my pipeline as I should using templates: https://learn.microsoft.com/en-us/azure/devops/pipelines/process/templates?view=azure-devops

Here's a tree list sample folder;

E:.
├───01_stage (many files per folder)
├───02_jobs (many files per folder)
├───03_steps (many files per folder)
└───...main pipeline files

Ideally I want to run an IF condition on checking out a repository depending upon the pipeline being PROD or NON-PROD. I am fine with defining this as a parameter, but I am also open to it being defined as a variable. As far as I'm aware; you can't use IF condition on variables.

This is fine

- ${{ if eq(parameters.pester, true) }}:     # or even as variables['pester']
  - name: pester
    value: yes

This is not fine

- ${{ if eq(variables.pester, true) }}:     # or even as variables['pester']
  - name: pester
    value: yes

The condition I want this to run is nest far below many templates, and it would be absolutely painful to have to re-code everything to confirm to the parameters value being declared and passed down in each file.

This is where I want it:

steps:

- ${{ if eq(parameters['masterTagged'], 'true') }}:   # here
  - checkout: masterTagged
    displayName: Repo Tagged

- ${{ if ne(parameters['masterTagged'], 'true') }}:   # here
  - checkout: self
    displayName: Repo Self

- template: /.pipelines/03_steps/ssh_install.yml

- template: /.pipelines/03_steps/tf_install.yml
  parameters:
    terraformVersion: ${{ parameters['terraformVersion'] }}

- ...many more templates

Here is my main YAML pipeline file:

parameters:
- name: artifactory_base
  type: boolean
  default: true

# ...many more params

- name: pester
  type: boolean
  default: true

- name: planDeploy
  type: boolean
  default: true

- name: useBackupAgent
  type: boolean
  default: false

- name: masterTagged  # key param
  type: boolean
  default: true


name: Team2

pr: none
resources:
  repositories:
  - repository: masterTagged
    endpoint: nationwide-ccoe
    name: my-github-org/my-github-repo
    type: github
    ref: refs/tags/v2.0.3
trigger: none
variables:
- template: /.pipelines/config/sub-asdfasdf.config.yml
- template: /.pipelines/config/namingstd.config.yml
- ${{ if eq(parameters.artifactory_base, true) }}:
  - name: artifactory_base
    value: yes
# ...many more conditions
- ${{ if eq(parameters.pester, true) }}:
  - name: pester
    value: yes
- ${{ if eq(parameters.planDeploy, true) }}:
  - name: planDeploy
    value: yes

stages:
- template: /.pipelines/01_stage/lz_deploy.yml
  parameters:
    ${{ if eq(parameters.useBackupAgent, false) }}:
      pool:
        vmImage: Ubuntu 18.04
    ${{ if eq(parameters.useBackupAgent, true) }}:
      pool:
        name: backupAgents
    terraformVersion: $(TERRAFORM_VERSION)

Is it possible to set this masterTagged parameter and for it to filter all the way down without having to declare it each time?

Also; is it even possible to use variables instead of parameters in this manner (I understand that parameters expand before variables):

- ${{ if eq(variables.pester, true) }}:     # or even as variables['pester']
  - name: pester
    value: yes

...if it is, have I been doing it wrong all this time?

Note:

I do understand that you can use a standard task condition on the checkout task (shown below); however, having a 'switch' on two tasks ruins the folder path of the checked out repository. Even though we're only checking out on repository, it adds another folder level to the $SYSTEM_DEFAULTWORKINGDIRECTORY. Doing it this way would require more re-coding on the current structure of my YAML piplines.

- checkout: masterTagged
  condition: eq(variables['masterTagged'], 'true')
  displayName: Repo Tagged

- checkout: self
  condition: ne(variables['masterTagged'], 'true')
  displayName: Repo Self

If I could, but I know it's not possible (as seen by other peoples requests), I would enable a parameter or variable on the repository reference:

resources:
  repositories:
  - repository: masterTagged
    endpoint: nationwide-ccoe
    name: my-github-org/my-github-repo
    type: github
    ref: ${{ parameters.repoRef }}    # here

Upvotes: 2

Views: 3828

Answers (1)

Dom
Dom

Reputation: 361

Is it possible to set this masterTagged parameter and for it to filter all the way down without having to declare it each time?

No, because parameters are “scoped” to the file they are defined with. This is due to them being expanded when the pipeline is first compiled. (See > Pipeline run sequence)

You can use IF conditions on variables, however you can’t use template expressions (wrapped with {{}}) on variables inside templates as the variables do not exist/have not been populated at the point of template expansion.

One option is just using the conditions on the checkout tasks as you suggested, and dealing with the extra folder level to the default working directory. I had to do something similar a while back, our solution was to copy the contents of the repo folder up a level into the default working directory.

Your other option is to do the checkout in the top level pipeline file. This will allow you to template the checkout step/s using the parameter without having to pass it all the way through the files. This is the option I would suggest as you do not have to deal with the folder structure issues of the first option.

This would look something like this:

parameters:
  - name: masterTagged
    default: true
    type: boolean

resources:
  repositories:
    - repository: masterTagged
      endpoint: nationwide-ccoe
      name: my-github-org/my-github-repo
      type: github
      ref: refs/tags/v2.0.3

steps:
  - ${{ if eq(parameters.masterTagged, true) }}:
    - checkout: masterTagged
  - ${{ if eq(parameters.masterTagged, false) }}:
    - checkout: self

  - template: ./path/to/template.yml

I hope this answers your question.

Upvotes: 4

Related Questions