# frozen_string_literal: true PROJECT_NAME = helper.config.project_name MESSAGE = <<MARKDOWN ## Reviewer roulette Changes that require review have been detected! A merge request is normally reviewed by both a reviewer and a maintainer in its primary category and by a maintainer in all other categories. MARKDOWN TABLE_MARKDOWN = <<MARKDOWN To spread load more evenly across eligible reviewers, Danger has picked a candidate for each review slot. Feel free to [override these selections](https://about.gitlab.com/handbook/engineering/projects/##{PROJECT_NAME}) 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. 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). Please consider assigning a reviewer or maintainer who is a [domain expert](https://about.gitlab.com/handbook/engineering/projects/#gitlab-development-kit) in the area of the merge request. Once you've decided who will review this merge request, mention them as you normally would! Danger does not automatically notify them for you. MARKDOWN TABLE_HEADER_WITH_CATEGORIES = <<MARKDOWN | Category | Reviewer | Maintainer | | -------- | -------- | ---------- | MARKDOWN TABLE_HEADER_WITHOUT_CATEGORIES = <<MARKDOWN | Reviewer | Maintainer | | -------- | ---------- | MARKDOWN OPTIONAL_REVIEW_TEMPLATE = '%{role} review is optional' NOT_AVAILABLE_TEMPLATE = 'No %{role} available' def note_for_spins_role(spins, role) spins.each do |spin| note = note_for_spin_role(spin, role) return note if note end NOT_AVAILABLE_TEMPLATE % { role: role } end def note_for_spin_role(spin, role) if spin.optional_role == role return OPTIONAL_REVIEW_TEMPLATE % { role: role.capitalize } end spin.public_send(role)&.markdown_name(author: roulette.team_mr_author) end def markdown_row_for_spins(category = nil, spins_array, has_categories:) reviewer_note = note_for_spins_role(spins_array, :reviewer) maintainer_note = note_for_spins_role(spins_array, :maintainer) row = +"| #{reviewer_note} | #{maintainer_note} |" row.prepend("| #{helper.label_for_category(category)} ") if has_categories row end changes = helper.changes_by_category # Replicating label based categories from: # https://gitlab.com/gitlab-org/gitlab/-/blob/master/danger/roulette/Dangerfile categories = Set.new(changes.keys - [:unknown]) # Ensure to spin for database reviewer/maintainer when ~database is applied (e.g. to review SQL queries) categories << :database if helper.mr_labels.include?('database') # Ensure to spin for UX reviewer when ~UX is applied (e.g. to review changes to the UI) except when it's from wider community contribution where we want to assign from the corresponding group categories << :ux if helper.mr_labels.include?('UX') && !helper.mr_labels.include?('Community contribution') # 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") # Skip Product intelligence reviews for growth experiment MRs categories.delete(:product_intelligence) if helper.mr_labels.include?("growth experiment") if changes.any? has_categories = categories.any? categories = [nil] unless has_categories random_roulette_spins = roulette.spin(nil, categories) rows = random_roulette_spins.map do |spin| markdown_row_for_spins(spin.category, [spin], has_categories: has_categories) end table_header = has_categories ? TABLE_HEADER_WITH_CATEGORIES : TABLE_HEADER_WITHOUT_CATEGORIES markdown(MESSAGE) markdown(TABLE_MARKDOWN + table_header + rows.join("\n")) unless rows.empty? end