Azure-pipelines-agent: YAML - Support conditions for templates

Created on 7 Aug 2018  路  18Comments  路  Source: microsoft/azure-pipelines-agent

Have you tried trouble shooting?

Queuing a build generates an error. Unexpected value 'condition'.

Agent Version and Platform

Version of your agent? 2.102.0/2.100.1/...

OS of the machine running the agent? Windows

VSTS Type and Version

VSTS

If VisualStudio.com, what is your account name? https://fsmb.visualstudio.com

What's not working?

I am trying to set up a YAML build. We have a lot of builds and our existing definitions use task groups. I am moving the task group logic into a template so they can be shared across build definitions. The templates are stored in a separate repository. All this is working correctly.

There is one step that shouldn't execute when it is a PR build so I tried to do this.

- template: sharedstep.yml@templates
  parameters:
     value: true
  condition: and(succeeded(), eq(variables['Build.Reason'], 'PullRequest'))

The build won't queue because of the error - Unexpected value 'condition'.

It would be nice if templates could be conditional like tasks are. Right now the workaround would be to either use a parameter or specify the condition inside the template but the template may not always know the correct condition to use.

Agent and Worker's Diagnostic Logs

It is not queuing so there is no log.

Related Repositories

Please ensure you are logging issues to the correct repository in order to get the best support.

  • Tasks Repository - contains all of the inbox tasks we ship with VSTS/TFS. If you are having issues with tasks in Build/Release jobs (e.g. unreasonable task failure) please log an issue here.
  • Hosted Agent Image Repository - contains the VM image used in the VSTS Hosted Agent Pool. If you are having Build/Release failures that seems like they are related to software installed on the Hosted Agent (e.g. the DotnetSDK is missing or the AzureSDK is not on the latest version) please log an issue here.

If you are hitting a generic issue about VSTS/TFS, please report it to the Developer Community

enhancement

Most helpful comment

this is supported:

- ${{ if eq(variables['Build.Reason'], 'PullRequest') }}:
  - template: sharedstep.yml@templates
    parameters:
       value: true

All 18 comments

this is supported:

- ${{ if eq(variables['Build.Reason'], 'PullRequest') }}:
  - template: sharedstep.yml@templates
    parameters:
       value: true

Yes I agree a template would work but the enhancement request is that I be able to use a condition like I can for every other item I can put into a step. Conditions are far easier to write and read then template expressions and the overly complex syntax you have to use to avoid errors.

i seem to be experiencing some issues with this kind of conditions in yaml`s

child yaml:

  • ${{ if or(eq(variables['Build.SourceBranch'], 'refs/heads/master'), eq(parameters.updateArmTemplate, 'true')) }}:

    • powershell: |

      blabla-my-ps-code

parent yaml:

  • template: "Pipelines\.vsts-arm-pipeline-template.yml"
    parameters:
    updateArmTemplate: $(updateArmTemplate)

$(updateArmTemplate) is a variable settable at queue time, with default value 'true' and around the yaml i also have a default value when declaring this parameter in the child yaml

the behavior is that it doesn't get executed although on 'true'
is this a bug or is there something i`m not doing right ?

I came across this issue yesterday and tried the solution mentioned above and I can confirm that it does not work, the way it is described. Here's part of my yaml:

  • ${{ if eq(variables['ExecuteTests'], '1') }}:

    • template: ExecuteTests.yml

The same syntax (eq(variables['ExecuteTests'], '1')) works in the condition tag of a single task.

We have created a new repository for all YAML related issues, please move the current issue to there.
https://github.com/Microsoft/azure-pipelines-yaml

this is supported:

- ${{ if eq(variables['Build.Reason'], 'PullRequest') }}:
  - template: sharedstep.yml@templates
    parameters:
       value: true

@ericsciple
How would this work using an output variable from another task in the same job ?
Thanks.

@vtbassmatt to redirect

@MathieuBuisson you could do something like this:

# azure-pipelines.yml
steps:
- script: <generate output variable here>
  name: deciderstep
- template: sharedstep.yml@templates
  parameters:
    doTheThing: $[ variables['deciderstep.myVariable'] ]

# sharedstep.yml
steps:
- script: echo Sometimes this happens!
  condition: eq(parameters.doTheThing, 'true')
- script: echo Sometimes this also happens!
  condition: eq(parameters.doTheThing, 'true')

(N.B. I didn't test that, just wrote it from memory, and it may need some tweaking.) It's not as elegant as a conditional inclusion of the template, but does get the scenario working.

I tried that and got an error message stating that "parameters" was unknown here.
Then I tried something like

  condition: eq('${{parameters.doTheThing}}', 'true')

but this did not execute because the parameter was only evaluated as literally $[ variables['deciderstep.myVariable'], which was not true.

Or to be accurate in what I tested, in case it matters, I did not use an output variable but a simple one, and just used this syntax: $(myVariable).

I'm using the suggested approach for optional execution of a template:

image

And get:

/build-templates/steps/node-app-deploy-steps.yml@templates: (Line: 76, Col: 19, Idx: 3882) - (Line: 76, Col: 19, Idx: 3882): Mapping values are not allowed in this context.

If I remove the parameters, then the pipeline compiles, but obviously I need my parameters!

This is a template within a template calling another template - don't know if that's significant.

Update:

It was an indentation issue - 'parameters' should be at the same level as the 'template' keyword. I'll leave it here so that future generations can laugh at my mistake :-)

Nothing to laugh at -- YAML is a confusing beast :grin: Glad you got it solved.

Hello @vtbassmat , I am trying to use the example you provided however having some issue such as the one described by @afeblot. When you use the parameter syntax as below
condition: eq(${{parameters.doThething}},true)
this evaluates the parameters at compilation time at which point the variables haven't been set so it evaluates as
condition: eq('variables['deciderstep.myVariable']',true )
which naturally doesn't work, do you have any advice on how to get this working?
also the syntax you described
eq(parameters.doTheThing, 'true')
gives the result:

##[error]Unrecognized value: 'parameters'.

Hi @pbalexlear - we're not doing product support through GitHub issues anymore. Please open a ticket on Developer Community with your scenario.

I'll note a couple of things that may unblock you here:

  • Your condition section needs to evaluate to something that doesn't wrap the variables['deciderstep'] stuff in single-quotes. My example was correct in this regard.
  • The parameters suggestion is tricky and may only be applicable to the original person's scenario. The parameter gets consumed statically at compile time and refers to a $[ ] runtime expression. Then the runtime expression has to evaluate correctly at runtime.

Thanks for coming back to me @vtbassmatt , I understand what you are saying however, the default action when a parameter is passed into a template seems to be to wrap it as a string or at least this is how it is displayed in the pipeline output as if it is treating it as a string value of the expression.

I understand what you are saying that if the value of a parameter was an expression and wasn't wrapped as a string it would be substituted in and evaluated at runtime, however because the system is wrapping the parameter as a string it doesn't behave this way.

I did manage to find a solution by passing the name of the variable as the value of the parameter, which isn't a solution I like but does work functionally.

If you could advise on how to prevent the system wrapping the expression as a string that would be greatly appreciated.

As I have resolved my issue although through an unideal solution I won't raise a ticket, but would appreciate it if you could advise on the above.

Thanks.

Alex

Your comment made me dig in and try this, and I realized I had a couple of dumb mistakes. The below two files are complete and work the way you'd expect:

# azure-pipelines.yml
pool: { vmImage: ubuntu-latest }
steps:
- checkout: none
- bash: |
    echo Creating output variable...
    echo '##vso[task.setVariable variable=myVariable;isOutput=true]true' # also tested with 'false'
  name: deciderstep
- template: template.yml
  parameters:
    doTheThing: eq(variables['deciderstep.myVariable'], true)
# template.yml
parameters:
  doTheThing: 'false'
steps:
- script: echo This always happens!
  displayName: Always
- script: echo Sometimes this happens!
  condition: ${{ parameters.doTheThing }}
  displayName: Only if true

Thanks @vtbassmatt , that's perfect and exactly what I was looking for, thanks very much for taking the time to look into this.

Its still not solved how to work in that case with "succeeded()" as this is not supported for templates.
image

Was this page helpful?
0 / 5 - 0 ratings