2019-10-21 11:05:58 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
module Ci
|
|
|
|
# This class loops through all builds with exposed artifacts and returns
|
|
|
|
# basic information about exposed artifacts for given jobs for the frontend
|
|
|
|
# to display them as custom links in the merge request.
|
|
|
|
#
|
|
|
|
# This service must be used with care.
|
|
|
|
# Looking for exposed artifacts is very slow and should be done asynchronously.
|
|
|
|
class FindExposedArtifactsService < ::BaseService
|
|
|
|
include Gitlab::Routing
|
|
|
|
|
|
|
|
MAX_EXPOSED_ARTIFACTS = 10
|
|
|
|
|
|
|
|
def for_pipeline(pipeline, limit: MAX_EXPOSED_ARTIFACTS)
|
|
|
|
results = []
|
|
|
|
|
|
|
|
pipeline.builds.latest.with_exposed_artifacts.find_each do |job|
|
|
|
|
if job_exposed_artifacts = for_job(job)
|
|
|
|
results << job_exposed_artifacts
|
|
|
|
end
|
|
|
|
|
|
|
|
break if results.size >= limit
|
|
|
|
end
|
|
|
|
|
|
|
|
results
|
|
|
|
end
|
|
|
|
|
|
|
|
def for_job(job)
|
|
|
|
return unless job.has_exposed_artifacts?
|
|
|
|
|
|
|
|
metadata_entries = first_2_metadata_entries_for_artifacts_paths(job)
|
|
|
|
return if metadata_entries.empty?
|
|
|
|
|
|
|
|
{
|
|
|
|
text: job.artifacts_expose_as,
|
|
|
|
url: path_for_entries(metadata_entries, job),
|
2020-03-05 10:07:52 -05:00
|
|
|
job_path: project_job_path(job.project, job),
|
2019-10-21 11:05:58 -04:00
|
|
|
job_name: job.name
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
# we don't need to fetch all artifacts entries for a job because
|
|
|
|
# it could contain many. We only need to know whether it has 1 or more
|
|
|
|
# artifacts, so fetching the first 2 would be sufficient.
|
|
|
|
def first_2_metadata_entries_for_artifacts_paths(job)
|
2020-01-03 10:08:33 -05:00
|
|
|
return [] unless job.artifacts_metadata
|
|
|
|
|
2019-10-21 11:05:58 -04:00
|
|
|
job.artifacts_paths
|
|
|
|
.lazy
|
|
|
|
.map { |path| job.artifacts_metadata_entry(path, recursive: true) }
|
|
|
|
.select { |entry| entry.exists? }
|
|
|
|
.first(2)
|
|
|
|
end
|
|
|
|
|
|
|
|
def path_for_entries(entries, job)
|
|
|
|
return if entries.empty?
|
|
|
|
|
|
|
|
if single_artifact?(entries)
|
2020-03-05 10:07:52 -05:00
|
|
|
file_project_job_artifacts_path(job.project, job, entries.first.path)
|
2019-10-21 11:05:58 -04:00
|
|
|
else
|
2020-03-05 10:07:52 -05:00
|
|
|
browse_project_job_artifacts_path(job.project, job)
|
2019-10-21 11:05:58 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def single_artifact?(entries)
|
|
|
|
entries.size == 1 && entries.first.file?
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|