diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-09 09:07:45 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-09 09:07:45 +0000 |
commit | f4186a753b86625a83e8499af14b5badd63a2ac2 (patch) | |
tree | b960dd9f4255e9eee9f87d28e853f163836aa4c5 /app/finders/ci | |
parent | 0221116862ee66024a03492b4fbbe4e069d84303 (diff) | |
download | gitlab-ce-f4186a753b86625a83e8499af14b5badd63a2ac2.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/finders/ci')
-rw-r--r-- | app/finders/ci/pipelines_for_merge_request_finder.rb | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/app/finders/ci/pipelines_for_merge_request_finder.rb b/app/finders/ci/pipelines_for_merge_request_finder.rb new file mode 100644 index 00000000000..c01a68d6749 --- /dev/null +++ b/app/finders/ci/pipelines_for_merge_request_finder.rb @@ -0,0 +1,90 @@ +# frozen_string_literal: true + +module Ci + # A state object to centralize logic related to merge request pipelines + class PipelinesForMergeRequestFinder + include Gitlab::Utils::StrongMemoize + + EVENT = 'merge_request_event' + + def initialize(merge_request) + @merge_request = merge_request + end + + attr_reader :merge_request + + delegate :commit_shas, :source_project, :source_branch, to: :merge_request + + def all + strong_memoize(:all_pipelines) do + next Ci::Pipeline.none unless source_project + + pipelines = + if merge_request.persisted? + pipelines_using_cte + else + triggered_for_branch.for_sha(commit_shas) + end + + sort(pipelines) + end + end + + private + + def pipelines_using_cte + cte = Gitlab::SQL::CTE.new(:shas, merge_request.all_commits.select(:sha)) + + source_pipelines_join = cte.table[:sha].eq(Ci::Pipeline.arel_table[:source_sha]) + source_pipelines = filter_by(triggered_by_merge_request, cte, source_pipelines_join) + detached_pipelines = filter_by_sha(triggered_by_merge_request, cte) + pipelines_for_branch = filter_by_sha(triggered_for_branch, cte) + + Ci::Pipeline.with(cte.to_arel) # rubocop: disable CodeReuse/ActiveRecord + .from_union([source_pipelines, detached_pipelines, pipelines_for_branch]) + end + + def filter_by_sha(pipelines, cte) + hex = Arel::Nodes::SqlLiteral.new("'hex'") + string_sha = Arel::Nodes::NamedFunction.new('encode', [cte.table[:sha], hex]) + join_condition = string_sha.eq(Ci::Pipeline.arel_table[:sha]) + + filter_by(pipelines, cte, join_condition) + end + + def filter_by(pipelines, cte, join_condition) + shas_table = + Ci::Pipeline.arel_table + .join(cte.table, Arel::Nodes::InnerJoin) + .on(join_condition) + .join_sources + + pipelines.joins(shas_table) # rubocop: disable CodeReuse/ActiveRecord + end + + # NOTE: this method returns only parent merge request pipelines. + # Child merge request pipelines have a different source. + def triggered_by_merge_request + source_project.ci_pipelines + .where(source: :merge_request_event, merge_request: merge_request) # rubocop: disable CodeReuse/ActiveRecord + end + + def triggered_for_branch + source_project.ci_pipelines + .where(source: branch_pipeline_sources, ref: source_branch, tag: false) # rubocop: disable CodeReuse/ActiveRecord + end + + def branch_pipeline_sources + strong_memoize(:branch_pipeline_sources) do + Ci::Pipeline.sources.reject { |source| source == EVENT }.values + end + end + + def sort(pipelines) + sql = 'CASE ci_pipelines.source WHEN (?) THEN 0 ELSE 1 END, ci_pipelines.id DESC' + query = ApplicationRecord.send(:sanitize_sql_array, [sql, Ci::Pipeline.sources[:merge_request_event]]) # rubocop:disable GitlabSecurity/PublicSend + + pipelines.order(Arel.sql(query)) # rubocop: disable CodeReuse/ActiveRecord + end + end +end |