summaryrefslogtreecommitdiff
path: root/app/finders/merge_requests_finder.rb
blob: 7bdc98d2e3d73b238e7631fd3f5bcedb3eb21060 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# frozen_string_literal: true

# Finders::MergeRequest class
#
# Used to filter MergeRequests collections by set of params
#
# Arguments:
#   current_user - which user use
#   params:
#     scope: 'created_by_me' or 'assigned_to_me' or 'all'
#     state: 'open', 'closed', 'merged', 'locked', or 'all'
#     group_id: integer
#     project_id: integer
#     milestone_title: string
#     release_tag: string
#     author_id: integer
#     author_username: string
#     assignee_id: integer
#     search: string
#     in: 'title', 'description', or a string joining them with comma
#     label_name: string
#     sort: string
#     non_archived: boolean
#     my_reaction_emoji: string
#     source_branch: string
#     target_branch: string
#     created_after: datetime
#     created_before: datetime
#     updated_after: datetime
#     updated_before: datetime
#
class MergeRequestsFinder < IssuableFinder
  include MergedAtFilter

  def self.scalar_params
    @scalar_params ||= super + [:wip, :draft, :target_branch, :merged_after, :merged_before, :approved_by_ids]
  end

  def self.array_params
    @array_params ||= super.merge(approved_by_usernames: [])
  end

  def klass
    MergeRequest
  end

  def filter_items(_items)
    items = by_commit(super)
    items = by_deployment(items)
    items = by_source_branch(items)
    items = by_draft(items)
    items = by_target_branch(items)
    items = by_merged_at(items)
    items = by_approvals(items)
    by_source_project_id(items)
  end

  private

  def by_commit(items)
    return items unless params[:commit_sha].presence

    items.by_commit_sha(params[:commit_sha])
  end

  def source_branch
    @source_branch ||= params[:source_branch].presence
  end

  # rubocop: disable CodeReuse/ActiveRecord
  def by_source_branch(items)
    return items unless source_branch

    items.where(source_branch: source_branch)
  end
  # rubocop: enable CodeReuse/ActiveRecord

  def target_branch
    @target_branch ||= params[:target_branch].presence
  end

  # rubocop: disable CodeReuse/ActiveRecord
  def by_target_branch(items)
    return items unless target_branch

    items.where(target_branch: target_branch)
  end

  def source_project_id
    @source_project_id ||= params[:source_project_id].presence
  end

  def by_source_project_id(items)
    return items unless source_project_id

    items.where(source_project_id: source_project_id)
  end

  def by_draft(items)
    draft_param = params[:draft] || params[:wip]

    if draft_param == 'yes'
      items.where(wip_match(items.arel_table))
    elsif draft_param == 'no'
      items.where.not(wip_match(items.arel_table))
    else
      items
    end
  end

  # WIP is deprecated in favor of Draft. Currently both options are supported
  def wip_match(table)
    items =
      table[:title].matches('WIP:%')
        .or(table[:title].matches('WIP %'))
        .or(table[:title].matches('[WIP]%'))

    # Let's keep this FF around until https://gitlab.com/gitlab-org/gitlab/-/issues/232999
    # is implemented
    return items unless Feature.enabled?(:merge_request_draft_filter, default_enabled: true)

    items
      .or(table[:title].matches('Draft - %'))
      .or(table[:title].matches('Draft:%'))
      .or(table[:title].matches('[Draft]%'))
      .or(table[:title].matches('(Draft)%'))
  end

  def by_deployment(items)
    return items unless deployment_id

    items.includes(:deployment_merge_requests)
         .where(deployment_merge_requests: { deployment_id: deployment_id })
  end

  def deployment_id
    @deployment_id ||= params[:deployment_id].presence
  end

  # Filter by merge requests that had been approved by specific users
  # rubocop: disable CodeReuse/Finder
  def by_approvals(items)
    MergeRequests::ByApprovalsFinder
      .new(params[:approved_by_usernames], params[:approved_by_ids])
      .execute(items)
  end
  # rubocop: enable CodeReuse/Finder
end

MergeRequestsFinder.prepend_if_ee('EE::MergeRequestsFinder')