Suppose, I have ADO CI pipeline with UI tests, and suppose thepipeline iterates through a list of devices and tests which can change between pipeline runs like so:

 - ${{ each device in parameters.devices }}:
      - job: RunUITests_${{ device.uniqueName }}
        timeoutInMinutes: 240
        variables:
        - name: iosDevice
          value: ${{ device.deviceType }}
        dependsOn: BuildUITests
        displayName: 'Run UI Tests - ${{ device.deviceType }} -'
        strategy:
          matrix:
            ${{ each testSuite in parameters.testSuites }}:
              ${{ testSuite }}:
                testSuite: ${{ testSuite }}
          maxParallel: ${{ parameters.parallelTestSuites }}
        steps:
        - checkout: self
          fetchDepth: 1
    
        - script: |
           ...
    
        - task: DownloadBuildArtifacts@0
          displayName: 'Download Build Artifacts'
          inputs:
            artifactName: 'BuildTestProducts'
    
       
        - task: CmdLine@2
          ...
    
        - task: CmdLine@2
          ...
    
        - task: Xcode@5
          displayName: 'Run UI Tests'
          ...
          useXcpretty: true
            xcprettyArgs: '-r junit --output "$(Build.ArtifactStagingDirectory)/$(iosDevice)-$(testSuite)-out.xml"'
    
    
        - more tasks...
        ...
    
    

These UI tests can and do get parallelized between different agents. One of the jobs will write errors to temp file.

How can I add a final job that will only run once the entire loop - ${{ each device in parameters.devices }}: with all its nested jobs and tasks gets finished (such that I could send the complete error file to a python script)?

I could normally add dependsOn: property to the final job, but dependsOn requires a name that it depends on, and a loop such as - ${{ each device in parameters.devices }}: doesn't have a static name, and the list of devices and tests can change. Naturally, the jobs within the loop also cannot be depended on to mark a final job because there is no guarantee which of the nested jobs will finish first.

UPD: updated code to include more details

I basically want to do something with the output of the Xcode5 task, so I need my python script to run once after the entire loop is done. I have it working already, but the script gets launched multiple times for each iteration, which is suboptimal. I want to make it better this way.

2

There are 2 best solutions below

0
InfiniteLoop On BEST ANSWER

This did the trick without having to alter anything in the first job's definition:

# Final job
- job: finalJob
  dependsOn:
    - ${{ each device in parameters.devices }}:
      - RunUITests_${{ device.uniqueName }}
  condition: always()
  steps:
0
Krzysztof Madej On

You could combine this with matrix strategy:

parameters:
  devices: []

jobs:
- job: test
  strategy:
    matrix:
      ${{ each device in parameters.devices }}:
    maxParallel: ${{length(parameters.devices)}}
  steps:
  - script: echo ${{ device.uniqueName }} 

- job: 'Publish'
  dependsOn: 'Test'

As far as I know there is not other way as dependsOn here must be known at compile time.