gitlab-dangerfiles 0.1.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/danger/helper.rb +155 -113
- data/lib/danger/roulette.rb +68 -36
- data/lib/gitlab/dangerfiles.rb +0 -34
- data/lib/gitlab/dangerfiles/base_linter.rb +96 -0
- data/lib/gitlab/dangerfiles/commit_linter.rb +25 -103
- data/lib/gitlab/dangerfiles/merge_request_linter.rb +30 -0
- data/lib/gitlab/dangerfiles/teammate.rb +23 -9
- data/lib/gitlab/dangerfiles/title_linting.rb +38 -0
- data/lib/gitlab/dangerfiles/version.rb +1 -1
- data/lib/gitlab/dangerfiles/weightage.rb +10 -0
- data/lib/gitlab/dangerfiles/weightage/maintainers.rb +33 -0
- data/lib/gitlab/dangerfiles/weightage/reviewers.rb +65 -0
- metadata +9 -25
- data/lib/danger/changelog.rb +0 -39
- data/lib/danger/sidekiq_queues.rb +0 -37
- data/lib/gitlab/dangerfiles/bundle_size/Dangerfile +0 -38
- data/lib/gitlab/dangerfiles/ce_ee_vue_templates/Dangerfile +0 -56
- data/lib/gitlab/dangerfiles/changelog/Dangerfile +0 -90
- data/lib/gitlab/dangerfiles/changes_size/Dangerfile +0 -17
- data/lib/gitlab/dangerfiles/commit_messages/Dangerfile +0 -135
- data/lib/gitlab/dangerfiles/database/Dangerfile +0 -67
- data/lib/gitlab/dangerfiles/documentation/Dangerfile +0 -29
- data/lib/gitlab/dangerfiles/duplicate_yarn_dependencies/Dangerfile +0 -29
- data/lib/gitlab/dangerfiles/eslint/Dangerfile +0 -31
- data/lib/gitlab/dangerfiles/frozen_string/Dangerfile +0 -28
- data/lib/gitlab/dangerfiles/karma/Dangerfile +0 -51
- data/lib/gitlab/dangerfiles/metadata/Dangerfile +0 -50
- data/lib/gitlab/dangerfiles/popen.rb +0 -55
- data/lib/gitlab/dangerfiles/prettier/Dangerfile +0 -41
- data/lib/gitlab/dangerfiles/roulette/Dangerfile +0 -97
- data/lib/gitlab/dangerfiles/sidekiq_queues/Dangerfile +0 -27
- data/lib/gitlab/dangerfiles/specs/Dangerfile +0 -42
- data/lib/gitlab/dangerfiles/tasks.rb +0 -19
- data/lib/gitlab/dangerfiles/telemetry/Dangerfile +0 -32
- data/lib/gitlab/dangerfiles/utility_css/Dangerfile +0 -51
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a41237cf8c1b948162962ffd5712cac36034d6e3f6ddbd551f7b7f5c64315ac6
|
4
|
+
data.tar.gz: 9416beb3ed3688db58d83bfafb103a3f21b15c7a1e1dae83fe08dae33b13d329
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 294c63c0dad1685a71e4110ab5248d96e7efa97ef448dc861c6a443a8123fd490b1fbdf303b87bf7c18802074b24b3b371a433b3ef06c831cc368559c4c832a0
|
7
|
+
data.tar.gz: aa3bc70fe5068018df9dd1eee9010732b4df231033434ba02c3872b0902e3850adde1b97b6228dbda9f58e10c032b7d4b6467c96f18392d3e74dfab497638835
|
data/lib/danger/helper.rb
CHANGED
@@ -2,93 +2,72 @@
|
|
2
2
|
|
3
3
|
require "net/http"
|
4
4
|
require "json"
|
5
|
+
require "danger"
|
5
6
|
require_relative "../gitlab/dangerfiles/teammate"
|
7
|
+
require_relative "../gitlab/dangerfiles/title_linting"
|
6
8
|
|
7
9
|
module Danger
|
8
10
|
# Common helper functions for our danger scripts.
|
9
11
|
class Helper < Danger::Plugin
|
10
12
|
RELEASE_TOOLS_BOT = "gitlab-release-tools-bot"
|
13
|
+
DRAFT_REGEX = /\A*#{Regexp.union(/(?i)(\[WIP\]\s*|WIP:\s*|WIP$)/, /(?i)(\[draft\]|\(draft\)|draft:|draft\s\-\s|draft$)/)}+\s*/i.freeze
|
11
14
|
CATEGORY_LABELS = {
|
12
15
|
docs: "~documentation", # Docs are reviewed along DevOps stages, so don't need roulette for now.
|
13
16
|
none: "",
|
14
17
|
qa: "~QA",
|
15
18
|
test: "~test ~Quality for `spec/features/*`",
|
16
19
|
engineering_productivity: '~"Engineering Productivity" for CI, Danger',
|
17
|
-
|
18
|
-
# First-match win, so be sure to put more specific regex at the top...
|
19
|
-
CATEGORIES = {
|
20
|
-
%r{\Adoc/} => :docs,
|
21
|
-
%r{\A(CONTRIBUTING|LICENSE|MAINTENANCE|PHILOSOPHY|PROCESS|README)(\.md)?\z} => :docs,
|
22
|
-
|
23
|
-
%r{\A(ee/)?app/(assets|views)/} => :frontend,
|
24
|
-
%r{\A(ee/)?public/} => :frontend,
|
25
|
-
%r{\A(ee/)?spec/(javascripts|frontend)/} => :frontend,
|
26
|
-
%r{\A(ee/)?vendor/assets/} => :frontend,
|
27
|
-
%r{\A(ee/)?scripts/frontend/} => :frontend,
|
28
|
-
%r{(\A|/)(
|
29
|
-
\.babelrc |
|
30
|
-
\.eslintignore |
|
31
|
-
\.eslintrc(\.yml)? |
|
32
|
-
\.nvmrc |
|
33
|
-
\.prettierignore |
|
34
|
-
\.prettierrc |
|
35
|
-
\.scss-lint.yml |
|
36
|
-
\.stylelintrc |
|
37
|
-
\.haml-lint.yml |
|
38
|
-
\.haml-lint_todo.yml |
|
39
|
-
babel\.config\.js |
|
40
|
-
jest\.config\.js |
|
41
|
-
package\.json |
|
42
|
-
yarn\.lock |
|
43
|
-
config/.+\.js
|
44
|
-
)\z}x => :frontend,
|
45
|
-
|
46
|
-
%r{(\A|/)(
|
47
|
-
\.gitlab/ci/frontend\.gitlab-ci\.yml
|
48
|
-
)\z}x => %i[frontend engineering_productivity],
|
49
|
-
|
50
|
-
%r{\A(ee/)?db/(?!fixtures)[^/]+} => :database,
|
51
|
-
%r{\A(ee/)?lib/gitlab/(database|background_migration|sql|github_import)(/|\.rb)} => :database,
|
52
|
-
%r{\A(app/models/project_authorization|app/services/users/refresh_authorized_projects_service)(/|\.rb)} => :database,
|
53
|
-
%r{\A(ee/)?app/finders/} => :database,
|
54
|
-
%r{\Arubocop/cop/migration(/|\.rb)} => :database,
|
55
|
-
|
56
|
-
%r{\A(\.gitlab-ci\.yml\z|\.gitlab\/ci)} => :engineering_productivity,
|
57
|
-
%r{\A\.codeclimate\.yml\z} => :engineering_productivity,
|
58
|
-
%r{\A\.overcommit\.yml\.example\z} => :engineering_productivity,
|
59
|
-
%r{\A\.editorconfig\z} => :engineering_productivity,
|
60
|
-
%r{Dangerfile\z} => :engineering_productivity,
|
61
|
-
%r{\A(ee/)?(danger/|lib/gitlab/danger/)} => :engineering_productivity,
|
62
|
-
%r{\A(ee/)?scripts/} => :engineering_productivity,
|
63
|
-
%r{\Atooling/} => :engineering_productivity,
|
64
|
-
|
65
|
-
%r{\A(ee/)?app/(?!assets|views)[^/]+} => :backend,
|
66
|
-
%r{\A(ee/)?(bin|config|generator_templates|lib|rubocop)/} => :backend,
|
67
|
-
%r{\A(ee/)?spec/features/} => :test,
|
68
|
-
%r{\A(ee/)?spec/} => :backend,
|
69
|
-
%r{\A(ee/)?vendor/} => :backend,
|
70
|
-
%r{\A(Gemfile|Gemfile.lock|Rakefile)\z} => :backend,
|
71
|
-
%r{\A[A-Z_]+_VERSION\z} => :backend,
|
72
|
-
%r{\A\.rubocop(_todo)?\.yml\z} => :backend,
|
73
|
-
%r{\Afile_hooks/} => :backend,
|
74
|
-
|
75
|
-
%r{\A(ee/)?qa/} => :qa,
|
76
|
-
|
77
|
-
# Files that don't fit into any category are marked with :none
|
78
|
-
%r{\A(ee/)?changelogs/} => :none,
|
79
|
-
%r{\Alocale/gitlab\.pot\z} => :none,
|
80
|
-
|
81
|
-
# Fallbacks in case the above patterns miss anything
|
82
|
-
%r{\.rb\z} => :backend,
|
83
|
-
%r{(
|
84
|
-
\.(md|txt)\z |
|
85
|
-
\.markdownlint\.json
|
86
|
-
)}x => :none, # To reinstate roulette for documentation, set to `:docs`.
|
87
|
-
%r{\.js\z} => :frontend,
|
20
|
+
ci_template: '~"ci::templates"',
|
88
21
|
}.freeze
|
89
22
|
|
90
23
|
HTTPError = Class.new(StandardError)
|
91
24
|
|
25
|
+
Change = Struct.new(:file, :change_type, :category)
|
26
|
+
|
27
|
+
class Changes < ::SimpleDelegator
|
28
|
+
def added
|
29
|
+
select_by_change_type(:added)
|
30
|
+
end
|
31
|
+
|
32
|
+
def modified
|
33
|
+
select_by_change_type(:modified)
|
34
|
+
end
|
35
|
+
|
36
|
+
def deleted
|
37
|
+
select_by_change_type(:deleted)
|
38
|
+
end
|
39
|
+
|
40
|
+
def renamed_before
|
41
|
+
select_by_change_type(:renamed_before)
|
42
|
+
end
|
43
|
+
|
44
|
+
def renamed_after
|
45
|
+
select_by_change_type(:renamed_after)
|
46
|
+
end
|
47
|
+
|
48
|
+
def has_category?(category)
|
49
|
+
any? { |change| change.category == category }
|
50
|
+
end
|
51
|
+
|
52
|
+
def by_category(category)
|
53
|
+
Changes.new(select { |change| change.category == category })
|
54
|
+
end
|
55
|
+
|
56
|
+
def categories
|
57
|
+
map(&:category).uniq
|
58
|
+
end
|
59
|
+
|
60
|
+
def files
|
61
|
+
map(&:file)
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def select_by_change_type(change_type)
|
67
|
+
Changes.new(select { |change| change.change_type == change_type })
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
92
71
|
def gitlab_helper
|
93
72
|
# Unfortunately the following does not work:
|
94
73
|
# - respond_to?(:gitlab)
|
@@ -98,10 +77,6 @@ module Danger
|
|
98
77
|
nil
|
99
78
|
end
|
100
79
|
|
101
|
-
def rule_names
|
102
|
-
ci? ? Gitlab::Dangerfiles::LOCAL_RULES | Gitlab::Dangerfiles::CI_ONLY_RULES : Gitlab::Dangerfiles::LOCAL_RULES
|
103
|
-
end
|
104
|
-
|
105
80
|
def html_link(str)
|
106
81
|
ci? ? gitlab_helper.html_link(str) : str
|
107
82
|
end
|
@@ -148,23 +123,25 @@ module Danger
|
|
148
123
|
.sort
|
149
124
|
end
|
150
125
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
126
|
+
# Returns a string containing changed lines as git diff
|
127
|
+
#
|
128
|
+
# Considering changing a line in lib/gitlab/usage_data.rb it will return:
|
129
|
+
#
|
130
|
+
# [ "--- a/lib/gitlab/usage_data.rb",
|
131
|
+
# "+++ b/lib/gitlab/usage_data.rb",
|
132
|
+
# "+ # Test change",
|
133
|
+
# "- # Old change" ]
|
134
|
+
def changed_lines(changed_file)
|
135
|
+
diff = git.diff_for_file(changed_file)
|
136
|
+
return [] unless diff
|
137
|
+
|
138
|
+
diff.patch.split("\n").select { |line| %r{^[+-]}.match?(line) }
|
158
139
|
end
|
159
140
|
|
160
141
|
def release_automation?
|
161
142
|
gitlab_helper&.mr_author == RELEASE_TOOLS_BOT
|
162
143
|
end
|
163
144
|
|
164
|
-
def project_name
|
165
|
-
ee? ? "gitlab" : "gitlab-foss"
|
166
|
-
end
|
167
|
-
|
168
145
|
def markdown_list(items)
|
169
146
|
list = items.map { |item| "* `#{item}`" }.join("\n")
|
170
147
|
|
@@ -175,17 +152,51 @@ module Danger
|
|
175
152
|
end
|
176
153
|
end
|
177
154
|
|
178
|
-
# @return [Hash<
|
179
|
-
def changes_by_category
|
155
|
+
# @return [Hash<Symbol,Array<String>>]
|
156
|
+
def changes_by_category(categories)
|
180
157
|
all_changed_files.each_with_object(Hash.new { |h, k| h[k] = [] }) do |file, hash|
|
181
|
-
categories_for_file(file).each { |category| hash[category] << file }
|
158
|
+
categories_for_file(file, categories).each { |category| hash[category] << file }
|
182
159
|
end
|
183
160
|
end
|
184
161
|
|
185
|
-
#
|
162
|
+
# @return [Changes]
|
163
|
+
def changes(categories)
|
164
|
+
Changes.new([]).tap do |changes|
|
165
|
+
git.added_files.each do |file|
|
166
|
+
categories_for_file(file, categories).each { |category| changes << Change.new(file, :added, category) }
|
167
|
+
end
|
168
|
+
|
169
|
+
git.modified_files.each do |file|
|
170
|
+
categories_for_file(file, categories).each { |category| changes << Change.new(file, :modified, category) }
|
171
|
+
end
|
172
|
+
|
173
|
+
git.deleted_files.each do |file|
|
174
|
+
categories_for_file(file, categories).each { |category| changes << Change.new(file, :deleted, category) }
|
175
|
+
end
|
176
|
+
|
177
|
+
git.renamed_files.map { |x| x[:before] }.each do |file|
|
178
|
+
categories_for_file(file, categories).each { |category| changes << Change.new(file, :renamed_before, category) }
|
179
|
+
end
|
180
|
+
|
181
|
+
git.renamed_files.map { |x| x[:after] }.each do |file|
|
182
|
+
categories_for_file(file, categories).each { |category| changes << Change.new(file, :renamed_after, category) }
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
# Determines the categories a file is in, e.g., `[:frontend]`, `[:backend]`, or `%i[frontend engineering_productivity]`
|
188
|
+
# using filename regex and specific change regex if given.
|
189
|
+
#
|
186
190
|
# @return Array<Symbol>
|
187
|
-
def categories_for_file(file)
|
188
|
-
_, categories =
|
191
|
+
def categories_for_file(file, categories)
|
192
|
+
_, categories = categories.find do |key, _|
|
193
|
+
filename_regex, changes_regex = Array(key)
|
194
|
+
|
195
|
+
found = filename_regex.match?(file)
|
196
|
+
found &&= changed_lines(file).any? { |changed_line| changes_regex.match?(changed_line) } if changes_regex
|
197
|
+
|
198
|
+
found
|
199
|
+
end
|
189
200
|
|
190
201
|
Array(categories || :unknown)
|
191
202
|
end
|
@@ -202,43 +213,64 @@ module Danger
|
|
202
213
|
usernames.map { |u| Gitlab::Dangerfiles::Teammate.new("username" => u) }
|
203
214
|
end
|
204
215
|
|
205
|
-
def
|
206
|
-
|
207
|
-
["database"]
|
208
|
-
else
|
209
|
-
["database", "database::review pending"]
|
210
|
-
end
|
216
|
+
def mr_iid
|
217
|
+
return "" unless gitlab_helper
|
211
218
|
|
212
|
-
|
219
|
+
gitlab_helper.mr_json["iid"]
|
213
220
|
end
|
214
221
|
|
215
|
-
def
|
216
|
-
|
222
|
+
def mr_title
|
223
|
+
return "" unless gitlab_helper
|
224
|
+
|
225
|
+
gitlab_helper.mr_json["title"]
|
217
226
|
end
|
218
227
|
|
219
|
-
def
|
220
|
-
return
|
228
|
+
def mr_web_url
|
229
|
+
return "" unless gitlab_helper
|
230
|
+
|
231
|
+
gitlab_helper.mr_json["web_url"]
|
232
|
+
end
|
233
|
+
|
234
|
+
def mr_labels
|
235
|
+
return [] unless gitlab_helper
|
236
|
+
|
237
|
+
gitlab_helper.mr_labels
|
238
|
+
end
|
239
|
+
|
240
|
+
def mr_target_branch
|
241
|
+
return "" unless gitlab_helper
|
221
242
|
|
222
|
-
gitlab_helper.mr_json["
|
243
|
+
gitlab_helper.mr_json["target_branch"]
|
244
|
+
end
|
245
|
+
|
246
|
+
def draft_mr?
|
247
|
+
Gitlab::Dangerfiles::TitleLinting.has_draft_flag?(mr_title)
|
248
|
+
end
|
249
|
+
|
250
|
+
def security_mr?
|
251
|
+
mr_web_url.include?("/gitlab-org/security/")
|
223
252
|
end
|
224
253
|
|
225
254
|
def cherry_pick_mr?
|
226
|
-
|
255
|
+
Gitlab::Dangerfiles::TitleLinting.has_cherry_pick_flag?(mr_title)
|
256
|
+
end
|
227
257
|
|
228
|
-
|
258
|
+
def run_all_rspec_mr?
|
259
|
+
Gitlab::Dangerfiles::TitleLinting.has_run_all_rspec_flag?(mr_title)
|
229
260
|
end
|
230
261
|
|
231
|
-
def
|
232
|
-
|
262
|
+
def run_as_if_foss_mr?
|
263
|
+
Gitlab::Dangerfiles::TitleLinting.has_run_as_if_foss_flag?(mr_title)
|
264
|
+
end
|
233
265
|
|
234
|
-
|
266
|
+
def stable_branch?
|
267
|
+
/\A\d+-\d+-stable-ee/i.match?(mr_target_branch)
|
235
268
|
end
|
236
269
|
|
237
270
|
def mr_has_labels?(*labels)
|
238
|
-
return false unless gitlab_helper
|
239
|
-
|
240
271
|
labels = labels.flatten.uniq
|
241
|
-
|
272
|
+
|
273
|
+
(labels & mr_labels) == labels
|
242
274
|
end
|
243
275
|
|
244
276
|
def labels_list(labels, sep: ", ")
|
@@ -251,10 +283,20 @@ module Danger
|
|
251
283
|
"/label #{labels_list(labels, sep: " ")}"
|
252
284
|
end
|
253
285
|
|
254
|
-
|
286
|
+
def changed_files(regex)
|
287
|
+
all_changed_files.grep(regex)
|
288
|
+
end
|
255
289
|
|
256
290
|
def has_database_scoped_labels?(current_mr_labels)
|
257
291
|
current_mr_labels.any? { |label| label.start_with?("database::") }
|
258
292
|
end
|
293
|
+
|
294
|
+
def has_ci_changes?
|
295
|
+
changed_files(%r{\A(\.gitlab-ci\.yml|\.gitlab/ci/)}).any?
|
296
|
+
end
|
297
|
+
|
298
|
+
def group_label(labels)
|
299
|
+
labels.find { |label| label.start_with?("group::") }
|
300
|
+
end
|
259
301
|
end
|
260
302
|
end
|
data/lib/danger/roulette.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative "../gitlab/dangerfiles/teammate"
|
4
|
+
require_relative "../gitlab/dangerfiles/weightage/maintainers"
|
5
|
+
require_relative "../gitlab/dangerfiles/weightage/reviewers"
|
4
6
|
|
5
7
|
module Danger
|
6
8
|
# Common helper functions for our danger scripts. See Danger::Helper
|
@@ -9,42 +11,58 @@ module Danger
|
|
9
11
|
ROULETTE_DATA_URL = "https://gitlab-org.gitlab.io/gitlab-roulette/roulette.json"
|
10
12
|
HOURS_WHEN_PERSON_CAN_BE_PICKED = (6..14).freeze
|
11
13
|
|
12
|
-
|
14
|
+
INCLUDE_TIMEZONE_FOR_CATEGORY = {
|
15
|
+
database: false,
|
16
|
+
}.freeze
|
17
|
+
|
18
|
+
Spin = Struct.new(:category, :reviewer, :maintainer, :optional_role, :timezone_experiment)
|
19
|
+
|
20
|
+
def team_mr_author
|
21
|
+
team.find { |person| person.username == mr_author_username }
|
22
|
+
end
|
13
23
|
|
14
24
|
# Assigns GitLab team members to be reviewer and maintainer
|
15
25
|
# for each change category that a Merge Request contains.
|
16
26
|
#
|
17
27
|
# @return [Array<Spin>]
|
18
|
-
def spin(project, categories,
|
19
|
-
|
20
|
-
|
21
|
-
rescue => err
|
22
|
-
warn("Reviewer roulette failed to load team data: #{err.message}")
|
23
|
-
[]
|
24
|
-
end
|
28
|
+
def spin(project, categories, timezone_experiment: false)
|
29
|
+
spins = categories.sort.map do |category|
|
30
|
+
including_timezone = INCLUDE_TIMEZONE_FOR_CATEGORY.fetch(category, timezone_experiment)
|
25
31
|
|
26
|
-
|
27
|
-
|
28
|
-
spin_per_category = categories.each_with_object({}) do |category, memo|
|
29
|
-
memo[category] = spin_for_category(team, project, category, canonical_branch_name, timezone_experiment: timezone_experiment)
|
32
|
+
spin_for_category(project, category, timezone_experiment: including_timezone)
|
30
33
|
end
|
31
34
|
|
32
|
-
|
33
|
-
|
35
|
+
backend_spin = spins.find { |spin| spin.category == :backend }
|
36
|
+
|
37
|
+
spins.each do |spin|
|
38
|
+
including_timezone = INCLUDE_TIMEZONE_FOR_CATEGORY.fetch(spin.category, timezone_experiment)
|
39
|
+
case spin.category
|
40
|
+
when :qa
|
41
|
+
# MR includes QA changes, but also other changes, and author isn't an SET
|
42
|
+
if categories.size > 1 && !team_mr_author&.any_capability?(project, spin.category)
|
43
|
+
spin.optional_role = :maintainer
|
44
|
+
end
|
34
45
|
when :test
|
46
|
+
spin.optional_role = :maintainer
|
47
|
+
|
35
48
|
if spin.reviewer.nil?
|
36
49
|
# Fetch an already picked backend reviewer, or pick one otherwise
|
37
|
-
spin.reviewer =
|
50
|
+
spin.reviewer = backend_spin&.reviewer || spin_for_category(project, :backend, timezone_experiment: including_timezone).reviewer
|
38
51
|
end
|
39
52
|
when :engineering_productivity
|
40
53
|
if spin.maintainer.nil?
|
41
54
|
# Fetch an already picked backend maintainer, or pick one otherwise
|
42
|
-
spin.maintainer =
|
55
|
+
spin.maintainer = backend_spin&.maintainer || spin_for_category(project, :backend, timezone_experiment: including_timezone).maintainer
|
56
|
+
end
|
57
|
+
when :ci_template
|
58
|
+
if spin.maintainer.nil?
|
59
|
+
# Fetch an already picked backend maintainer, or pick one otherwise
|
60
|
+
spin.maintainer = backend_spin&.maintainer || spin_for_category(project, :backend, timezone_experiment: including_timezone).maintainer
|
43
61
|
end
|
44
62
|
end
|
45
|
-
|
46
|
-
spin
|
47
63
|
end
|
64
|
+
|
65
|
+
spins
|
48
66
|
end
|
49
67
|
|
50
68
|
# Looks up the current list of GitLab team members and parses it into a
|
@@ -66,14 +84,9 @@ module Danger
|
|
66
84
|
# @return [Array<Teammate>]
|
67
85
|
def project_team(project_name)
|
68
86
|
team.select { |member| member.in_project?(project_name) }
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
branch_name.gsub(/^[ce]e-|-[ce]e$/, "")
|
73
|
-
end
|
74
|
-
|
75
|
-
def new_random(seed)
|
76
|
-
Random.new(Digest::MD5.hexdigest(seed).to_i(16))
|
87
|
+
rescue => err
|
88
|
+
warn("Reviewer roulette failed to load team data: #{err.message}")
|
89
|
+
[]
|
77
90
|
end
|
78
91
|
|
79
92
|
# Known issue: If someone is rejected due to OOO, and then becomes not OOO, the
|
@@ -106,30 +119,49 @@ module Danger
|
|
106
119
|
# @param [Teammate] person
|
107
120
|
# @return [Boolean]
|
108
121
|
def mr_author?(person)
|
109
|
-
person.username ==
|
122
|
+
person.username == mr_author_username
|
123
|
+
end
|
124
|
+
|
125
|
+
def mr_author_username
|
126
|
+
helper.gitlab_helper&.mr_author || `whoami`
|
127
|
+
end
|
128
|
+
|
129
|
+
def mr_source_branch
|
130
|
+
return `git rev-parse --abbrev-ref HEAD` unless helper.gitlab_helper&.mr_json
|
131
|
+
|
132
|
+
helper.gitlab_helper.mr_json["source_branch"]
|
133
|
+
end
|
134
|
+
|
135
|
+
def mr_labels
|
136
|
+
helper.gitlab_helper&.mr_labels || []
|
137
|
+
end
|
138
|
+
|
139
|
+
def new_random(seed)
|
140
|
+
Random.new(Digest::MD5.hexdigest(seed).to_i(16))
|
110
141
|
end
|
111
142
|
|
112
143
|
def spin_role_for_category(team, role, project, category)
|
113
144
|
team.select do |member|
|
114
|
-
member.public_send("#{role}?", project, category,
|
145
|
+
member.public_send("#{role}?", project, category, mr_labels) # rubocop:disable GitlabSecurity/PublicSend
|
115
146
|
end
|
116
147
|
end
|
117
148
|
|
118
|
-
def spin_for_category(
|
149
|
+
def spin_for_category(project, category, timezone_experiment: false)
|
150
|
+
team = project_team(project)
|
119
151
|
reviewers, traintainers, maintainers =
|
120
152
|
%i[reviewer traintainer maintainer].map do |role|
|
121
153
|
spin_role_for_category(team, role, project, category)
|
122
154
|
end
|
123
155
|
|
124
|
-
|
125
|
-
|
156
|
+
random = new_random(mr_source_branch)
|
157
|
+
|
158
|
+
weighted_reviewers = Gitlab::Dangerfiles::Weightage::Reviewers.new(reviewers, traintainers).execute
|
159
|
+
weighted_maintainers = Gitlab::Dangerfiles::Weightage::Maintainers.new(maintainers).execute
|
126
160
|
|
127
|
-
|
128
|
-
|
129
|
-
reviewer = spin_for_person(reviewers + traintainers + traintainers, random: random, timezone_experiment: timezone_experiment)
|
130
|
-
maintainer = spin_for_person(maintainers, random: random, timezone_experiment: timezone_experiment)
|
161
|
+
reviewer = spin_for_person(weighted_reviewers, random: random, timezone_experiment: timezone_experiment)
|
162
|
+
maintainer = spin_for_person(weighted_maintainers, random: random, timezone_experiment: timezone_experiment)
|
131
163
|
|
132
|
-
Spin.new(category, reviewer, maintainer)
|
164
|
+
Spin.new(category, reviewer, maintainer, false, timezone_experiment)
|
133
165
|
end
|
134
166
|
end
|
135
167
|
end
|