gitlab-dangerfiles 4.6.0 → 4.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 501394f58303715430e058da5fbc46a6c539136b8a888ed22521ab56da6595c3
4
- data.tar.gz: 520c933eb21695e1cdc9e74cea42ec1e636b08455377d2b9dc3ebafe405977ac
3
+ metadata.gz: a3462c1433faf49899f1472e4411ce488ada1b6f59da331ede45114703fe2dfa
4
+ data.tar.gz: 37b7134a0cec36afed2dc1a4d78321cf9c9a80a405c5551fe52b2ce4834fd312
5
5
  SHA512:
6
- metadata.gz: 5d68efa303d47210a6e1d126d9e7706f8872ae61a5a24dacce6b6a48242f8e9d0854f8067d35c64e6340602768e4ed65bd1fcfab71f7447798576172095497bc
7
- data.tar.gz: 79b38327e2b8a133c58124952b2ff371cb551fde1d61aeb29b5f67d29ee212f93c1c423842121f0247304af52414efd5e690d3fa1c4e50083a9dfacdca7f4d33
6
+ metadata.gz: 9a7d44496574a8336bd42665f3c096e4b5c4bb7eeb322533b0b0a84d901d541104878fa13ab214a80fecea15c5c875ad4cb6f98d751b290b8f00108d2d837816
7
+ data.tar.gz: c032a92c6fb18de185e1552faabc9b648573ff95ee1d0b5e88fe3f57c7668e502d251cb51f2bd9e4b36d555c147cb9f538f6904223546b3e4fbbb5591d9826b5
data/.gitignore CHANGED
@@ -3,7 +3,6 @@
3
3
  /.rspec
4
4
  /.bundle/
5
5
  /.yardoc
6
- /Gemfile.lock
7
6
  /_yardoc/
8
7
  /coverage/
9
8
  /pkg/
data/.gitlab-ci.yml CHANGED
@@ -2,9 +2,6 @@ stages:
2
2
  - test
3
3
  - deploy
4
4
 
5
- variables:
6
- DEFAULT_CI_IMAGE: "ruby:${RUBY_VERSION}"
7
-
8
5
  workflow:
9
6
  rules:
10
7
  # For merge requests, create a pipeline.
@@ -15,12 +12,8 @@ workflow:
15
12
  - if: '$CI_COMMIT_TAG'
16
13
 
17
14
  default:
18
- image: "${DEFAULT_CI_IMAGE}"
19
15
  tags:
20
16
  - gitlab-org
21
- before_script:
22
- - gem install bundler
23
- - bundle install -j $(nproc) --path vendor
24
17
  cache:
25
18
  key:
26
19
  files:
@@ -28,12 +21,14 @@ default:
28
21
  - gitlab-dangerfiles.gemspec
29
22
  paths:
30
23
  - vendor/ruby
31
- - Gemfile.lock
32
- policy: pull
33
24
 
34
25
  .default-test-job:
26
+ image: "ruby:${RUBY_VERSION}"
35
27
  stage: test
36
28
  needs: []
29
+ before_script:
30
+ - gem install bundler
31
+ - bundle install -j $(nproc) --path vendor
37
32
  parallel:
38
33
  matrix:
39
34
  - RUBY_VERSION: ['3.0', '3.1', '3.2']
@@ -49,15 +44,13 @@ test:rubocop:
49
44
  - bundle exec rubocop -P -E .
50
45
 
51
46
  include:
52
- - template: Security/Dependency-Scanning.gitlab-ci.yml
53
- - template: Security/SAST.gitlab-ci.yml
54
- - template: Security/Secret-Detection.gitlab-ci.yml
55
- - project: 'gitlab-org/quality/pipeline-common'
56
- file:
57
- - '/ci/danger-review.yml'
58
- - component: "gitlab.com/gitlab-org/quality/pipeline-common/gem-release@7.6.1"
47
+ - component: gitlab.com/components/sast/sast@~latest
48
+ - component: gitlab.com/components/secret-detection/secret-detection@~latest
49
+ - component: gitlab.com/gitlab-org/components/gem-release/gem-release@~latest
59
50
  inputs:
60
51
  smoke_test_script: "ruby -r 'gitlab-dangerfiles' -e \"puts Gitlab::Dangerfiles::VERSION\""
52
+ - component: gitlab.com/gitlab-org/components/danger-review/danger-review@~latest
53
+ - template: Security/Dependency-Scanning.gitlab-ci.yml
61
54
 
62
55
  # run security jobs on MRs
63
56
  # see: https://gitlab.com/gitlab-org/gitlab/-/issues/218444#note_478761991
data/.rubocop.yml CHANGED
@@ -28,6 +28,9 @@ RSpec/FilePath:
28
28
  RSpec/SpecFilePathFormat:
29
29
  Enabled: false
30
30
 
31
+ Style/ArrayIntersect:
32
+ Enabled: false # We're still supporting Ruby 3.1 and below
33
+
31
34
  Style/HashSyntax:
32
35
  EnforcedStyle: ruby19_no_mixed_keys
33
36
  # Introduced in Ruby 3.1. Disable for now.
data/Gemfile.lock ADDED
@@ -0,0 +1,231 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ gitlab-dangerfiles (4.7.0)
5
+ danger (>= 9.3.0)
6
+ danger-gitlab (>= 8.0.0)
7
+ rake (~> 13.0)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ activesupport (7.0.4.2)
13
+ concurrent-ruby (~> 1.0, >= 1.0.2)
14
+ i18n (>= 1.6, < 2)
15
+ minitest (>= 5.1)
16
+ tzinfo (~> 2.0)
17
+ addressable (2.8.1)
18
+ public_suffix (>= 2.0.2, < 6.0)
19
+ ast (2.4.2)
20
+ binding_of_caller (1.0.0)
21
+ debug_inspector (>= 0.0.1)
22
+ claide (1.1.0)
23
+ claide-plugins (0.9.2)
24
+ cork
25
+ nap
26
+ open4 (~> 1.3)
27
+ climate_control (1.2.0)
28
+ coderay (1.1.3)
29
+ colored2 (3.1.2)
30
+ concurrent-ruby (1.2.0)
31
+ cork (0.3.0)
32
+ colored2 (~> 3.1)
33
+ crack (0.4.5)
34
+ rexml
35
+ danger (9.3.0)
36
+ claide (~> 1.0)
37
+ claide-plugins (>= 0.9.2)
38
+ colored2 (~> 3.1)
39
+ cork (~> 0.1)
40
+ faraday (>= 0.9.0, < 3.0)
41
+ faraday-http-cache (~> 2.0)
42
+ git (~> 1.13.0)
43
+ kramdown (~> 2.3)
44
+ kramdown-parser-gfm (~> 1.0)
45
+ no_proxy_fix
46
+ octokit (~> 5.0)
47
+ terminal-table (>= 1, < 4)
48
+ danger-gitlab (8.0.0)
49
+ danger
50
+ gitlab (~> 4.2, >= 4.2.0)
51
+ debug_inspector (1.1.0)
52
+ diff-lcs (1.5.0)
53
+ faraday (2.7.10)
54
+ faraday-net_http (>= 2.0, < 3.1)
55
+ ruby2_keywords (>= 0.0.4)
56
+ faraday-http-cache (2.5.0)
57
+ faraday (>= 0.8)
58
+ faraday-net_http (3.0.2)
59
+ ffi (1.15.5)
60
+ formatador (1.1.0)
61
+ git (1.13.2)
62
+ addressable (~> 2.8)
63
+ rchardet (~> 1.8)
64
+ gitlab (4.19.0)
65
+ httparty (~> 0.20)
66
+ terminal-table (>= 1.5.1)
67
+ gitlab-styles (10.0.0)
68
+ rubocop (~> 1.43.0)
69
+ rubocop-graphql (~> 0.18)
70
+ rubocop-performance (~> 1.15)
71
+ rubocop-rails (~> 2.17)
72
+ rubocop-rspec (~> 2.18)
73
+ guard (2.18.0)
74
+ formatador (>= 0.2.4)
75
+ listen (>= 2.7, < 4.0)
76
+ lumberjack (>= 1.0.12, < 2.0)
77
+ nenv (~> 0.1)
78
+ notiffany (~> 0.0)
79
+ pry (>= 0.13.0)
80
+ shellany (~> 0.0)
81
+ thor (>= 0.18.1)
82
+ guard-compat (1.2.1)
83
+ guard-rspec (4.7.3)
84
+ guard (~> 2.1)
85
+ guard-compat (~> 1.1)
86
+ rspec (>= 2.99.0, < 4.0)
87
+ hashdiff (1.0.1)
88
+ httparty (0.21.0)
89
+ mini_mime (>= 1.0.0)
90
+ multi_xml (>= 0.5.2)
91
+ i18n (1.12.0)
92
+ concurrent-ruby (~> 1.0)
93
+ json (2.6.3)
94
+ kramdown (2.4.0)
95
+ rexml
96
+ kramdown-parser-gfm (1.1.0)
97
+ kramdown (~> 2.0)
98
+ lefthook (1.5.2)
99
+ listen (3.8.0)
100
+ rb-fsevent (~> 0.10, >= 0.10.3)
101
+ rb-inotify (~> 0.9, >= 0.9.10)
102
+ lumberjack (1.2.8)
103
+ method_source (1.0.0)
104
+ mini_mime (1.1.2)
105
+ minitest (5.17.0)
106
+ multi_xml (0.6.0)
107
+ nap (1.1.0)
108
+ nenv (0.3.0)
109
+ no_proxy_fix (0.1.2)
110
+ notiffany (0.1.3)
111
+ nenv (~> 0.1)
112
+ shellany (~> 0.0)
113
+ octokit (5.6.1)
114
+ faraday (>= 1, < 3)
115
+ sawyer (~> 0.9)
116
+ open4 (1.3.4)
117
+ parallel (1.22.1)
118
+ parser (3.2.1.0)
119
+ ast (~> 2.4.1)
120
+ proc_to_ast (0.1.0)
121
+ coderay
122
+ parser
123
+ unparser
124
+ pry (0.14.2)
125
+ coderay (~> 1.1)
126
+ method_source (~> 1.0)
127
+ public_suffix (5.0.1)
128
+ rack (3.0.4.1)
129
+ rainbow (3.1.1)
130
+ rake (13.0.6)
131
+ rb-fsevent (0.11.2)
132
+ rb-inotify (0.10.1)
133
+ ffi (~> 1.0)
134
+ rchardet (1.8.0)
135
+ regexp_parser (2.7.0)
136
+ rexml (3.2.5)
137
+ rspec (3.12.0)
138
+ rspec-core (~> 3.12.0)
139
+ rspec-expectations (~> 3.12.0)
140
+ rspec-mocks (~> 3.12.0)
141
+ rspec-core (3.12.1)
142
+ rspec-support (~> 3.12.0)
143
+ rspec-expectations (3.12.2)
144
+ diff-lcs (>= 1.2.0, < 2.0)
145
+ rspec-support (~> 3.12.0)
146
+ rspec-mocks (3.12.3)
147
+ diff-lcs (>= 1.2.0, < 2.0)
148
+ rspec-support (~> 3.12.0)
149
+ rspec-parameterized (1.0.0)
150
+ rspec-parameterized-core (< 2)
151
+ rspec-parameterized-table_syntax (< 2)
152
+ rspec-parameterized-core (1.0.0)
153
+ parser
154
+ proc_to_ast
155
+ rspec (>= 2.13, < 4)
156
+ unparser
157
+ rspec-parameterized-table_syntax (1.0.0)
158
+ binding_of_caller
159
+ rspec-parameterized-core (< 2)
160
+ rspec-support (3.12.0)
161
+ rubocop (1.43.0)
162
+ json (~> 2.3)
163
+ parallel (~> 1.10)
164
+ parser (>= 3.2.0.0)
165
+ rainbow (>= 2.2.2, < 4.0)
166
+ regexp_parser (>= 1.8, < 3.0)
167
+ rexml (>= 3.2.5, < 4.0)
168
+ rubocop-ast (>= 1.24.1, < 2.0)
169
+ ruby-progressbar (~> 1.7)
170
+ unicode-display_width (>= 2.4.0, < 3.0)
171
+ rubocop-ast (1.26.0)
172
+ parser (>= 3.2.1.0)
173
+ rubocop-capybara (2.19.0)
174
+ rubocop (~> 1.41)
175
+ rubocop-factory_bot (2.24.0)
176
+ rubocop (~> 1.33)
177
+ rubocop-graphql (0.19.0)
178
+ rubocop (>= 0.87, < 2)
179
+ rubocop-performance (1.19.1)
180
+ rubocop (>= 1.7.0, < 2.0)
181
+ rubocop-ast (>= 0.4.0)
182
+ rubocop-rails (2.17.4)
183
+ activesupport (>= 4.2.0)
184
+ rack (>= 1.1)
185
+ rubocop (>= 1.33.0, < 2.0)
186
+ rubocop-rspec (2.24.1)
187
+ rubocop (~> 1.33)
188
+ rubocop-capybara (~> 2.17)
189
+ rubocop-factory_bot (~> 2.22)
190
+ ruby-progressbar (1.11.0)
191
+ ruby2_keywords (0.0.5)
192
+ sawyer (0.9.2)
193
+ addressable (>= 2.3.5)
194
+ faraday (>= 0.17.3, < 3)
195
+ shellany (0.0.1)
196
+ terminal-table (3.0.2)
197
+ unicode-display_width (>= 1.1.1, < 3)
198
+ thor (1.2.1)
199
+ timecop (0.9.6)
200
+ tzinfo (2.0.6)
201
+ concurrent-ruby (~> 1.0)
202
+ unicode-display_width (2.4.2)
203
+ unparser (0.6.7)
204
+ diff-lcs (~> 1.3)
205
+ parser (>= 3.2.0)
206
+ webmock (3.18.1)
207
+ addressable (>= 2.8.0)
208
+ crack (>= 0.3.2)
209
+ hashdiff (>= 0.4.0, < 2.0.0)
210
+ webrick (1.7.0)
211
+ yard (0.9.28)
212
+ webrick (~> 1.7.0)
213
+
214
+ PLATFORMS
215
+ ruby
216
+
217
+ DEPENDENCIES
218
+ climate_control
219
+ gitlab-dangerfiles!
220
+ gitlab-styles (~> 10.0)
221
+ guard-rspec (~> 4.7.3)
222
+ lefthook (~> 1.3)
223
+ rspec (~> 3.8)
224
+ rspec-parameterized
225
+ rubocop-rails (< 2.21.2)
226
+ timecop
227
+ webmock
228
+ yard
229
+
230
+ BUNDLED WITH
231
+ 2.5.4
@@ -27,7 +27,8 @@ module Danger
27
27
  analytics_instrumentation: '~"analytics instrumentation"',
28
28
  import_integrate_be: '~"group::import and integrate" (backend)',
29
29
  import_integrate_fe: '~"group::import and integrate" (frontend)',
30
- "Authentication and Authorization": '~"group::authentication and authorization"',
30
+ Authentication: '~"group::authentication"',
31
+ Authorization: '~"group::authorization"',
31
32
  Compliance: '~"group::compliance"',
32
33
  }.freeze
33
34
  # rubocop:enable Style/HashSyntax
@@ -1,34 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../../gitlab/dangerfiles/approval"
4
+ require_relative "../../gitlab/dangerfiles/spinner"
3
5
  require_relative "../../gitlab/dangerfiles/teammate"
4
- require_relative "../../gitlab/dangerfiles/weightage/maintainers"
5
- require_relative "../../gitlab/dangerfiles/weightage/reviewers"
6
6
 
7
7
  module Danger
8
8
  # Common helper functions for our danger scripts. See Danger::Helper
9
9
  # for more details
10
10
  class Roulette < Danger::Plugin
11
- ROULETTE_DATA_URL = "https://gitlab-org.gitlab.io/gitlab-roulette/roulette.json"
12
11
  HOURS_WHEN_PERSON_CAN_BE_PICKED = (6..14).freeze
13
-
14
- Spin = Struct.new(:category, :reviewer, :maintainer, :optional_role)
15
12
  HTTPError = Class.new(StandardError)
16
13
 
17
- Approval = Struct.new(:category, :spin) do
18
- def self.from_approval_rule(rule, maintainer)
19
- category =
20
- if rule["section"] == "codeowners"
21
- "`#{rule["name"]}`"
22
- else
23
- rule["section"]
24
- end.to_sym
25
-
26
- spin = Spin.new(category, nil, maintainer, :reviewer)
27
-
28
- new(category, spin)
29
- end
30
- end
31
-
32
14
  def prepare_categories(changes_keys)
33
15
  categories = Set.new(changes_keys)
34
16
 
@@ -53,7 +35,7 @@ module Danger
53
35
  #
54
36
  # @return [Gitlab::Dangerfiles::Teammate]
55
37
  def team_mr_author
56
- @team_mr_author ||= find_member(helper.mr_author)
38
+ @team_mr_author ||= Gitlab::Dangerfiles::Teammate.find_member(helper.mr_author)
57
39
  end
58
40
 
59
41
  # Assigns GitLab team members to be reviewer and maintainer
@@ -63,70 +45,22 @@ module Danger
63
45
  # @param categories [Array<Symbol>] An array of categories symbols.
64
46
  #
65
47
  # @return [Array<Spin>]
66
- # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
67
48
  def spin(project = nil, categories = [:none], ux_fallback_wider_community_reviewer: teammate_pedroms)
49
+ # TODO: Deprecate the project argument. It prevents us from
50
+ # memorizing Spinner and can cause unexpected results if it's
51
+ # passing a different project than the merge request project.
68
52
  project = (project || config_project_name).downcase
69
53
  categories = categories.map { |category| category&.downcase || :none }
70
- categories.reject! { |category| import_and_integrate_reject_category?(category, project) }
71
-
72
- spins = categories.sort_by(&:to_s).map do |category|
73
- spin_for_category(project, category)
74
- end
75
-
76
- backend_spin = spins.find { |spin| spin.category == :backend }
77
- frontend_spin = spins.find { |spin| spin.category == :frontend }
78
-
79
- spins.each do |spin|
80
- case spin.category
81
- when :qa
82
- # MR includes QA changes, but also other changes, and author isn't an SET
83
- if categories.size > 1 &&
84
- !(team_mr_author && team_mr_author.capabilities(project).any? { |capability| capability.end_with?("qa") })
85
- spin.optional_role = :maintainer
86
- end
87
- when :test
88
- spin.optional_role = :maintainer
89
-
90
- if spin.reviewer.nil?
91
- # Fetch an already picked backend reviewer, or pick one otherwise
92
- spin.reviewer = backend_spin&.reviewer || spin_for_category(project, :backend).reviewer
93
- end
94
- when :tooling
95
- if spin.maintainer.nil?
96
- # Fetch an already picked backend maintainer, or pick one otherwise
97
- spin.maintainer = backend_spin&.maintainer || spin_for_category(project, :backend).maintainer
98
- end
99
- when :ci_template
100
- if spin.maintainer.nil?
101
- # Fetch an already picked backend maintainer, or pick one otherwise
102
- spin.maintainer = backend_spin&.maintainer || spin_for_category(project, :backend).maintainer
103
- end
104
- when :analytics_instrumentation
105
- spin.optional_role = :maintainer
106
-
107
- if spin.maintainer.nil?
108
- # Fetch an already picked maintainer, or pick one otherwise
109
- spin.maintainer = backend_spin&.maintainer || frontend_spin&.maintainer || spin_for_category(project, :backend).maintainer
110
- end
111
- when :import_integrate_be, :import_integrate_fe
112
- spin.optional_role = :maintainer
113
- when :ux
114
- spin.optional_role = :maintainer
115
54
 
116
- # We want at least a UX reviewer who can review any wider community
117
- # contribution even without a team designer. We assign this to Pedro.
118
- spin.reviewer = ux_fallback_wider_community_reviewer if
119
- labels.include?("Community contribution") &&
120
- spin.reviewer.nil? &&
121
- spin.maintainer.nil?
122
- end
123
- end
124
-
125
- spins
55
+ Gitlab::Dangerfiles::Spinner.new(
56
+ project: project,
57
+ author: helper.mr_author, team_author: team_mr_author,
58
+ labels: labels, categories: categories, random: random,
59
+ ux_fallback_wider_community_reviewer:
60
+ ux_fallback_wider_community_reviewer)
61
+ .spin
126
62
  end
127
63
 
128
- # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
129
-
130
64
  def codeowners_approvals
131
65
  approval_rules = helper.mr_approval_state["rules"]
132
66
 
@@ -134,23 +68,31 @@ module Danger
134
68
 
135
69
  required_approval_rules = unique_approval_rules(approval_rules)
136
70
  required_approval_rules.filter_map do |rule|
137
- spin_for_approval_rule?(rule) &&
138
- Approval.from_approval_rule(rule, spin_for_approver(rule))
71
+ if spin_for_approval_rule?(rule)
72
+ approver = Gitlab::Dangerfiles::Spinner.new(
73
+ project: config_project_name.downcase,
74
+ author: helper.mr_author, team_author: team_mr_author,
75
+ random: random
76
+ ).spin_for_approver(rule)
77
+
78
+ Gitlab::Dangerfiles::Approval.from_approval_rule(rule, approver)
79
+ end
139
80
  end
140
81
  end
141
82
 
83
+ alias_method :required_approvals, :codeowners_approvals
84
+
85
+ # For backward compatibility
142
86
  def warnings
143
- @warnings ||= []
87
+ Gitlab::Dangerfiles::Teammate.warnings
144
88
  end
145
89
 
90
+ private
91
+
146
92
  def teammate_pedroms
147
- @teammate_pedroms ||= find_member("pedroms")
93
+ @teammate_pedroms ||= Gitlab::Dangerfiles::Teammate.find_member("pedroms")
148
94
  end
149
95
 
150
- alias_method :required_approvals, :codeowners_approvals
151
-
152
- private
153
-
154
96
  def spin_for_approval_rule?(rule)
155
97
  rule["rule_type"] == "code_owner" &&
156
98
  should_include_codeowners_rule?(rule) &&
@@ -188,179 +130,17 @@ module Danger
188
130
  end
189
131
  end
190
132
 
191
- # @param [Gitlab::Dangerfiles::Teammate] person
192
- # @return [Boolean]
193
- def valid_person?(person)
194
- !mr_author?(person) && person.available
195
- end
196
-
197
- # @param [Gitlab::Dangerfiles::Teammate] person
198
- # @return [Boolean]
199
- def mr_author?(person)
200
- person.username == helper.mr_author
201
- end
202
-
203
- # @param [String] category name
204
- # @return [Boolean]
205
- def import_and_integrate_reject_category?(category, project)
206
- # Reject Import and Integrate categories if the MR author has reviewing abilities for the category.
207
- team_mr_author&.import_integrate_be?(project, category, labels) ||
208
- team_mr_author&.import_integrate_fe?(project, category, labels)
209
- end
210
-
211
133
  def random
212
134
  @random ||= Random.new(Digest::MD5.hexdigest(helper.mr_source_branch).to_i(16))
213
135
  end
214
136
 
215
- def spin_role_for_category(team, role, project, category)
216
- team.select do |member|
217
- member.public_send("#{role}?", project, category, labels)
218
- end
219
- end
220
-
221
- # Known issue: If someone is rejected due to OOO, and then becomes not OOO, the
222
- # selection will change on next spin.
223
- #
224
- # @param [Array<Gitlab::Dangerfiles::Teammate>] people
225
- #
226
- # @return [Gitlab::Dangerfiles::Teammate]
227
- def spin_for_person(people)
228
- shuffled_people = people.shuffle(random: random)
229
-
230
- shuffled_people.find(&method(:valid_person?))
231
- end
232
-
233
- # Spin a reviewer for a particular approval rule
234
- #
235
- # @param [Hash] rule of approval
236
- #
237
- # @return [Gitlab::Dangerfiles::Teammate]
238
- def spin_for_approver(rule)
239
- approvers = rule["eligible_approvers"].filter_map do |approver|
240
- find_member(approver["username"], project: config_project_name.downcase)
241
- end
242
-
243
- spin_for_person(approvers) || spin_for_approver_fallback(rule)
244
- end
245
-
246
- # It can be possible that we don't have a valid reviewer for approval.
247
- # In this case, we sample again without considering:
248
- #
249
- # * If they're available
250
- # * If they're an actual reviewer from roulette data
251
- #
252
- # We do this because we strictly require an approval from the approvers.
253
- #
254
- # @param [Hash] rule of approval
255
- #
256
- # @return [Gitlab::Dangerfiles::Teammate]
257
- def spin_for_approver_fallback(rule)
258
- fallback_approvers = rule["eligible_approvers"].map do |approver|
259
- find_member(approver["username"]) ||
260
- Gitlab::Dangerfiles::Teammate.new(approver)
261
- end
262
-
263
- # Intentionally not using `spin_for_person` to skip `valid_person?`.
264
- # This should strictly return someone so we don't filter anything,
265
- # and it's a fallback mechanism which should not happen often that
266
- # deserves a complex algorithm.
267
- fallback_approvers.sample(random: random)
268
- end
269
-
270
- def spin_for_category(project, category)
271
- team = project_team(project)
272
- reviewers, traintainers, maintainers =
273
- %i[reviewer traintainer maintainer].map do |role|
274
- spin_role_for_category(team, role, project, category)
275
- end
276
-
277
- weighted_reviewers = Gitlab::Dangerfiles::Weightage::Reviewers.new(reviewers, traintainers).execute
278
- weighted_maintainers = Gitlab::Dangerfiles::Weightage::Maintainers.new(maintainers).execute
279
-
280
- reviewer = spin_for_person(weighted_reviewers)
281
- maintainer = spin_for_person(weighted_maintainers)
282
-
283
- # allow projects with small number of reviewers to take from maintainers if possible
284
- if reviewer.nil? && weighted_maintainers.uniq.size > 1
285
- weighted_maintainers.delete(maintainer)
286
- reviewer = spin_for_person(weighted_maintainers)
287
- end
288
-
289
- Spin.new(category, reviewer, maintainer, false)
290
- end
291
-
292
137
  def prepare_ux_category!(categories)
293
- if labels.include?("Community contribution")
138
+ if labels.include?("Community contribution") ||
139
+ # We only want to spin a reviewer for merge requests which has a
140
+ # designer for the team.
141
+ Gitlab::Dangerfiles::Teammate.has_member_for_the_group?(
142
+ :ux, project: config_project_name.downcase, labels: labels)
294
143
  categories << :ux
295
- else
296
- begin
297
- # We only want to spin a reviewer for merge requests which has a
298
- # designer for the team. There's no easy way to tell this, so we
299
- # pretend this is a community contribution, in which case we only
300
- # pick the team designer. If there's no one got picked, it means
301
- # there's no designer for this team.
302
- labels << "Community contribution"
303
-
304
- # Don't use a fallback reviewer so when a group doesn't have
305
- # available reviewers, it'll not give us any reviewers.
306
- ux_spin = spin(nil, [:ux], ux_fallback_wider_community_reviewer: nil).first
307
-
308
- categories << :ux if ux_spin.reviewer || ux_spin.maintainer
309
- ensure
310
- # Make sure we delete the label afterward
311
- labels.delete("Community contribution")
312
- end
313
- end
314
- end
315
-
316
- # Fetches the given +url+ and parse its response as JSON.
317
- #
318
- # @param [String] url
319
- #
320
- # @return [Hash, Array, NilClass]
321
- def http_get_json(url)
322
- rsp = Net::HTTP.get_response(URI.parse(url))
323
-
324
- if rsp.is_a?(Net::HTTPRedirection)
325
- uri = URI.parse(rsp.header["location"])
326
-
327
- uri.query = nil if uri
328
-
329
- warnings << "Redirection detected: #{uri}."
330
- return nil
331
- end
332
-
333
- unless rsp.is_a?(Net::HTTPOK)
334
- message = rsp.message[0, 30]
335
- warnings << "HTTPError: Failed to read #{url}: #{rsp.code} #{message}."
336
- return nil
337
- end
338
-
339
- JSON.parse(rsp.body)
340
- end
341
-
342
- # Looks up the current list of GitLab team members and parses it into a
343
- # useful form.
344
- #
345
- # @return [Array<Gitlab::Dangerfiles::Teammate>]
346
- def company_members
347
- @company_members ||= begin
348
- data = http_get_json(ROULETTE_DATA_URL) || []
349
- data.map { |hash| Gitlab::Dangerfiles::Teammate.new(hash) }
350
- rescue JSON::ParserError
351
- warnings << "Failed to parse JSON response from #{ROULETTE_DATA_URL}"
352
- []
353
- end
354
- end
355
-
356
- def find_member(username, project: nil)
357
- company_members.find do |member|
358
- member.username == username &&
359
- if project
360
- member.in_project?(project)
361
- else
362
- true
363
- end
364
144
  end
365
145
  end
366
146
 
@@ -377,18 +157,5 @@ module Danger
377
157
  def labels
378
158
  @labels ||= helper.mr_labels
379
159
  end
380
-
381
- # Like +team+, but only returns teammates in the current project, based on
382
- # project_name.
383
- #
384
- # @return [Array<Gitlab::Dangerfiles::Teammate>]
385
- def project_team(project_name)
386
- company_members.select do |member|
387
- member.in_project?(project_name)
388
- end
389
- rescue => err
390
- warn("Reviewer roulette failed to load team data: #{err.message}")
391
- []
392
- end
393
160
  end
394
161
  end