azure-devopsazure-pipelinesxcode-ui-testing

How to create a final job within ADO CI pipeline yaml that will only run once all the parallel jobs within a loop of tests and devices finish?


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.


Solution

  • 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: