From ad1e4b8fb8104b642fa79ed34fd144bc2bed8a19 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Mon, 21 Oct 2019 15:05:58 +0000 Subject: Add latest changes from gitlab-org/gitlab@master --- app/services/ci/compare_reports_base_service.rb | 5 ++ app/services/ci/find_exposed_artifacts_service.rb | 70 ++++++++++++++++++++++ .../generate_exposed_artifacts_report_service.rb | 30 ++++++++++ 3 files changed, 105 insertions(+) create mode 100644 app/services/ci/find_exposed_artifacts_service.rb create mode 100644 app/services/ci/generate_exposed_artifacts_report_service.rb (limited to 'app/services/ci') diff --git a/app/services/ci/compare_reports_base_service.rb b/app/services/ci/compare_reports_base_service.rb index 5b76e1824e4..83ba70e8437 100644 --- a/app/services/ci/compare_reports_base_service.rb +++ b/app/services/ci/compare_reports_base_service.rb @@ -1,6 +1,11 @@ # frozen_string_literal: true module Ci + # TODO: when using this class with exposed artifacts we see that there are + # 2 responsibilities: + # 1. reactive caching interface (same in all cases) + # 2. data generator (report comparison in most of the case but not always) + # issue: https://gitlab.com/gitlab-org/gitlab/issues/34224 class CompareReportsBaseService < ::BaseService def execute(base_pipeline, head_pipeline) comparer = comparer_class.new(get_report(base_pipeline), get_report(head_pipeline)) diff --git a/app/services/ci/find_exposed_artifacts_service.rb b/app/services/ci/find_exposed_artifacts_service.rb new file mode 100644 index 00000000000..5c75af294bf --- /dev/null +++ b/app/services/ci/find_exposed_artifacts_service.rb @@ -0,0 +1,70 @@ +# 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), + job_path: project_job_path(project, job), + 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) + 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) + file_project_job_artifacts_path(project, job, entries.first.path) + else + browse_project_job_artifacts_path(project, job) + end + end + + def single_artifact?(entries) + entries.size == 1 && entries.first.file? + end + end +end diff --git a/app/services/ci/generate_exposed_artifacts_report_service.rb b/app/services/ci/generate_exposed_artifacts_report_service.rb new file mode 100644 index 00000000000..b9bf580bcbc --- /dev/null +++ b/app/services/ci/generate_exposed_artifacts_report_service.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module Ci + # TODO: a couple of points with this approach: + # + reuses existing architecture and reactive caching + # - it's not a report comparison and some comparing features must be turned off. + # see CompareReportsBaseService for more notes. + # issue: https://gitlab.com/gitlab-org/gitlab/issues/34224 + class GenerateExposedArtifactsReportService < CompareReportsBaseService + def execute(base_pipeline, head_pipeline) + data = FindExposedArtifactsService.new(project, current_user).for_pipeline(head_pipeline) + { + status: :parsed, + key: key(base_pipeline, head_pipeline), + data: data + } + rescue => e + Gitlab::Sentry.track_acceptable_exception(e, extra: { project_id: project.id }) + { + status: :error, + key: key(base_pipeline, head_pipeline), + status_reason: _('An error occurred while fetching exposed artifacts.') + } + end + + def latest?(base_pipeline, head_pipeline, data) + data&.fetch(:key, nil) == key(base_pipeline, head_pipeline) + end + end +end -- cgit v1.2.3