gitlab-dangerfiles 3.6.0 → 3.6.4

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: af0d569b13b09e65dfaed6f7eaf3519e314e510e71279b395eabccdb49901f83
4
- data.tar.gz: 24050d6f8149c4e902d3c98a8b7d89aa8070a0e2445724f0f1733498d824800c
3
+ metadata.gz: 34ff9782c4b20cd3c7dbb4a25d7ecdf66cf49ef303e1deb0bb04074e1c4fca21
4
+ data.tar.gz: b21f8643147b7147fca7e5cba536c67bf98d65f827cb169d72fd2ac5ff3de355
5
5
  SHA512:
6
- metadata.gz: 84d10142bb9fbf7fe03c9b4d6aee7f39cf0e9ff0ca90c167b484f3d5f1f3a13ef7aed7756c2d1b7b2873e896025ac91dc17b40b5c625d3d2cebad95f4114f3d9
7
- data.tar.gz: 87cb02420672c5f9bb171837852733ee9550f30afc918ddb948a1e469224261eda5896ad18993b6aa550cc3d9ec5a782c1d17c278a40d3fc7a316edbf32d63c0
6
+ metadata.gz: 7f9f43daf58a905f330ad98020327073a47692f24c0494d407d7e76aa8b18819b74839772c58b19d9081b04034154a06e8dee588c70898b71db08bab03fa31a9
7
+ data.tar.gz: f30572b11ac8e2d9a4ab9cc35c19000c68ecdaefd72f8e276f18e73da3beeb64b81a44d2e4919977c0aabecafec5d3fa64a25443604c27168865a5acb7c6bf97
data/.rubocop.yml CHANGED
@@ -32,6 +32,9 @@ Style/HashSyntax:
32
32
  Style/StringLiterals:
33
33
  EnforcedStyle: double_quotes
34
34
 
35
+ Style/TrailingCommaInHashLiteral:
36
+ EnforcedStyleForMultiline: consistent_comma
37
+
35
38
  # Was problematic, and not included in the .rubocop_todo.yml
36
39
  GitlabSecurity/PublicSend:
37
40
  Enabled: false
data/README.md CHANGED
@@ -128,8 +128,12 @@ project. To use it in your project, perform the following steps:
128
128
  see how to set it up.
129
129
  1. When using the default roulette, use `import_defaults` or import it manually when setting
130
130
  up the gitlab-dangerfiles instance:
131
+
131
132
  ```ruby
133
+ require 'gitlab-dangerfiles'
134
+
132
135
  Gitlab::Dangerfiles.for_project(self) do |dangerfiles|
136
+ dangerfiles.import_plugins
133
137
  dangerfiles.import_dangerfiles(only: %w[simple_roulette])
134
138
  end
135
139
  ```
@@ -17,6 +17,7 @@ module Danger
17
17
  none: "",
18
18
  qa: "~QA",
19
19
  ux: "~UX",
20
+ codeowners: '~"Code Owners"',
20
21
  test: "~test for `spec/features/*`",
21
22
  # Deprecated as of 2.3.0 in favor of tooling
22
23
  engineering_productivity: '~"Engineering Productivity" for CI, Danger',
@@ -26,6 +27,7 @@ module Danger
26
27
  integrations_be: '~"group::integrations" (backend)',
27
28
  integrations_fe: '~"group::integrations" (frontend)',
28
29
  "Authentication and Authorization": '~"group::authentication and authorization"',
30
+ Compliance: '~"group::compliance"',
29
31
  }.freeze
30
32
 
31
33
  # Allows to set specific rule's configuration by passing a block.
@@ -234,7 +236,13 @@ module Danger
234
236
  # @return [String] the GFM for a category label, making its best guess if it's not
235
237
  # a category we know about.
236
238
  def label_for_category(category)
237
- CATEGORY_LABELS.fetch(category, %Q{~"#{category}"})
239
+ CATEGORY_LABELS[category] ||
240
+
241
+ if category.start_with?("`")
242
+ category.to_s
243
+ else
244
+ %Q{~"#{category}"}
245
+ end
238
246
  end
239
247
 
240
248
  # @return [String] +""+ when not in the CI context, and the MR Source Project ID as a string otherwise.
@@ -20,7 +20,13 @@ module Danger
20
20
 
21
21
  Approval = Struct.new(:category, :spin) do
22
22
  def self.from_approval_rule(rule, maintainer)
23
- category = rule["section"].to_sym
23
+ category =
24
+ if rule["section"] == "codeowners"
25
+ "`#{rule["name"]}`"
26
+ else
27
+ rule["section"]
28
+ end.to_sym
29
+
24
30
  spin = Spin.new(category, nil, maintainer, :reviewer)
25
31
 
26
32
  new(category, spin)
@@ -14,6 +14,7 @@ module Gitlab
14
14
  {
15
15
  subject_too_short: "The %s must contain at least #{MIN_SUBJECT_WORDS_COUNT} words",
16
16
  subject_too_long: "The %s may not be longer than #{MAX_LINE_LENGTH} characters",
17
+ subject_starts_with_a_space: "The %s must not start with a space",
17
18
  subject_starts_with_lowercase: "The %s must start with a capital letter",
18
19
  subject_ends_with_a_period: "The %s must not end with a period",
19
20
  }
@@ -49,6 +50,10 @@ module Gitlab
49
50
  add_problem(:subject_too_long, self.class.subject_description)
50
51
  end
51
52
 
53
+ if subject_starts_with_a_space?
54
+ add_problem(:subject_starts_with_a_space, self.class.subject_description)
55
+ end
56
+
52
57
  if subject_starts_with_lowercase?
53
58
  add_problem(:subject_starts_with_lowercase, self.class.subject_description)
54
59
  end
@@ -78,8 +83,13 @@ module Gitlab
78
83
  line.length > MAX_LINE_LENGTH
79
84
  end
80
85
 
86
+ def subject_starts_with_a_space?
87
+ subject.start_with?(" ")
88
+ end
89
+
81
90
  def subject_starts_with_lowercase?
82
91
  return false if subject.empty?
92
+ return false if subject_starts_with_a_space?
83
93
  return false if ("A".."Z").cover?(subject[0])
84
94
 
85
95
  first_char = subject.sub(/\A(\[[^\]]+\]|[^:\s]+:)\s/, "")[0]
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gitlab
4
+ module Dangerfiles
5
+ CategoryStruct = Struct.new(:name, :project, :kind, :labels, keyword_init: true)
6
+
7
+ class Category < CategoryStruct
8
+ def self.for(name, **arguments)
9
+ (name_to_class[name] || self).new(name: name, **arguments)
10
+ end
11
+
12
+ def self.name_to_class
13
+ @name_to_class ||= {
14
+ test: Test,
15
+ tooling: Tooling,
16
+ integrations_be: IntegrationsBE,
17
+ integrations_fe: IntegrationsFE,
18
+ ux: UX,
19
+ }.freeze
20
+ end
21
+ private_class_method :name_to_class
22
+
23
+ def has_capability?(...)
24
+ has_particular_capability?(...) || has_universal_capability?(...)
25
+ end
26
+
27
+ private
28
+
29
+ def has_particular_capability?(teammate)
30
+ teammate.capabilities(project).include?(capability)
31
+ end
32
+
33
+ def has_universal_capability?(teammate)
34
+ false
35
+ end
36
+
37
+ def capability
38
+ # name can be nil
39
+ @capability ||= "#{kind} #{name}".strip
40
+ end
41
+
42
+ class Test < Category
43
+ private
44
+
45
+ def has_particular_capability?(teammate)
46
+ return false if kind != :reviewer
47
+
48
+ area = teammate.role[/Software Engineer in Test(?:.*?, (\w+))/, 1]
49
+
50
+ area && labels.any?("devops::#{area.downcase}")
51
+ end
52
+ end
53
+
54
+ class Tooling < Category
55
+ private
56
+
57
+ def has_particular_capability?(teammate)
58
+ if super
59
+ true
60
+ elsif %i[trainee_maintainer maintainer].include?(kind)
61
+ false
62
+ else # fallback to backend reviewer
63
+ teammate.capabilities(project).include?("#{kind} backend")
64
+ end
65
+ end
66
+ end
67
+
68
+ class IntegrationsBE < Category
69
+ private
70
+
71
+ def has_particular_capability?(teammate)
72
+ kind == :reviewer &&
73
+ teammate.role.match?(/Backend Engineer.+Manage:Integrations/)
74
+ end
75
+ end
76
+
77
+ class IntegrationsFE < Category
78
+ private
79
+
80
+ def has_particular_capability?(teammate)
81
+ kind == :reviewer &&
82
+ teammate.role.match?(/Frontend Engineer.+Manage:Integrations/)
83
+ end
84
+ end
85
+
86
+ class UX < Category
87
+ private
88
+
89
+ def has_universal_capability?(teammate)
90
+ teammate.projects.each_value.find do |capabilities|
91
+ capabilities.include?(capability)
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -1,9 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "category"
4
+
3
5
  module Gitlab
4
6
  module Dangerfiles
5
7
  class Teammate
6
- attr_reader :options, :username, :name, :role, :projects, :available, :hungry, :reduced_capacity, :tz_offset_hours
8
+ attr_reader :options, :username, :name, :role, :projects, :available, :hungry, :reduced_capacity, :tz_offset_hours,
9
+ :only_maintainer_reviews
7
10
 
8
11
  # The options data are produced by https://gitlab.com/gitlab-org/gitlab-roulette/-/blob/master/lib/team_member.rb
9
12
  def initialize(options = {})
@@ -18,6 +21,7 @@ module Gitlab
18
21
  @hungry = options["hungry"]
19
22
  @reduced_capacity = options["reduced_capacity"]
20
23
  @tz_offset_hours = options["tz_offset_hours"]
24
+ @only_maintainer_reviews = options["only_maintainer_reviews"]
21
25
  end
22
26
 
23
27
  def to_h
@@ -74,6 +78,10 @@ module Gitlab
74
78
  (Time.now.utc + tz_offset_hours * 3600).hour
75
79
  end
76
80
 
81
+ def capabilities(project)
82
+ projects.fetch(project, [])
83
+ end
84
+
77
85
  protected
78
86
 
79
87
  def floored_offset_hours
@@ -123,42 +131,7 @@ module Gitlab
123
131
  end
124
132
 
125
133
  def has_capability?(project, category, kind, labels)
126
- case category
127
- when :test
128
- area = role[/Software Engineer in Test(?:.*?, (\w+))/, 1]
129
-
130
- area && labels.any?("devops::#{area.downcase}") if kind == :reviewer
131
- when :tooling, :engineering_productivity # Deprecated as of 2.3.0 in favor of tooling
132
- return true if capabilities(project).include?("#{kind} #{category}")
133
- return false if %i[trainee_maintainer maintainer].include?(kind)
134
-
135
- capabilities(project).include?("#{kind} backend") # fallback to backend reviewer
136
- when :integrations_be
137
- kind == :reviewer &&
138
- role.match?(/Backend Engineer.+Ecosystem:Integrations/)
139
- when :integrations_fe
140
- kind == :reviewer &&
141
- role.match?(/Frontend Engineer.+Ecosystem:Integrations/)
142
- when nil
143
- capabilities(project).include?("#{kind}")
144
- else
145
- capabilities(project).include?("#{kind} #{category}")
146
- end || has_universal_capability?(category, kind, labels)
147
- end
148
-
149
- def has_universal_capability?(category, kind, labels)
150
- case category
151
- when :ux
152
- capacity = "#{kind} #{category}"
153
-
154
- projects.each_value.find do |capabilities|
155
- capabilities.include?(capacity)
156
- end
157
- end
158
- end
159
-
160
- def capabilities(project)
161
- projects.fetch(project, [])
134
+ Category.for(category, project: project, kind: kind, labels: labels).has_capability?(self)
162
135
  end
163
136
 
164
137
  def pluralize(count, singular, plural)
@@ -1,5 +1,5 @@
1
1
  module Gitlab
2
2
  module Dangerfiles
3
- VERSION = "3.6.0"
3
+ VERSION = "3.6.4"
4
4
  end
5
5
  end
@@ -33,6 +33,7 @@ module Gitlab
33
33
  # https://gitlab.com/gitlab-org/gitlab/issues/26723
34
34
 
35
35
  remove_traintainers_from_reviewers!
36
+ remove_maintainer_only_from_reviewers!
36
37
 
37
38
  weighted_reviewers + weighted_traintainers
38
39
  end
@@ -49,6 +50,11 @@ module Gitlab
49
50
  reviewers.reject! { |reviewer| traintainers.include?(reviewer) }
50
51
  end
51
52
 
53
+ def remove_maintainer_only_from_reviewers!
54
+ # Using a maintainer-only reviewer emoji, team members can ensure they only get maintainer reviews
55
+ reviewers.reject! { |reviewer| reviewer&.only_maintainer_reviews }
56
+ end
57
+
52
58
  def weighted_reviewers
53
59
  reviewers.each_with_object([]) do |reviewer, total_reviewers|
54
60
  add_weighted_reviewer(total_reviewers, reviewer, DEFAULT_REVIEWER_WEIGHT)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitlab-dangerfiles
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.6.0
4
+ version: 3.6.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitLab
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-10-17 00:00:00.000000000 Z
11
+ date: 2022-12-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -183,6 +183,7 @@ files:
183
183
  - lib/gitlab/Dangerfile
184
184
  - lib/gitlab/dangerfiles.rb
185
185
  - lib/gitlab/dangerfiles/base_linter.rb
186
+ - lib/gitlab/dangerfiles/category.rb
186
187
  - lib/gitlab/dangerfiles/changes.rb
187
188
  - lib/gitlab/dangerfiles/commit_linter.rb
188
189
  - lib/gitlab/dangerfiles/config.rb