gitlab-dangerfiles 4.12.0 → 4.14.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: 053ccbe5f18fd65ff059c590e4de66d82b8632aa368453f48e5be40bba809e47
4
- data.tar.gz: 104c829cb3c5e1113fb890885abdac06e413d7076b45f26ee406b3d6d38f1fed
3
+ metadata.gz: e62a200646d128a780ee1e17bb644f5fe296fef2f530631ebdabe677a2eea93f
4
+ data.tar.gz: 73aec620889b66c1c7f61fe845ab2b43c528c21301ed7b1bb4a8b6ad6e93656b
5
5
  SHA512:
6
- metadata.gz: 1b0098a095fb630bb6301e2ad78c8d0709b4fdab22de3fb929a306954dd87026f4111e48f17d19d94fc7d62906f9ac413e0879d91df47c976622854b3dd63dca
7
- data.tar.gz: 44009f0ea1dc871c36608df7ee2d3d3a28f7c92692573c54781b8fecc36e37965fed1d972004cfef2539904f07820eabf84c06bea8216b12264e36d6732a3951
6
+ metadata.gz: cfaa1d404d59cb656354135dd146d6ea908046f51430fd5d4f7d9aa83f13446bed69f7dc21b018a8f9e6154b6a65b5abf0a3fc90c6863986702b2b64403ffa81
7
+ data.tar.gz: 6300e9593543c6f635ced6fb6b1c9d04773bf1baac66d0dbc7bb2957607196f094d2a429e2372c64dcdbc31b331047e40ac387e2b99bd7b2777d52956c3e6b25
data/.gitlab/CODEOWNERS CHANGED
@@ -1 +1 @@
1
- * @gl-dx/eng-prod
1
+ * @gl-dx
data/CONTRIBUTING.md CHANGED
@@ -6,7 +6,7 @@ Except for the license granted herein to GitLab B.V. and recipients of software
6
6
  distributed by GitLab B.V., you reserve all right, title, and interest in and to
7
7
  your Contributions.
8
8
 
9
- All contributions are subject to the Developer Certificate of Origin and license set out at [docs.gitlab.com/ce/legal/developer_certificate_of_origin](https://docs.gitlab.com/ce/legal/developer_certificate_of_origin).
9
+ All contributions are subject to the Developer Certificate of Origin and license set out at [docs.gitlab.com/legal/developer_certificate_of_origin](https://docs.gitlab.com/legal/developer_certificate_of_origin/).
10
10
 
11
11
  _This notice should stay as the first item in the CONTRIBUTING.md file._
12
12
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gitlab-dangerfiles (4.12.0)
4
+ gitlab-dangerfiles (4.14.0)
5
5
  danger (>= 9.3.0)
6
6
  danger-gitlab (>= 8.0.0)
7
7
  rake (~> 13.0)
data/README.md CHANGED
@@ -148,7 +148,7 @@ Danger rules are located under `lib/danger/rules`.
148
148
 
149
149
  #### `changelog`
150
150
 
151
- This rule ensures the merge request follows our [Changelog guidelines](https://docs.gitlab.com/ee/development/changelog.html#changelog-entries).
151
+ This rule ensures the merge request follows our [Changelog guidelines](https://docs.gitlab.com/development/changelog/).
152
152
 
153
153
  #### `changes_size`
154
154
 
@@ -169,16 +169,10 @@ This rule ensures the merge request isn't too big to be reviewed, otherwise it s
169
169
 
170
170
  #### `commits_counter`
171
171
 
172
- This rule posts a failure if the merge request has more than 20 commits.
172
+ This rule posts a warning if the merge request has more than 20 commits.
173
173
 
174
- #### `danger_code_review`
175
-
176
- This rule posts a warning/failure when `@GitLabDuo` isn't assigned as a reviewer.
177
-
178
- ##### Available configurations
179
-
180
- - `duo_code_review`: Whether a review from GitLab Duo Code is `:mandatory` or `:optional`.
181
- Default to `:optional`.
174
+ For merge requests in [`gitlab-org/gitlab`](https://gitlab.com/gitlab-org/gitlab), it posts a failure
175
+ instead, unless the merge request is set to squash commits.
182
176
 
183
177
  #### `metadata`
184
178
 
@@ -225,6 +219,32 @@ helper.config.auto_assign_for_roulette_roles = [:reviewer]
225
219
  helper.config.auto_assign_for_roulette_labels = ["maintenance::dependency"]
226
220
  ```
227
221
 
222
+ ##### CODEOWNERS boost
223
+
224
+ By default, the roulette selects reviewers and maintainers purely based on category membership and
225
+ capacity weights. You can optionally give CODEOWNERS-eligible approvers additional weight in the
226
+ selection pool, making them more likely to be picked without hard-gating on them.
227
+
228
+ Configure `codeowners_reviewer_boost_for_roulette` and/or `codeowners_maintainer_boost_for_roulette`
229
+ with a positive integer to add that many extra entries in the weighted pool for matching reviewers
230
+ or maintainers. The boost stacks on top of existing capacity, hungry, and traintainer weights.
231
+
232
+ ```ruby
233
+ # Prefer code owners for review, but not for maintainer approval
234
+ helper.config.codeowners_reviewer_boost_for_roulette = 3
235
+
236
+ # Prefer code owners for both review and maintainer approval
237
+ helper.config.codeowners_reviewer_boost_for_roulette = 3
238
+ helper.config.codeowners_maintainer_boost_for_roulette = 2
239
+ ```
240
+
241
+ | Value | Behavior |
242
+ |-------|----------|
243
+ | `0` (default) | No change — existing behavior preserved |
244
+ | `1-2` | Mild preference for code owners |
245
+ | `3` | Recommended — meaningful preference without starving non-owners |
246
+ | `4+` | Strong preference — use with caution on small teams |
247
+
228
248
  ##### Available configurations
229
249
 
230
250
  Note: These options aren't actually used in the `simple_roulette` rule, but can be used in your own
@@ -253,17 +273,15 @@ In order to run `danger` on GitLab CI, perform the following steps:
253
273
 
254
274
  1. If not yet done, create a `Dangerfile` at the top-level of your project. Refer to [Usage](#usage) to
255
275
  see how to set it up.
256
- 2. In `.gitlab-ci.yml`, include [CI configuration](https://gitlab.com/gitlab-org/quality/pipeline-common/-/blob/master/ci/danger-review.yml)
257
- which defines `danger-review` [CI job](https://docs.gitlab.com/ee/ci/jobs/):
276
+ 2. In `.gitlab-ci.yml`, include the [`danger-review` CI/CD component](https://gitlab.com/gitlab-org/components/danger-review)
277
+ which defines the `danger-review` [CI job](https://docs.gitlab.com/ee/ci/jobs/):
258
278
 
259
279
  ```yaml
260
280
  include:
261
- - project: 'gitlab-org/quality/pipeline-common'
262
- file:
263
- - '/ci/danger-review.yml'
281
+ - component: gitlab.com/gitlab-org/components/danger-review/danger-review@~latest
264
282
  ```
265
283
 
266
- 3. Create a [Project or group access token](https://docs.gitlab.com/ee/user/project/settings/project_access_tokens.html)
284
+ 3. Create a [Project or group access token](https://docs.gitlab.com/user/project/settings/project_access_tokens/)
267
285
  with scope `api` and role `Developer`.
268
286
  4. Add a [CI/CD variable](https://docs.gitlab.com/ee/ci/variables/#add-a-cicd-variable-to-a-project)
269
287
  `DANGER_GITLAB_API_TOKEN` (`Masked` but not `Protected`) and use Project access token as value.
@@ -274,25 +292,20 @@ See a [real world example](https://gitlab.com/gitlab-org/ruby/gems/gitlab-styles
274
292
 
275
293
  Danger is a Ruby project and uses [`bundler`](https://bundler.io/) to manage
276
294
  its dependencies. This requires a project to have a `Gemfile` and
277
- `Gemfile.lock` commited. This is helpful especially if Danger is also used
295
+ `Gemfile.lock` committed. This is helpful especially if Danger is also used
278
296
  locally - with `lefthook`, for example.
279
297
 
280
- In order to skip Ruby and `bundler` dependency in a project, use `bundle` commands directly
281
- in the CI configuration:
298
+ You don't need a `Gemfile` to use the `danger-review` component. If your project
299
+ has no `Gemfile`, the component creates one and adds the latest `gitlab-dangerfiles`
300
+ to it before it runs Danger.
301
+
302
+ To pin the `gitlab-dangerfiles` version instead, set the `gitlab_dangerfiles_version` input:
282
303
 
283
304
  ```yaml
284
305
  include:
285
- - project: 'gitlab-org/quality/pipeline-common'
286
- file: '/ci/danger-review.yml'
287
-
288
- danger-review:
289
- before_script:
290
- - bundle init
291
- # For latest version
292
- - bundle add gitlab-dangerfiles
293
- # OR
294
- # For a pinned version
295
- - bundle add gitlab-dangerfiles --version 3.1.0
306
+ - component: gitlab.com/gitlab-org/components/danger-review/danger-review@~latest
307
+ inputs:
308
+ gitlab_dangerfiles_version: "4.12.0"
296
309
  ```
297
310
 
298
311
  ## Local Danger Rake task
@@ -330,7 +343,7 @@ The following lint violations generate warnings:
330
343
  1. The commit changes too many lines across too many files without describing the changes in the commit body ([code](https://gitlab.com/gitlab-org/ruby/gems/gitlab-dangerfiles/blob/bccb167/lib/gitlab/dangerfiles/commit_linter.rb#L83-85)).
331
344
  1. The commit body contains too many characters per line ([code](https://gitlab.com/gitlab-org/ruby/gems/gitlab-dangerfiles/blob/bccb167/lib/gitlab/dangerfiles/commit_linter.rb#L87-96)).
332
345
 
333
- All other lint violations generate errors, except when the MR has [Squash commits when merge request is accepted](https://docs.gitlab.com/ee/user/project/merge_requests/squash_and_merge.html#squash-commits-in-a-merge-request) enabled, which downgrades lint violations to warnings.
346
+ All other lint violations generate errors, except when the MR has [Squash commits when merge request is accepted](https://docs.gitlab.com/user/project/merge_requests/squash_and_merge/#squash-commits-in-a-merge-request) enabled, which downgrades lint violations to warnings.
334
347
 
335
348
  ## Documentation
336
349
 
@@ -368,9 +381,9 @@ See an [example](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/92580) fo
368
381
 
369
382
  ## Contributing
370
383
 
371
- Bug reports and merge requests are welcome at https://gitlab.com/gitlab-org/gitlab-dangerfiles. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://gitlab.com/gitlab-org/gitlab-dangerfiles/blob/master/CODE_OF_CONDUCT.md).
384
+ Bug reports and merge requests are welcome at https://gitlab.com/gitlab-org/ruby/gems/gitlab-dangerfiles. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://gitlab.com/gitlab-org/ruby/gems/gitlab-dangerfiles/blob/master/CODE_OF_CONDUCT.md).
372
385
 
373
- Make sure to include a changelog entry in your commit message and read the [changelog entries section](https://docs.gitlab.com/ee/development/changelog.html).
386
+ Make sure to include a changelog entry in your commit message and read the [changelog entries section](https://docs.gitlab.com/development/changelog/).
374
387
 
375
388
  ## Release
376
389
 
@@ -402,4 +415,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
402
415
 
403
416
  ## Code of Conduct
404
417
 
405
- Everyone interacting in the Gitlab::Danger project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://gitlab.com/gitlab-org/gitlab-dangerfiles/blob/master/CODE_OF_CONDUCT.md).
418
+ Everyone interacting in the Gitlab::Danger project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://gitlab.com/gitlab-org/ruby/gems/gitlab-dangerfiles/blob/master/CODE_OF_CONDUCT.md).
data/lefthook.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  # Lefthook configuration. For more information, see:
2
- # https://github.com/Arkweid/lefthook/blob/master/docs/full_guide.md
2
+ # https://lefthook.dev/configuration/
3
3
 
4
4
  pre-push:
5
5
  commands:
@@ -13,34 +13,34 @@ module Danger
13
13
  NO_CHANGELOG_CATEGORIES = %i[docs none].freeze
14
14
  CHANGELOG_TRAILER_REGEX = /^(?<name>Changelog):\s*(?<category>.+)$/i.freeze
15
15
  CHANGELOG_EE_TRAILER_REGEX = /^EE: true$/.freeze
16
- CHANGELOG_MODIFIED_URL_TEXT = "**CHANGELOG.md was edited.** Please remove the additions and follow the [changelog guidelines](https://docs.gitlab.com/ee/development/changelog.html).\n\n"
17
- CHANGELOG_MISSING_URL_TEXT = "**[CHANGELOG missing](https://docs.gitlab.com/ee/development/changelog.html)**:\n\n"
16
+ CHANGELOG_MODIFIED_URL_TEXT = "**CHANGELOG.md was edited.** Please remove the additions and follow the [changelog guidelines](https://docs.gitlab.com/development/changelog/).\n\n"
17
+ CHANGELOG_MISSING_URL_TEXT = "**[CHANGELOG missing](https://docs.gitlab.com/development/changelog/)**:\n\n"
18
18
  IF_REVERT_MR_TEXT = <<~MARKDOWN
19
- In a revert merge request? Use the revert merge request template to add labels [that skip changelog checks](https://docs.gitlab.com/ee/development/pipelines#revert-mrs).
19
+ In a revert merge request? Use the revert merge request template to add labels [that skip changelog checks](https://docs.gitlab.com/development/pipelines/#revert-mrs).
20
20
 
21
21
  Reverting something in the current milestone? A changelog isn't required. Skip changelog checks by adding `~"regression:*"` label, then re-run the danger job (there is a link at the bottom of this comment).
22
22
  MARKDOWN
23
23
 
24
24
  OPTIONAL_CHANGELOG_MESSAGE = {
25
- local: "If this merge request [doesn't need a CHANGELOG entry](https://docs.gitlab.com/ee/development/changelog.html#what-warrants-a-changelog-entry), feel free to ignore this message.",
25
+ local: "If this merge request [doesn't need a CHANGELOG entry](https://docs.gitlab.com/development/changelog/#what-warrants-a-changelog-entry), feel free to ignore this message.",
26
26
  ci: <<~MSG
27
27
  If this merge request needs a changelog entry, add the `Changelog` trailer to the commit message you want to add to the changelog.
28
28
 
29
- If this merge request [doesn't need a CHANGELOG entry](https://docs.gitlab.com/ee/development/changelog.html#what-warrants-a-changelog-entry), feel free to ignore this message.
29
+ If this merge request [doesn't need a CHANGELOG entry](https://docs.gitlab.com/development/changelog/#what-warrants-a-changelog-entry), feel free to ignore this message.
30
30
  MSG
31
31
  }.freeze
32
- SEE_DOC = "See the [changelog documentation](https://docs.gitlab.com/ee/development/changelog.html)."
32
+ SEE_DOC = "See the [changelog documentation](https://docs.gitlab.com/development/changelog/)."
33
33
 
34
34
  REQUIRED_CHANGELOG_REASONS = {
35
35
  db_changes: "introduces a database migration",
36
36
  feature_flag_removed: "removes a feature flag"
37
37
  }.freeze
38
38
  REQUIRED_CHANGELOG_MESSAGE = {
39
- local: "This merge request requires a changelog entry because it [%<reason>s](https://docs.gitlab.com/ee/development/changelog.html#what-warrants-a-changelog-entry).",
39
+ local: "This merge request requires a changelog entry because it [%<reason>s](https://docs.gitlab.com/development/changelog/#what-warrants-a-changelog-entry).",
40
40
  ci: <<~MSG
41
41
  To create a changelog entry, add the `Changelog` trailer to one of your Git commit messages.
42
42
 
43
- This merge request requires a changelog entry because it [%<reason>s](https://docs.gitlab.com/ee/development/changelog.html#what-warrants-a-changelog-entry).
43
+ This merge request requires a changelog entry because it [%<reason>s](https://docs.gitlab.com/development/changelog/#what-warrants-a-changelog-entry).
44
44
  MSG
45
45
  }.freeze
46
46
  DEFAULT_CHANGELOG_CATEGORIES = %w[
@@ -191,15 +191,15 @@ module Danger
191
191
  ee_changes = helper.changed_files(%r{\Aee/})
192
192
 
193
193
  if ee_changes.any? && !ee_changelog? && !required?
194
- check_result.warning("This MR changes code in `ee/`, but its Changelog commit is missing the [`EE: true` trailer](https://docs.gitlab.com/ee/development/changelog.html#gitlab-enterprise-changes). Consider adding it to your Changelog commits.")
194
+ check_result.warning("This MR changes code in `ee/`, but its Changelog commit is missing the [`EE: true` trailer](https://docs.gitlab.com/development/changelog/#gitlab-enterprise-changes). Consider adding it to your Changelog commits.")
195
195
  end
196
196
 
197
197
  if ee_changes.empty? && ee_changelog?
198
198
  check_result.warning("This MR has a Changelog commit for EE, but no code changes in `ee/`. Consider removing the `EE: true` trailer from your commits.")
199
199
  end
200
200
 
201
- if ee_changes.any? && ee_changelog? && required_reasons.include?(:db_changes)
202
- check_result.warning("This MR has a Changelog commit with the `EE: true` trailer, but there are database changes which [requires](https://docs.gitlab.com/ee/development/changelog.html#what-warrants-a-changelog-entry) the Changelog commit to not have the `EE: true` trailer. Consider removing the `EE: true` trailer from your commits.")
201
+ if ee_changes.any? && ee_changelog? && required_reasons.include?(:db_changes) && non_ee_database_migration_changes?
202
+ check_result.warning("This MR has a Changelog commit with the `EE: true` trailer, but there are database changes which [requires](https://docs.gitlab.com/development/changelog/#what-warrants-a-changelog-entry) the Changelog commit to not have the `EE: true` trailer. Consider removing the `EE: true` trailer from your commits.")
203
203
  end
204
204
 
205
205
  check_result
@@ -216,6 +216,12 @@ module Danger
216
216
  required_reasons.any?
217
217
  end
218
218
 
219
+ def non_ee_database_migration_changes?
220
+ helper.changes.added.by_category(:migration).any? do |change|
221
+ !change.file.start_with?("ee/db/")
222
+ end
223
+ end
224
+
219
225
  def optional?
220
226
  categories_need_changelog? && mr_without_no_changelog_label?
221
227
  end
@@ -7,7 +7,7 @@ module Danger
7
7
  # Common helper functions for our danger scripts. See Danger::Helper
8
8
  # for more details
9
9
  class CommitMessages < Danger::Plugin
10
- COMMIT_MSG_DOC = "https://docs.gitlab.com/ee/development/contributing/merge_request_workflow.html#commit-messages-guidelines"
10
+ COMMIT_MSG_DOC = "https://docs.gitlab.com/development/contributing/merge_request_workflow/#commit-messages-guidelines"
11
11
  MORE_INFO = "For more information, take a look at our [Commit message guidelines](#{COMMIT_MSG_DOC}).".freeze
12
12
  THE_DANGER_JOB_TEXT = "the `%<job_name>s` job"
13
13
  MAX_COMMITS_COUNT_EXCEEDED_MESSAGE = <<~MSG
@@ -102,7 +102,10 @@ module Danger
102
102
  commit_linters = commits.map { |commit| lint_commit(commit) }
103
103
 
104
104
  if helper.squash_mr?
105
- multi_line_commit_linter = commit_linters.detect do |commit_linter|
105
+ # `commits` (and therefore `commit_linters`) is ordered newest-to-oldest, matching `git log`.
106
+ # We want the oldest multi-line, non-merge commit, since that's the commit whose message is
107
+ # expected to survive the squash, so we search in reverse order.
108
+ multi_line_commit_linter = commit_linters.reverse.detect do |commit_linter|
106
109
  !commit_linter.merge? && commit_linter.multi_line?
107
110
  end
108
111
 
@@ -53,12 +53,19 @@ module Danger
53
53
  project = (project || config_project_name).downcase
54
54
  categories = categories.map { |category| category&.downcase || :none }
55
55
 
56
+ reviewer_boost = helper.config.codeowners_reviewer_boost_for_roulette
57
+ maintainer_boost = helper.config.codeowners_maintainer_boost_for_roulette
58
+ co_usernames = reviewer_boost > 0 || maintainer_boost > 0 ? codeowners_eligible_usernames : Set.new
59
+
56
60
  Gitlab::Dangerfiles::Spinner.new(
57
61
  project: project,
58
62
  author: helper.mr_author, team_author: team_mr_author,
59
63
  labels: labels, categories: categories, random: random,
60
64
  ux_fallback_wider_community_reviewer:
61
- ux_fallback_wider_community_reviewer)
65
+ ux_fallback_wider_community_reviewer,
66
+ codeowners_usernames: co_usernames,
67
+ codeowners_reviewer_boost: reviewer_boost,
68
+ codeowners_maintainer_boost: maintainer_boost)
62
69
  .spin
63
70
  end
64
71
 
@@ -120,10 +127,25 @@ module Danger
120
127
  private
121
128
 
122
129
  def ux_fallback_reviewer
123
- teammates = %w[pedroms annabeldunstone seggenberger jmiocene clavimoniere]
130
+ teammates = %w[pedroms seggenberger clavimoniere]
124
131
  Gitlab::Dangerfiles::Teammate.find_member(teammates.sample)
125
132
  end
126
133
 
134
+ # Collect all CODEOWNERS-eligible approver usernames across qualifying approval rules.
135
+ #
136
+ # @return [Set<String>]
137
+ def codeowners_eligible_usernames
138
+ approval_rules = helper.mr_approval_state["rules"]
139
+
140
+ return Set.new unless approval_rules
141
+
142
+ unique_approval_rules(approval_rules).each_with_object(Set.new) do |rule, usernames|
143
+ next unless spin_for_approval_rule?(rule)
144
+
145
+ rule["eligible_approvers"].each { |approver| usernames << approver["username"] }
146
+ end
147
+ end
148
+
127
149
  def spin_for_approval_rule?(rule)
128
150
  rule["rule_type"] == "code_owner" &&
129
151
  should_include_codeowners_rule?(rule) &&
@@ -7,6 +7,7 @@ module Gitlab
7
7
  class BaseLinter
8
8
  MIN_SUBJECT_WORDS_COUNT = 3
9
9
  MAX_LINE_LENGTH = 72
10
+ PREFIX_REGEX = /\A(\[[^\]]+\]|[^:\s]+:)\s/
10
11
 
11
12
  attr_reader :commit, :problems
12
13
 
@@ -92,11 +93,17 @@ module Gitlab
92
93
  return false if subject_starts_with_a_space?
93
94
  return false if ("A".."Z").cover?(subject[0])
94
95
 
95
- first_char = subject.sub(/\A(\[[^\]]+\]|[^:\s]+:)\s/, "")[0]
96
- first_char_downcased = first_char.downcase
97
- return true unless ("a".."z").cover?(first_char_downcased)
96
+ if PREFIX_REGEX.match?(subject)
97
+ first_char = subject.sub(PREFIX_REGEX, "")[0]
98
+ return true if first_char.nil?
98
99
 
99
- first_char.downcase == first_char
100
+ first_char_downcased = first_char.downcase
101
+ return true unless ("a".."z").cover?(first_char_downcased)
102
+
103
+ false
104
+ else
105
+ true
106
+ end
100
107
  end
101
108
 
102
109
  def subject_ends_with_a_period?
@@ -13,7 +13,6 @@ module Gitlab
13
13
  def self.category_to_class
14
14
  @category_to_class ||= {
15
15
  none: None,
16
- test: Test,
17
16
  tooling: Tooling,
18
17
  ux: UX
19
18
  }.freeze
@@ -36,16 +35,6 @@ module Gitlab
36
35
  end
37
36
  end
38
37
 
39
- class Test < Capability
40
- def has_capability?(teammate)
41
- return false if kind != :reviewer
42
-
43
- area = teammate.role[/Software Engineer in Test(?:.*?, (\w+))/, 1]
44
-
45
- !!area && labels.any?("devops::#{area.downcase}")
46
- end
47
- end
48
-
49
38
  class Tooling < Capability
50
39
  def has_capability?(teammate)
51
40
  if super
@@ -46,7 +46,7 @@ module Gitlab
46
46
  end
47
47
 
48
48
  def merge?
49
- commit.message.start_with?("Merge branch")
49
+ commit.message.start_with?("Merge branch", "Merge remote-tracking branch")
50
50
  end
51
51
 
52
52
  def revert?
@@ -40,11 +40,6 @@ module Gitlab
40
40
  # @return [Integer] the maximum number of allowed non-squashed/non-fixup commits for a given MR. A warning is triggered if the MR has more commits.
41
41
  attr_accessor :max_commits_count
42
42
 
43
- # Rule: duo_code_review
44
- # @!attribute duo_code_review
45
- # @return [Symbol] whether a review from GitLab Duo Code is `:mandatory` or `:optional`. Default to `:optional`.
46
- attr_accessor :duo_code_review
47
-
48
43
  # Rule: simple_roulette
49
44
  # @!attribute included_optional_codeowners_sections_for_roulette
50
45
  # @return [Array] indicating which optional codeowners sections should be included in roulette. Default to `[]`.
@@ -55,6 +50,16 @@ module Gitlab
55
50
  # @return [Array] indicating which required codeowners sections should be excluded from roulette. Default to `[]`.
56
51
  attr_accessor :excluded_required_codeowners_sections_for_roulette
57
52
 
53
+ # Rule: simple_roulette
54
+ # @!attribute codeowners_reviewer_boost_for_roulette
55
+ # @return [Integer] extra weight given to reviewers who are CODEOWNERS-eligible approvers for the current merge request. Set to 0 to disable. Default to `0`.
56
+ attr_accessor :codeowners_reviewer_boost_for_roulette
57
+
58
+ # Rule: simple_roulette
59
+ # @!attribute codeowners_maintainer_boost_for_roulette
60
+ # @return [Integer] extra weight given to maintainers who are CODEOWNERS-eligible approvers for the current merge request. Set to 0 to disable. Default to `0`.
61
+ attr_accessor :codeowners_maintainer_boost_for_roulette
62
+
58
63
  # @!attribute auto_assign_for_roulette_roles
59
64
  # @return [Array<Symbol>] which roles to auto assign as reviewers, given roulette recommendations (:reviewer, :maintainer, or both). If empty, auto-assignment is disabled. Default to `[]`.
60
65
  attr_accessor :auto_assign_for_roulette_roles
@@ -77,9 +82,10 @@ module Gitlab
77
82
  @disabled_roulette_categories = []
78
83
  @included_optional_codeowners_sections_for_roulette = []
79
84
  @excluded_required_codeowners_sections_for_roulette = []
85
+ @codeowners_reviewer_boost_for_roulette = 0
86
+ @codeowners_maintainer_boost_for_roulette = 0
80
87
  @auto_assign_for_roulette_roles = []
81
88
  @auto_assign_for_roulette_labels = []
82
- @duo_code_review = :optional
83
89
  end
84
90
  end
85
91
  end
@@ -154,17 +154,6 @@ RSpec.shared_context "with teammates" do
154
154
  )
155
155
  end
156
156
 
157
- let(:software_engineer_in_test) do
158
- Gitlab::Dangerfiles::Teammate.new(
159
- "username" => "software-engineer-in-test",
160
- "name" => "Software Engineer in Test",
161
- "role" => "Software Engineer in Test, Create:Source Code",
162
- "projects" => { "gitlab" => "maintainer qa", "gitlab-qa" => "maintainer" },
163
- "available" => true,
164
- "tz_offset_hours" => 2.0
165
- )
166
- end
167
-
168
157
  let(:tooling_reviewer) do
169
158
  Gitlab::Dangerfiles::Teammate.new(
170
159
  "username" => "eng-prod-reviewer",
@@ -227,7 +216,6 @@ RSpec.shared_context "with teammates" do
227
216
  frontend_maintainer.to_h,
228
217
  frontend_reviewer.to_h,
229
218
  ux_reviewer.to_h,
230
- software_engineer_in_test.to_h,
231
219
  tooling_reviewer.to_h,
232
220
  ci_template_reviewer.to_h,
233
221
  workhorse_reviewer.to_h,
@@ -10,9 +10,14 @@ module Gitlab
10
10
  class Spinner
11
11
  attr_reader :project, :author, :team_author, :labels, :categories
12
12
 
13
- def initialize(
13
+ # @param codeowners_usernames [Set<String>] usernames of CODEOWNERS-eligible approvers for the MR
14
+ # @param codeowners_reviewer_boost [Integer] extra weight entries for CODEOWNERS-eligible reviewers
15
+ # @param codeowners_maintainer_boost [Integer] extra weight entries for CODEOWNERS-eligible maintainers
16
+ def initialize( # rubocop:disable Metrics/ParameterLists -- CODEOWNERS boost params extend the existing signature
14
17
  project:, author:, team_author: nil, labels: [], categories: [],
15
- random: Random.new, ux_fallback_wider_community_reviewer: nil)
18
+ random: Random.new, ux_fallback_wider_community_reviewer: nil,
19
+ codeowners_usernames: Set.new, codeowners_reviewer_boost: 0,
20
+ codeowners_maintainer_boost: 0)
16
21
  @project = project
17
22
  @author = author
18
23
  @team_author = team_author
@@ -20,9 +25,12 @@ module Gitlab
20
25
  @categories = categories
21
26
  @random = random
22
27
  @ux_fallback_wider_community_reviewer = ux_fallback_wider_community_reviewer
28
+ @codeowners_usernames = codeowners_usernames
29
+ @codeowners_reviewer_boost = codeowners_reviewer_boost
30
+ @codeowners_maintainer_boost = codeowners_maintainer_boost
23
31
  end
24
32
 
25
- # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
33
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
26
34
  def spin
27
35
  spins = categories.sort_by(&:to_s).map do |category|
28
36
  spin_for_category(category)
@@ -33,10 +41,7 @@ module Gitlab
33
41
 
34
42
  spins.each do |spin|
35
43
  case spin.category
36
- when :qa
37
- spin.optional_role = :maintainer if
38
- categories.size > 1 && author_no_qa_capability?
39
- when :test
44
+ when :qa, :test
40
45
  spin.optional_role = :maintainer
41
46
 
42
47
  if spin.no_reviewer?
@@ -61,8 +66,6 @@ module Gitlab
61
66
  spin.maintainer = backend_spin&.maintainer || frontend_spin&.maintainer || spin_for_category(:backend).maintainer
62
67
  end
63
68
  when :ux
64
- spin.optional_role = :maintainer
65
-
66
69
  # We want at least a UX reviewer who can review any wider community
67
70
  # contribution even without a team designer. We assign this to Pedro.
68
71
  spin.reviewer = ux_fallback_wider_community_reviewer if
@@ -74,7 +77,7 @@ module Gitlab
74
77
 
75
78
  spins
76
79
  end
77
- # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
80
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
78
81
 
79
82
  # Spin a reviewer for a particular approval rule
80
83
  #
@@ -92,12 +95,8 @@ module Gitlab
92
95
 
93
96
  private
94
97
 
95
- attr_reader :random, :ux_fallback_wider_community_reviewer
96
-
97
- # MR includes QA changes, but also other changes, and author isn't an SET
98
- def author_no_qa_capability?
99
- !(team_author && team_author.capabilities(project).any? { |capability| capability.end_with?("qa") })
100
- end
98
+ attr_reader :random, :ux_fallback_wider_community_reviewer,
99
+ :codeowners_usernames, :codeowners_reviewer_boost, :codeowners_maintainer_boost
101
100
 
102
101
  def spin_for_category(category)
103
102
  reviewers, traintainers, maintainers =
@@ -105,8 +104,16 @@ module Gitlab
105
104
  spin_role_for_category(role, category)
106
105
  end
107
106
 
108
- weighted_reviewers = Weightage::Reviewers.new(reviewers, traintainers).execute
109
- weighted_maintainers = Weightage::Maintainers.new(maintainers).execute
107
+ weighted_reviewers = Weightage::Reviewers.new(
108
+ reviewers, traintainers,
109
+ codeowners_usernames: codeowners_usernames,
110
+ codeowners_boost: codeowners_reviewer_boost
111
+ ).execute
112
+ weighted_maintainers = Weightage::Maintainers.new(
113
+ maintainers,
114
+ codeowners_usernames: codeowners_usernames,
115
+ codeowners_boost: codeowners_maintainer_boost
116
+ ).execute
110
117
 
111
118
  reviewer = spin_for_person(weighted_reviewers)
112
119
  maintainer = spin_for_person(weighted_maintainers)
@@ -3,7 +3,10 @@
3
3
  module Gitlab
4
4
  module Dangerfiles
5
5
  module TitleLinting
6
- DRAFT_REGEX = /\A*#{Regexp.union(/(?i)(\[WIP\]\s*|WIP:\s*|WIP$)/, /(?i)(\[draft\]|\(draft\)|draft:|draft\s\-\s|draft$)/)}+\s*/i.freeze
6
+ # Matches the markers a title starts with, one or several in a row, and
7
+ # a WIP or draft it ends with. The same markers anywhere else in a title
8
+ # are part of its text.
9
+ DRAFT_REGEX = /\A(?:(?:\[WIP\]|WIP:|\[draft\]|\(draft\)|draft:|draft\s-\s)\s*)+|(?:WIP|draft)\z/i.freeze
7
10
  CHERRY_PICK_REGEX = /cherry[\s-]*pick/i.freeze
8
11
  RUN_ALL_RSPEC_REGEX = /RUN ALL RSPEC/i.freeze
9
12
  RUN_AS_IF_FOSS_REGEX = /RUN AS-IF-FOSS/i.freeze
@@ -1,5 +1,5 @@
1
1
  module Gitlab
2
2
  module Dangerfiles
3
- VERSION = "4.12.0"
3
+ VERSION = "4.14.0"
4
4
  end
5
5
  end
@@ -7,8 +7,13 @@ module Gitlab
7
7
  module Weightage
8
8
  # @api private
9
9
  class Maintainers
10
- def initialize(maintainers)
10
+ # @param maintainers [Array<Gitlab::Dangerfiles::Teammate>]
11
+ # @param codeowners_usernames [Set<String>] usernames of CODEOWNERS-eligible approvers for the MR
12
+ # @param codeowners_boost [Integer] extra weight entries for CODEOWNERS-eligible maintainers
13
+ def initialize(maintainers, codeowners_usernames: Set.new, codeowners_boost: 0)
11
14
  @maintainers = maintainers
15
+ @codeowners_usernames = codeowners_usernames
16
+ @codeowners_boost = codeowners_boost
12
17
  end
13
18
 
14
19
  def execute
@@ -19,7 +24,7 @@ module Gitlab
19
24
 
20
25
  private
21
26
 
22
- attr_reader :maintainers
27
+ attr_reader :maintainers, :codeowners_usernames, :codeowners_boost
23
28
 
24
29
  def add_weighted_reviewer(reviewers, reviewer, weight)
25
30
  if reviewer.reduced_capacity
@@ -27,6 +32,8 @@ module Gitlab
27
32
  else
28
33
  reviewers.fill(reviewer, reviewers.size, weight * Gitlab::Dangerfiles::Weightage::CAPACITY_MULTIPLIER)
29
34
  end
35
+
36
+ reviewers.fill(reviewer, reviewers.size, codeowners_boost) if codeowners_boost.positive? && codeowners_usernames.include?(reviewer.username)
30
37
  end
31
38
  end
32
39
  end
@@ -18,20 +18,27 @@ module Gitlab
18
18
  # | hungry traintainer | 6 |
19
19
  # +------------------------------+--------------------------------+
20
20
  #
21
+ # When +codeowners_boost+ is configured (> 0), reviewers whose
22
+ # username appears in +codeowners_usernames+ receive that many
23
+ # additional entries in the pool on top of their base weight.
24
+ #
21
25
  # @api private
22
26
  class Reviewers
23
27
  DEFAULT_REVIEWER_WEIGHT = Gitlab::Dangerfiles::Weightage::CAPACITY_MULTIPLIER * Gitlab::Dangerfiles::Weightage::BASE_REVIEWER_WEIGHT
24
28
  TRAINTAINER_WEIGHT = 2
25
29
 
26
- def initialize(reviewers, traintainers)
30
+ # @param reviewers [Array<Gitlab::Dangerfiles::Teammate>]
31
+ # @param traintainers [Array<Gitlab::Dangerfiles::Teammate>]
32
+ # @param codeowners_usernames [Set<String>] usernames of CODEOWNERS-eligible approvers for the MR
33
+ # @param codeowners_boost [Integer] extra weight entries for CODEOWNERS-eligible reviewers
34
+ def initialize(reviewers, traintainers, codeowners_usernames: Set.new, codeowners_boost: 0)
27
35
  @reviewers = reviewers
28
36
  @traintainers = traintainers
37
+ @codeowners_usernames = codeowners_usernames
38
+ @codeowners_boost = codeowners_boost
29
39
  end
30
40
 
31
41
  def execute
32
- # TODO: take CODEOWNERS into account?
33
- # https://gitlab.com/gitlab-org/gitlab/issues/26723
34
-
35
42
  remove_traintainers_from_reviewers!
36
43
  remove_maintainer_only_from_reviewers!
37
44
 
@@ -40,7 +47,7 @@ module Gitlab
40
47
 
41
48
  private
42
49
 
43
- attr_reader :reviewers, :traintainers
50
+ attr_reader :reviewers, :traintainers, :codeowners_usernames, :codeowners_boost
44
51
 
45
52
  def remove_traintainers_from_reviewers!
46
53
  # Sometimes folks will add themselves as traintainers and not remove themselves as reviewers.
@@ -75,6 +82,8 @@ module Gitlab
75
82
  else
76
83
  reviewers.fill(reviewer, reviewers.size, DEFAULT_REVIEWER_WEIGHT)
77
84
  end
85
+
86
+ reviewers.fill(reviewer, reviewers.size, codeowners_boost) if codeowners_boost.positive? && codeowners_usernames.include?(reviewer.username)
78
87
  end
79
88
  end
80
89
  end
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: 4.12.0
4
+ version: 4.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitLab
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-06-15 00:00:00.000000000 Z
11
+ date: 2026-10-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -241,14 +241,12 @@ files:
241
241
  - lefthook.yml
242
242
  - lib/danger/plugins/changelog.rb
243
243
  - lib/danger/plugins/commit_messages.rb
244
- - lib/danger/plugins/duo_code.rb
245
244
  - lib/danger/plugins/internal/helper.rb
246
245
  - lib/danger/plugins/roulette.rb
247
246
  - lib/danger/rules/changelog/Dangerfile
248
247
  - lib/danger/rules/changes_size/Dangerfile
249
248
  - lib/danger/rules/commit_messages/Dangerfile
250
249
  - lib/danger/rules/commits_counter/Dangerfile
251
- - lib/danger/rules/duo_code_review/Dangerfile
252
250
  - lib/danger/rules/metadata/Dangerfile
253
251
  - lib/danger/rules/simple_roulette/Dangerfile
254
252
  - lib/danger/rules/type_label/Dangerfile
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Danger
4
- # Contains method to check if Duo code suggestion added to MR as a reviewer.
5
- class DuoCode < Danger::Plugin
6
- def suggestion_added?
7
- return false unless helper.ci?
8
-
9
- helper.mr_reviewers.include?("GitLabDuo")
10
- end
11
- end
12
- end
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- return if duo_code.suggestion_added?
4
-
5
- case helper.config.duo_code_review
6
- when :optional
7
- markdown("We advise getting a review from GitLab Duo Code. You can assign `@GitLabDuo` as a reviewer to this merge request.")
8
- when :mandatory
9
- failure("A review from GitLab Duo Code is mandatory. Please assign `@GitLabDuo` as a reviewer to this merge request.")
10
- end