azure-devopsazure-pipelinesazure-pipelines-yamlazure-artifacts

Azure DevOps Pipeline to check if artifacts exists from a specific pipeline, if not found then trigger the pipeline


I have a main pipeline which is downloading pipeline artifact from a specific pipeline.

- task: DownloadPipelineArtifact@2
  inputs:
    source: specific
    project: ABC
    pipeline: 1
    runVersion: latestFromBranch
    runBranch: $(Build.SourceBranch)
    artifact: artifact-abc
    targetPath: $(Pipeline.Workspace)

I need to do a prerequisite check if artifact exists for the specific pipeline for the branch if not then run the specific pipeline. How to achieve this? Can we make use of a python script to invoke REST API to check and trigger the pipeline run?


Solution

  • You could use the Builds - List API to retrieve a list of builds, then loop through those results and check if the artifact exists.

    - task: PowerShell@2
      displayName: Locate existing artifact
      inputs:
        targetType: inline
        script: |
          $project = "ABC"
          $pipeline = "1"
          $branch = "$(Build.SourceBranch)"
          $artifact = "artifact-abc"
          $baseUrl = "$(System.CollectionUri)/$project"
          $headers = @{ Authorization = "Bearer $(System.AccessToken)" }
    
          $url = $baseUrl + `
                 "/_apis/build/builds?definitions=$pipeline" + `
                 "&branchName=$branch" + `
                 "&resultFilter=succeeded" + `
                 "&statusFilter=completed" + `
                 "&queryOrder=queueTimeDescending" + `
                 "&api-version=7.1"
    
          # obtain list of build candidates
          $result = Invoke-RestMethod `
                      -Method Get `
                      -Uri $url `
                      -Headers $headers `
                      -UseBasicParsing
    
          # loop through builds to find artifact
          $builds = $result.value
          if $(builds) {
            $builds | ForEach-Object {
              $buildId = $_.id
              $artifactUrl = $baseUrl + `
                             "_apis/build/builds/$pipeline/artifacts" + `
                             "?artifactName=$artifact" + `
                             "&api-version=7.1"
     
              # check if artifact exists
              try {
                $result = Invoke-RestMethod `
                            -Method Get `
                            -Uri $artifactUrl `
                            -Headers $headers `
                            -UseBasicParsing
                if ($result.name -eq $artifact) {
                  # artifact found!
                  Write-Output "##vso[task.setvariable variable=artifactExists]true"
                  break
                }
              }
              catch {}
            }
          }
          Write-Host "Artifact not found."
    

    Then you can use the Pipeline - Run API to queue the pipeline. You'd then have to query the pipeline using Runs - Get until it's completed. This isn't an ideal, because you're using your build agent to monitor another build. If you only have a single build agent, this obviously won't work.

    - task: PowerShell@2
      displayName: Invoke build
      condition: ne(variables['artifactExists'], 'true')
      inputs:
        targetType: inline
        script: |
          $branch = "$(Build.SourceBranch)"
          $project = "ABC"
          $pipeline = "1"
          $baseUrl = "$(System.CollectionUri)/$project"
          $headers = @{ Authorization = "Bearer $(System.AccessToken)" }
    
          $invokeUrl = $baseUrl + `
                         "/_apis/pipelines/$pipeline/runs" + `
                         "?api-version=7.1"
          $invokeBody = @{
            resources = @{
               repositories = @{
                 self = @{
                  refName = $branch
                 }
               }
            }
          } | ConvertTo-Json -Depth 10
    
          # queue the build
          $result = Invoke-RestMethod `
                      -Method POST `
                      -Body $invokeBody `
                      -Uri $invokeUrl `
                      -Headers $headers
          
          $runId = $result.id
    
          # Monitor the build
          $monitorUrl = $baseUrl + `
                 "/_apis/pipelines/$pipeline/runs/$runId?api-version=7.1"
    
          $done = false
          while (!$done) {
            Start-Delay -Seconds 60
            $result = Invoke-RestMethod `
                       -Method Get `
                       -Uri $monitorUrl `
                       -Headers $headers
            $done = $result.state -eq "completed"
          }