Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/models/merge_request.rb')
-rw-r--r--app/models/merge_request.rb79
1 files changed, 63 insertions, 16 deletions
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index f4c2d568b4d..3fdc501644d 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -21,10 +21,12 @@ class MergeRequest < ApplicationRecord
include MilestoneEventable
include StateEventable
include ApprovableBase
+ include IdInOrdered
extend ::Gitlab::Utils::Override
sha_attribute :squash_commit_sha
+ sha_attribute :merge_ref_sha
self.reactive_cache_key = ->(model) { [model.project.id, model.iid] }
self.reactive_cache_refresh_interval = 10.minutes
@@ -80,6 +82,8 @@ class MergeRequest < ApplicationRecord
has_many :merge_request_assignees
has_many :assignees, class_name: "User", through: :merge_request_assignees
+ has_many :merge_request_reviewers
+ has_many :reviewers, class_name: "User", through: :merge_request_reviewers
has_many :user_mentions, class_name: "MergeRequestUserMention", dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
has_many :deployment_merge_requests
@@ -105,7 +109,6 @@ class MergeRequest < ApplicationRecord
after_create :ensure_merge_request_diff
after_update :clear_memoized_shas
- after_update :clear_memoized_source_branch_exists
after_update :reload_diff_if_branch_changed
after_commit :ensure_metrics, on: [:create, :update], unless: :importing?
after_commit :expire_etag_cache, unless: :importing?
@@ -250,6 +253,15 @@ class MergeRequest < ApplicationRecord
joins(:notes).where(notes: { commit_id: sha })
end
scope :join_project, -> { joins(:target_project) }
+ scope :join_metrics, -> do
+ query = joins(:metrics)
+
+ if Feature.enabled?(:improved_mr_merged_at_queries, default_enabled: true)
+ query = query.where(MergeRequest.arel_table[:target_project_id].eq(MergeRequest::Metrics.arel_table[:target_project_id]))
+ end
+
+ query
+ end
scope :references_project, -> { references(:target_project) }
scope :with_api_entity_associations, -> {
preload_routables
@@ -263,6 +275,14 @@ class MergeRequest < ApplicationRecord
where("target_branch LIKE ?", ApplicationRecord.sanitize_sql_like(wildcard_branch_name).tr('*', '%'))
end
scope :by_target_branch, ->(branch_name) { where(target_branch: branch_name) }
+ scope :order_merged_at, ->(direction) do
+ query = join_metrics.order(Gitlab::Database.nulls_last_order('merge_request_metrics.merged_at', direction))
+
+ # Add `merge_request_metrics.merged_at` to the `SELECT` in order to make the keyset pagination work.
+ query.select(*query.arel.projections, MergeRequest::Metrics.arel_table[:merged_at].as('"merge_request_metrics.merged_at"'))
+ end
+ scope :order_merged_at_asc, -> { order_merged_at('ASC') }
+ scope :order_merged_at_desc, -> { order_merged_at('DESC') }
scope :preload_source_project, -> { preload(:source_project) }
scope :preload_target_project, -> { preload(:target_project) }
scope :preload_routables, -> do
@@ -294,7 +314,7 @@ class MergeRequest < ApplicationRecord
alias_attribute :auto_merge_enabled, :merge_when_pipeline_succeeds
alias_method :issuing_parent, :target_project
- delegate :active?, to: :head_pipeline, prefix: true, allow_nil: true
+ delegate :active?, :builds_with_coverage, to: :head_pipeline, prefix: true, allow_nil: true
delegate :success?, :active?, to: :actual_head_pipeline, prefix: true, allow_nil: true
RebaseLockTimeout = Class.new(StandardError)
@@ -319,6 +339,15 @@ class MergeRequest < ApplicationRecord
.pluck(:target_branch)
end
+ def self.sort_by_attribute(method, excluded_labels: [])
+ case method.to_s
+ when 'merged_at', 'merged_at_asc' then order_merged_at_asc.with_order_id_desc
+ when 'merged_at_desc' then order_merged_at_desc.with_order_id_desc
+ else
+ super
+ end
+ end
+
def rebase_in_progress?
rebase_jid.present? && Gitlab::SidekiqStatus.running?(rebase_jid)
end
@@ -333,7 +362,11 @@ class MergeRequest < ApplicationRecord
def merge_pipeline
return unless merged?
- target_project.pipeline_for(target_branch, merge_commit_sha)
+ # When the merge_method is :merge there will be a merge_commit_sha, however
+ # when it is fast-forward there is no merge commit, so we must fall back to
+ # either the squash commit (if the MR was squashed) or the diff head commit.
+ sha = merge_commit_sha || squash_commit_sha || diff_head_sha
+ target_project.latest_pipeline(target_branch, sha)
end
# Pattern used to extract `!123` merge request references from text
@@ -867,10 +900,6 @@ class MergeRequest < ApplicationRecord
clear_memoization(:target_branch_head)
end
- def clear_memoized_source_branch_exists
- clear_memoization(:source_branch_exists)
- end
-
def reload_diff_if_branch_changed
if (saved_change_to_source_branch? || saved_change_to_target_branch?) &&
(source_branch_head && target_branch_head)
@@ -928,8 +957,9 @@ class MergeRequest < ApplicationRecord
self.class.wip_title(self.title)
end
- def mergeable?(skip_ci_check: false)
- return false unless mergeable_state?(skip_ci_check: skip_ci_check)
+ def mergeable?(skip_ci_check: false, skip_discussions_check: false)
+ return false unless mergeable_state?(skip_ci_check: skip_ci_check,
+ skip_discussions_check: skip_discussions_check)
check_mergeability
@@ -1122,11 +1152,9 @@ class MergeRequest < ApplicationRecord
end
def source_branch_exists?
- strong_memoize(:source_branch_exists) do
- next false unless self.source_project
+ return false unless self.source_project
- self.source_project.repository.branch_exists?(self.source_branch)
- end
+ self.source_project.repository.branch_exists?(self.source_branch)
end
def target_branch_exists?
@@ -1232,6 +1260,8 @@ class MergeRequest < ApplicationRecord
# Returns the current merge-ref HEAD commit.
#
def merge_ref_head
+ return project.repository.commit(merge_ref_sha) if merge_ref_sha
+
project.repository.commit(merge_ref_path)
end
@@ -1345,9 +1375,9 @@ class MergeRequest < ApplicationRecord
end
def has_coverage_reports?
- return false unless Feature.enabled?(:coverage_report_view, project)
+ return false unless Feature.enabled?(:coverage_report_view, project, default_enabled: true)
- actual_head_pipeline&.has_reports?(Ci::JobArtifact.coverage_reports)
+ actual_head_pipeline&.has_coverage_reports?
end
def has_terraform_reports?
@@ -1447,6 +1477,19 @@ class MergeRequest < ApplicationRecord
Commit.truncate_sha(merge_commit_sha) if merge_commit_sha
end
+ def merged_commit_sha
+ return unless merged?
+
+ sha = merge_commit_sha || squash_commit_sha || diff_head_sha
+ sha.presence
+ end
+
+ def short_merged_commit_sha
+ if sha = merged_commit_sha
+ Commit.truncate_sha(sha)
+ end
+ end
+
def can_be_reverted?(current_user)
return false unless merge_commit
return false unless merged_at
@@ -1561,7 +1604,7 @@ class MergeRequest < ApplicationRecord
def first_contribution?
return false if project.team.max_member_access(author_id) > Gitlab::Access::GUEST
- project.merge_requests.merged.where(author_id: author_id).empty?
+ !project.merge_requests.merged.exists?(author_id: author_id)
end
# TODO: remove once production database rename completes
@@ -1633,6 +1676,10 @@ class MergeRequest < ApplicationRecord
end
end
+ def allows_reviewers?
+ Feature.enabled?(:merge_request_reviewers, project)
+ end
+
private
def with_rebase_lock