Search code examples
gitlabgitlab-cigitlab-api

How to get the job artifacts of a child pipeline with GitLab API?


job 1 ________ child-pipeline ________ job 3 (x)
         /                       \
job 2 __/                         \___ job 4

I'm trying to reach the artifact of job 3. Here is where I reached so far:

I need the ID of the job 3 according to the GitLab docs. I use Gitbeaker to simplify things in NodeJS but if you are not familiar with it it's fine to answer with curl examples.

First, I got the pipelines of the commit then I retrieved the jobs of those pipelines but those gave me only job 1 and job 2 even though the docs says "In GitLab 13.3 and later, this endpoint returns data for any pipeline including child pipelines. (ref)"

api.Pipelines.all(PROJECT_ID, {
  sha: 'commit_sha',
  ref: 'master',
}).then(async (commitPipelines) => {
  for await (const pipeline of commitPipelines) {
    api.Jobs.showPipelineJobs(PROJECT_ID, pipeline.id, {
      scope: 'success',
    }).then((pipelineJobs) => {
      console.log(pipelineJobs);
    });
  }
});

Then I picked another route to get the commit status of on the child-pipelines stage assuming I would get the pipeline IDs of the child pipelines and I would reach the jobs of them. But the IDs that I got were not the pipeline IDs.

api.Commits.status(PROJECT_ID, 'commit_sha', {
  stage: 'child-pipelines',
  ref: 'master',
}).then((state) => {
  state.forEach(async (commitStatus) => {
    if (commitStatus.status === 'success') {
      console.log(commitStatus);
    }
  });
});

In the end, both of my approaches got stuck at the child pipelines. Maybe, I overlook at this. Any suggestions?


Solution

  • I figured out that Gitlab has an endpoint to access the child pipelines which is called pipeline bridges which helped me to find a solution.

    async function getCommitPipelines(commitId) {
      return await api.Pipelines.all(GITLAB_PROJECT_ID, {
        sha: commitId,
        ref: 'master',
        status: 'success',
      });
    }
    
    async function getPipelineJobs(pipelineId) {
      return await api.Jobs.showPipelineJobs(GITLAB_PROJECT_ID, pipelineId, {
        scope: 'success',
      });
    }
    
    async function getPipelineBridges(pipelineId) {
      return await api.Jobs.showPipelineBridges(GITLAB_PROJECT_ID, pipelineId);
    }
    
    async function downloadArtifactFile(jobId) {
      return await api.Jobs.downloadSingleArtifactFile(
        GITLAB_PROJECT_ID,
        jobId,
        'artifact-file.json',
      );
    }
    
    async function downloadCommitArtifacts(commitId) {
      const commitArtifacts = [];
      // 1. Get all of the pipelines of a the commit
      const commitPipelines = await getCommitPipelines(commitId);
    
      for (const commitPipeline of commitPipelines) {
        // 2. Get all of the downstream pipelines of each pipeline
        const bridgePipelines = await getPipelineBridges(commitPipeline.id);
    
        for (const bridgePipeline of bridgePipelines) {
          // 3. Get all the child pipeline jobs
          // Here you are looking at the job 3 and job 4
          const job = await getPipelineJobs(
            bridgePipeline.downstream_pipeline.id
          );
    
          for (const job of jobs) {
            if (job.name !== 'job-3') {
              continue;
            }
    
            // 4. Get the artifact (the artifact file in this case) from the job
            const artifactFile = await downloadArtifactFile(job.id);
            commitArtifacts.push(artifactFile);
          }
        }
      }
    
      return commitArtifacts;
    }