debian-mirror-gitlab/app/finders/ci/pipelines_for_merge_request_finder.rb

122 lines
4.1 KiB
Ruby
Raw Normal View History

2020-04-08 14:13:33 +05:30
# frozen_string_literal: true
module Ci
# A state object to centralize logic related to merge request pipelines
class PipelinesForMergeRequestFinder
include Gitlab::Utils::StrongMemoize
2020-07-28 23:09:34 +05:30
def initialize(merge_request, current_user)
2020-04-08 14:13:33 +05:30
@merge_request = merge_request
2020-07-28 23:09:34 +05:30
@current_user = current_user
2020-04-08 14:13:33 +05:30
end
2020-07-28 23:09:34 +05:30
attr_reader :merge_request, :current_user
2020-04-08 14:13:33 +05:30
2020-07-28 23:09:34 +05:30
delegate :commit_shas, :target_project, :source_project, :source_branch, to: :merge_request
2020-04-08 14:13:33 +05:30
2020-07-28 23:09:34 +05:30
# Fetch all pipelines that the user can read.
def execute
if can_read_pipeline_in_target_project? && can_read_pipeline_in_source_project?
all
elsif can_read_pipeline_in_source_project?
all.for_project(merge_request.source_project)
elsif can_read_pipeline_in_target_project?
all.for_project(merge_request.target_project)
else
Ci::Pipeline.none
end
end
# Fetch all pipelines without permission check.
2020-04-08 14:13:33 +05:30
def all
strong_memoize(:all_pipelines) do
next Ci::Pipeline.none unless source_project
pipelines =
if merge_request.persisted?
2021-02-22 17:27:13 +05:30
if Feature.enabled?(:ci_pipelines_for_merge_request_finder_new_cte, target_project)
pipelines_using_cte
else
pipelines_using_legacy_cte
end
2020-04-08 14:13:33 +05:30
else
triggered_for_branch.for_sha(commit_shas)
end
sort(pipelines)
end
end
private
2021-02-22 17:27:13 +05:30
def pipelines_using_legacy_cte
2020-04-08 14:13:33 +05:30
cte = Gitlab::SQL::CTE.new(:shas, merge_request.all_commits.select(:sha))
2020-07-28 23:09:34 +05:30
source_sha_join = cte.table[:sha].eq(Ci::Pipeline.arel_table[:source_sha])
merged_result_pipelines = filter_by(triggered_by_merge_request, cte, source_sha_join)
detached_merge_request_pipelines = filter_by_sha(triggered_by_merge_request, cte)
2020-04-08 14:13:33 +05:30
pipelines_for_branch = filter_by_sha(triggered_for_branch, cte)
Ci::Pipeline.with(cte.to_arel) # rubocop: disable CodeReuse/ActiveRecord
2020-07-28 23:09:34 +05:30
.from_union([merged_result_pipelines, detached_merge_request_pipelines, pipelines_for_branch])
2020-04-08 14:13:33 +05:30
end
2021-02-22 17:27:13 +05:30
def pipelines_using_cte
cte = Gitlab::SQL::CTE.new(:shas, merge_request.all_commits.select(:sha))
pipelines_for_merge_requests = triggered_by_merge_request
pipelines_for_branch = filter_by_sha(triggered_for_branch, cte)
Ci::Pipeline.with(cte.to_arel) # rubocop: disable CodeReuse/ActiveRecord
.from_union([pipelines_for_merge_requests, pipelines_for_branch])
end
2020-04-08 14:13:33 +05:30
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
2020-07-28 23:09:34 +05:30
Ci::Pipeline.triggered_by_merge_request(merge_request)
2020-04-08 14:13:33 +05:30
end
def triggered_for_branch
2021-02-22 17:27:13 +05:30
source_project.all_pipelines.ci_branch_sources.for_branch(source_branch)
2020-04-08 14:13:33 +05:30
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
2020-07-28 23:09:34 +05:30
def can_read_pipeline_in_target_project?
strong_memoize(:can_read_pipeline_in_target_project) do
Ability.allowed?(current_user, :read_pipeline, target_project)
end
end
def can_read_pipeline_in_source_project?
strong_memoize(:can_read_pipeline_in_source_project) do
Ability.allowed?(current_user, :read_pipeline, source_project)
end
end
2020-04-08 14:13:33 +05:30
end
end