Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

design: each expression #2

Merged
merged 1 commit into from
Oct 25, 2018
Merged

design: each expression #2

merged 1 commit into from
Oct 25, 2018

Conversation

ericsciple
Copy link
Contributor

No description provided.

@ericsciple
Copy link
Contributor Author

@mmitche @chcosta check this out. We've iterated on this quite a bit on our side. We think this will meet the scenario where you need to bootstrap each job in the graph with pre steps (setup microbuild) and post steps (publish telemetry).

@ericsciple
Copy link
Contributor Author

@chrisrpatterson

pool: ${{ job.pool }}
workspace: ${{ job.workspace }}
steps: ${{ job.steps }}
```
Copy link
Member

@mmitche mmitche Oct 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean this could be written as such (simpler, no need to explicit list out everything)

parameters:
  jobs: []

jobs:
- job: CredScan                      # Cred scan first
  pool: MyCredScanPool
  steps:
  - task: MyCredScanTask@1
${{ each job in parameters.jobs }}
- ${{ each pair in job }}:           # Insert all properties other than "steps"
    ${{ if ne(pair.key, 'dependsOn') }}:
      ${{ pair.key }}: ${{ pair.value }}
  ${{if job.dependsOn}}
     dependsOn:
      - ${{ CredScan }}
      - ${{ job.dependsOn }}
  ${{ if not(job.dependsOn) }}:
      dependsOn:
      - CredScan

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep

@vtbassmatt
Copy link
Member

Could we do this in $[ ] expressions, too?

variables:
  NODE_VERS: ['6.x', '8.x', '10.x']
  TS_VERS: ['2.8', '2.9', '3.0']
strategy:
  matrix:
    $[ each nodeVer in variables.NODE_VERS ]:
      $[ each tsVer in variables.TS_VERS ]:
        $[ concat(nodeVer, '_', tsVer) ]:
          NODE_VERSION: $[ nodeVer ]
          TS_VERSION: $[ tsVer ]
steps:
- script: echo Node $(NODE_VERSION) against TypeScript $(TS_VERSION)

It's not the prettiest way to create a matrix, for sure. I predict people will try to do it, though, and the same thing is even grosser if you're forced into a template for it :)

@chrispat
Copy link
Contributor

@vtbassmatt I would much rather have a specific function for doing a cross product a variable array and apply some exclusions. Seems cleaner.

@4c74356b41
Copy link

my comments got deleted, eh?

@chcosta
Copy link

chcosta commented Oct 16, 2018

@4c74356b41, looks like your comments were added as a part of mmitche's review, which was resolved but is still available.

@4c74356b41
Copy link

can you provide a link, i cant seem to find those. thanks. @chcosta

@chcosta
Copy link

chcosta commented Oct 16, 2018

#2 (comment)

@4c74356b41
Copy link

ok, why is it resolved than? I dont mean to say I'm the most important guy out here, but comments are there for a reason. I work with these yaml definitions and they are pretty horrible for anything remotely clever. why cant I use concats? or other common string\object manipulation functions?

@chcosta
Copy link

chcosta commented Oct 16, 2018

mmitche's review was resolved (likely via a GitHub push). If you have feedback, you should do your own review or start another comment thread so that the topics don't get lost in the mix.

@mikeharder
Copy link

@vtbassmatt , @chrisrpatterson: Is there a way to create a cross product matrix today? If not, should a separate issue be filed for this?

@vtbassmatt
Copy link
Member

@mikeharder there isn't a command for cross-product matrix. Feel free to file it; it's on our minds but not highly prioritized right now.

@chcosta
Copy link

chcosta commented Oct 19, 2018

What is meant by "cross-product matrix"? @vtbassmatt , is that the same request as https://dnceng.visualstudio.com/7ea9116e-9fac-403d-b258-b31fcf1bb293/_workitems/edit/59 or a different scenario?

@mikeharder
Copy link

mikeharder commented Oct 19, 2018

@chcosta: It looks like https://dnceng.visualstudio.com/7ea9116e-9fac-403d-b258-b31fcf1bb293/_workitems/edit/59 is the same as #4. The ability to use a variable (in this case from a matrix) to set vmImage.

By "cross-product matrix", I mean the scenario where you want to use the matrix strategy on a cross-product of multiple dimensions. For example, say you want to run tests on 2 OS (Linux, Windows) and 2 versions of Python (3.6, 3.7). Currently, you'd need to manually create a matrix with all the combinations:

strategy:
  matrix:
    Linux_Python36:
      VM_IMAGE: 'ubuntu-16.04'
      PYTHON_VERSION: '3.6'
    Linux_Python37:
      VM_IMAGE: 'ubuntu-16.04'
      PYTHON_VERSION: '3.7'
    Windows_Python36:
      VM_IMAGE: 'vs2017-win2016'
      PYTHON_VERSION: '3.6'
    Windows_Python37:
      VM_IMAGE: 'vs2017-win2016'
      PYTHON_VERSION: '3.7'

While this isn't too bad with a small number of dimensions and a small number of variables in each dimension, it can quickly become unmaintainable as the dimensions and variables grow. It would be nice if there was a way to express this more succinctly, something like:

strategy:
  cross-product:
    PYTHON_VERSION: [ '3.6', '3.7' ]
    VM_IMAGE: [ `ubuntu-16.04`, `vs2017-win2016` ]

Tracking issue: #20

@vtbassmatt
Copy link
Member

We've shied away from cross-product for two reasons:

  1. Now you have to introduce an exception syntax. I don't think I've ever seen a higher-dimension matrix that didn't have at least one exception.
  2. Especially when n=3 or higher, it becomes painfully easy to run dozens/hundreds of jobs unintentionally. I know this sounds crazy since so many other CI systems do it, but we've seen it happen many times with our designer-based builds (which had the cross-product concept).

Notwithstanding the above, I'm open to the concept. Let's start a separate issue about it and have the conversation there. This PR's about each.

@mikeharder
Copy link

@vtbassmatt: Separate issue for cross-product: #20

@ericsciple ericsciple merged commit 8865554 into master Oct 25, 2018
@ericsciple ericsciple deleted the users/ersciple/m142each branch October 25, 2018 16:29
@andrewsuiter
Copy link

@ericsciple, if my solution has multiple projects, I would like to loop through each project and publish build artifacts

task: PublishBuildArtifacts@1
${{ each job in parameters.project }}
displayName: 'Publish Artifact: drop'
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)/${{parameters.project}}.zip'
How would I loop through each project and set the .zip file for each project?
I would like to zip up project 1 and project 2.

Thanks,

@ericsciple
Copy link
Contributor Author

Can you add two tasks?

steps:
- ${{ each job in parameters.project }}:
  - task: PublishBuildArtifacts@1
    displayName: 'Publish ${{ parameters.project }}
    inputs:
      PathtoPublish: '$(Build.ArtifactStagingDirectory)/${{parameters.project}}.zip'

@ericsciple
Copy link
Contributor Author

...@andrewsuiter

@andrewsuiter
Copy link

andrewsuiter commented Jan 8, 2019

@ericsciple I could always do that but there may be a situation where there are multiple projects in one solution, some may have 5, some may have 3 projects. It would make it easier if I could loop through each project that is defined as an array in the parameter.

parameters;
project: 'name: test1 project: project1, name: test2 project: project2, name: test3 project: project3'

Thanks

UPDATE: How do I pass the project parameters?

parameters;
project: [ 'TEST1', 'TEST2']?

@andrewsuiter
Copy link

@ericsciple any update as to how to pass the project parameter? I am using the each each expression but getting an array can not be converted to a string error.

@ericsciple
Copy link
Contributor Author

@andrewsuiter sorry, my example was wrong.

Here is a better example:

# my-template.yml
parameters:
steps:
- ${{ each project in parameters.project }}:
  - task: PublishBuildArtifacts@1
    displayName: 'Publish ${{ project }}
    inputs:
      PathtoPublish: '$(Build.ArtifactStagingDirectory)/${{ project }}.zip'
# ci.yml
steps:
- template: my-template.yml
  parameters:
  - test1
  - test2

That way, one task is added for each item in the array parameters.project. Does that work? If not, can you paste the cotents of both files (the template, and the caller of the template)

@andrewsuiter
Copy link

ok great, I will give it a shot, thanks for the help!

@andrewsuiter
Copy link

@ericsciple That works perfect, exactly what I was looking for, much appreciated!

@idubnori
Copy link

@ericsciple Is there any way to use nested within parameters?
The example below to be error...

# my-template.yml
parameters:
steps:
- ${{ each pf in parameters.pf }}:
  - task: PublishBuildArtifacts@1
    displayName: 'Publish ${{ pf.rid }} ${{ pf.output }}'
    inputs:
      PathtoPublish: '$(Build.ArtifactStagingDirectory)/${{ pf.output }}.zip'
# ci.yml
steps:
- template: my-template.yml
  parameters:
  - windows:
      rid: 'win-x64'
      output: 'Foo.exe'
  - macos:
      rid: 'osx-x64'
      output: 'foo'

@ravican09
Copy link

ravican09 commented Dec 22, 2020

Hi Team
Sub: Variables in YAML pipeline are not allowing to define array
Error : A sequence was not expected,
Please advise how to define variables in YAML pipelines to define array.

Code:

variables:

  • name: MyVariableName
    value: ['Value1','Value2']

I want to use/pass MyVariableName to template.yml where i want to iterate array

parameters:
MyVariableName: [] #defining array here to expect multiple values.

steps:

  • ${{ each hostname in parameters.MyVariableName}}:

    logic

@harre096
Copy link

harre096 commented May 24, 2022

@andrewsuiter sorry, my example was wrong.

Here is a better example:

# my-template.yml
parameters:
steps:
- ${{ each project in parameters.project }}:
  - task: PublishBuildArtifacts@1
    displayName: 'Publish ${{ project }}
    inputs:
      PathtoPublish: '$(Build.ArtifactStagingDirectory)/${{ project }}.zip'
# ci.yml
steps:
- template: my-template.yml
  parameters:
  - test1
  - test2

That way, one task is added for each item in the array parameters.project. Does that work? If not, can you paste the cotents of both files (the template, and the caller of the template)

@ericsciple - FYI the quote is missing in the displayName of your example:
displayName: 'Publish ${{ project }}'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.