Dangerfile 5.11 KB
Newer Older
Nick Thomas's avatar
Nick Thomas committed
1 2
# frozen_string_literal: true

3 4
require 'digest/md5'

5
REVIEW_ROULETTE_SECTION = <<MARKDOWN
Nick Thomas's avatar
Nick Thomas committed
6
## Reviewer roulette
7 8 9 10 11
MARKDOWN

CATEGORY_TABLE = <<MARKDOWN

Changes that require review have been detected!
Nick Thomas's avatar
Nick Thomas committed
12

13 14 15 16
Please refer to the table below for assigning reviewers and maintainers suggested by Danger in the specified category:

| Category | Reviewer | Maintainer |
| -------- | -------- | ---------- |
Nick Thomas's avatar
Nick Thomas committed
17 18
MARKDOWN

19
POST_TABLE_MESSAGE = <<MARKDOWN
Nick Thomas's avatar
Nick Thomas committed
20

21 22
To spread load more evenly across eligible reviewers, Danger has picked a candidate for each
review slot, based on their timezone. Feel free to
23
[override these selections](https://about.gitlab.com/handbook/engineering/projects/#gitlab)
24 25
if you think someone else would be better-suited
or use the [GitLab Review Workload Dashboard](https://gitlab-org.gitlab.io/gitlab-roulette/) to find other available reviewers.
Nick Thomas's avatar
Nick Thomas committed
26

27 28 29
To read more on how to use the reviewer roulette, please take a look at the
[Engineering workflow](https://about.gitlab.com/handbook/engineering/workflow/#basics)
and [code review guidelines](https://docs.gitlab.com/ee/development/code_review.html).
30 31
Please consider assigning a reviewer or maintainer who is a
[domain expert](https://about.gitlab.com/handbook/engineering/projects/#gitlab) in the area of the merge request.
32

33 34
Once you've decided who will review this merge request, assign them as a reviewer!
Danger does not automatically notify them for you.
35
MARKDOWN
Nick Thomas's avatar
Nick Thomas committed
36

37 38 39
NO_SUGGESTIONS = <<MARKDOWN

There are no reviewer and maintainer suggestions for the changes in this MR.
Nick Thomas's avatar
Nick Thomas committed
40 41 42
MARKDOWN

UNKNOWN_FILES_MESSAGE = <<MARKDOWN
43
### Uncategorized files
Nick Thomas's avatar
Nick Thomas committed
44

45
These files couldn't be categorized, so Danger was unable to suggest a reviewer.
Nick Thomas's avatar
Nick Thomas committed
46
Please consider creating a merge request to
47
[add support](https://gitlab.com/gitlab-org/gitlab/blob/master/tooling/danger/project_helper.rb)
Nick Thomas's avatar
Nick Thomas committed
48 49 50
for them.
MARKDOWN

51
def group_not_available_template(slack_channel, gitlab_group)
52 53
  <<~TEMPLATE.strip
    No engineer is available for automated assignment, please reach out to the `#{slack_channel}` Slack channel or mention `#{gitlab_group}` for assistance.
54 55 56
  TEMPLATE
end

57
OPTIONAL_REVIEW_TEMPLATE = '%{role} review is optional for %{category}'
58 59
NOT_AVAILABLE_TEMPLATES = {
  default: 'No %{role} available',
60 61 62
  product_intelligence: group_not_available_template('#g_product_intelligence', '@gitlab-org/growth/product-intelligence/engineers'),
  integrations_be: group_not_available_template('#g_ecosystem_integrations', '@gitlab-org/ecosystem-stage/integrations'),
  integrations_fe: group_not_available_template('#g_ecosystem_integrations', '@gitlab-org/ecosystem-stage/integrations')
63 64 65 66
}.freeze

def note_for_spins_role(spins, role, category)
  template = NOT_AVAILABLE_TEMPLATES[category] || NOT_AVAILABLE_TEMPLATES[:default]
67

68 69 70 71 72 73
  spins.each do |spin|
    note = note_for_spin_role(spin, role)

    return note if note
  end

74
  template % { role: role }
75 76
end

77
def note_for_spin_role(spin, role)
78 79
  if spin.optional_role == role
    return OPTIONAL_REVIEW_TEMPLATE % { role: role.capitalize, category: helper.label_for_category(spin.category) }
80 81
  end

82
  spin.public_send(role)&.markdown_name(author: roulette.team_mr_author) # rubocop:disable GitlabSecurity/PublicSend
83 84
end

85
def markdown_row_for_spins(category, spins_array)
86 87
  maintainer_note = note_for_spins_role(spins_array, :maintainer, category)
  reviewer_note = note_for_spins_role(spins_array, :reviewer, category)
88

89
  "| #{helper.label_for_category(category)} | #{reviewer_note} | #{maintainer_note} |"
Nick Thomas's avatar
Nick Thomas committed
90 91
end

92
changes = project_helper.changes_by_category
93

94
# Ignore any files that are known but uncategorized. Prompt for any unknown files
95
changes.delete(:none)
96 97
# To reinstate roulette for documentation, remove this line.
changes.delete(:docs)
98 99
# No special review for changelog needed and changelog was never a label.
changes.delete(:changelog)
100 101
# No special review for feature flags needed.
changes.delete(:feature_flag)
102
categories = Set.new(changes.keys - [:unknown])
Nick Thomas's avatar
Nick Thomas committed
103

104
# Ensure to spin for database reviewer/maintainer when ~database is applied (e.g. to review SQL queries)
105 106
categories << :database if helper.mr_labels.include?('database')

107
# Ensure to spin for UX reviewer for community contributions when ~UX is applied (e.g. to review changes to the UI)
108
categories << :ux if (["UX", "Community contribution"] - helper.mr_labels).empty?
Austin Regnery's avatar
Austin Regnery committed
109

110 111
# Ensure to spin for Product Intelligence reviewer when ~"product intelligence::review pending" is applied
categories << :product_intelligence if helper.mr_labels.include?("product intelligence::review pending")
112 113 114

# Skip Product intelligence reviews for growth experiment MRs
categories.delete(:product_intelligence) unless helper.mr_labels.include?("growth experiment")
115

116
if changes.any?
117
  project = project_helper.project_name
118

119
  random_roulette_spins = roulette.spin(project, categories, timezone_experiment: false)
120

121 122
  rows = random_roulette_spins.map do |spin|
    markdown_row_for_spins(spin.category, [spin])
123
  end
Nick Thomas's avatar
Nick Thomas committed
124

125 126 127 128 129 130 131 132
  markdown(REVIEW_ROULETTE_SECTION)

  if rows.empty?
    markdown(NO_SUGGESTIONS)
  else
    markdown(CATEGORY_TABLE + rows.join("\n"))
    markdown(POST_TABLE_MESSAGE)
  end
133 134

  unknown = changes.fetch(:unknown, [])
135
  markdown(UNKNOWN_FILES_MESSAGE + helper.markdown_list(unknown)) unless unknown.empty?
Nick Thomas's avatar
Nick Thomas committed
136
end