gitlab-dangerfiles 4.6.0 → 4.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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