Revisiting ADO YAML Objects and Looping
Introduction
My own experience has evolved since initially posting Advanced Azure DevOps YAML Objects two years ago! Thus thought a post revisiting ADO YAML Objects and Looping was warranted. This initial post is still widely popular and still one of the top results when looking for Azure DevOps and YAML Objects. There is nothing wrong with the initial posting, just a recognition that my skills as a blogger has grown and the information from Microsoft on YAML Pipelines as grown.
The Use Case
Suppose you are working in YAML Pipelines and would like to create an object. Inside that object say you have a need to a list of values. Typically I run into this when defining either an environment with multiple regions or a deployment with multiple projects.
Microsoft’s documentation was a little weak on what to do past defining an object and potentially looping through said object…until recently and more on that later.
Variable/Parameter Structure
The variable or parameters being used to loop through should follow a fairly straight forward syntax. In my TheYAMLPipelineOne, I have examples being read in as parameters with a default value.
parameters:
- name: environmentObjects
type: object
default:
- environmentName: 'dev'
regionAbrvs: ['cus']
- environmentName: 'tst'
regionAbrvs: ['cus','eus']
Looping
Azure DevOps YAML Pipelines does offer some looping functionality through the each
keyword. I have a submitted a Pull Request to have the documentation updated to include the following:
parameters:
- name: listOfFruits
type: object
default:
- fruitName: 'apple'
colors: ['red','green']
- fruitName: 'lemon'
colors: ['yellow']
steps:
- ${{ each fruit in parameters.listOfFruits }} :
- ${{ each fruitColor in fruit.colors}} :
- script: echo ${{ fruit.fruitName}} ${{ fruitColor }}
The basis of this is understanding the each
loop will go through and pull the listOfFruits
instance and store it in the fruit object. The second each
statement will go through the array of values for the colors
on each instance of listOfFruits
. We will echo the fruitName
from the first each
with each fruitColor
being iterated through the second each
.
In ADO this will look like:
2022-12-28T16:15:33.2955122Z Script contents:
2022-12-28T16:15:33.2957273Z echo apple red
.....
2022-12-28T16:15:33.9862565Z Script contents:
2022-12-28T16:15:33.9863692Z echo apple green
.....
2022-12-28T16:15:34.6171924Z Generating script.
2022-12-28T16:15:34.6183737Z Script contents:
2022-12-28T16:15:34.6185339Z echo lemon yellow
Updating Documentation/Additional Content
Part of this revisit is inspired of continuously viewing documentation that did not illustrate this. In addition to the pull request mentioned on Azure Pipelines each keyword I have also had PRs merged into Parameter Data Types to help show this example to a wider audiance.
If wanting to also learn more on how to use this one can watch my YouTube video on YAML Deployment Pipelines, TheYamlPipelineOne repository, or check out my series on Azure DevOps Pipelines on Microsoft’s Tech Community Platform
Conclusion
There it is. A simple look at revisiting ADO YAML Objects and Looping. This concept took me a while to discover and afterward made more advanced items like templating and multi-stage pipelines easier. Hopefully it does the same for you.
Hi John, thanks for this nice article.
You say “one can easily do this with variables as well”. Were you able to loop over a variable ? I have a use case where I need to create a list dynamically and would like to iterate over it later in the pipeline to invoke a given task multiple times.
As I understand it, variables are only strings and cannot be typed of something else. And the documentation also says the “each” keyword is only for parameters.
And given that my use case is rather dynamic, I think it’s not feasible. But it woud be nice to have your opinion on this.
Thanks.
Hey Matthew,
You are correct. I will update the article accordingly as this is something I overlooked. Variables can only be strings; however, I typically leverage templates to pass in parameter objects to the templates. Alternatively if need be I would have a variable template file with the appropriate values and then have that template scoped to the appropriate stage/job. If these are dynamic then this may not work for you.
If you wouldn’t mind sharing more would be happy to provide input. Some suggestions off the bat would be to consider how the variables would be scoped or alternatively dynamically create ADO variables in your pipelineto be used later on.
Hey, there. I am wondering what to do if inside this loop (or nested loop) I want to access another parameter. Let’s say for the sake of the example there is another parameter string “store” with the idea to print for each fruit color also the store name. But the store name is not specific to any fruit or color, so it’s a separate parameter. I have found that I can’t access other parameters in my each loop.
Apologies for delay in getting back to you. To achieve this just need to reference the parameter as ${{parameters.storeName}} this will read the parameter outside the loop. If you are already doing this and it is not working please provide your YAML and I’ll be happy to take a look.
Hello. Thanks for the article. I am using the same way the parameters are being used above, just in place of colors i have multiple sites where i need the package to be deployed to. But the each loop condition doesnt work and it doesnt run the job.
Thanks for posting. I would need to know more detail on what you are trying to achieve. Are you able to provide any additional context? I have a feeling the issue is related to how the package deploy step is written. To Confirm you could write out the parameter object item to the terminal and see what the value is each time it is being ran through.