diff --git a/danger/roulette/Dangerfile b/danger/roulette/Dangerfile index ae701dc2f9ed634e3cbc0b2f5451c82cae0a8f01..ae4932991364745fedfb4ced8eb9bd93fc890307 100644 --- a/danger/roulette/Dangerfile +++ b/danger/roulette/Dangerfile @@ -43,9 +43,7 @@ rescue StandardError => e [] end -def spin_for_category(team, project, category, branch_name) - random = roulette.new_random(branch_name) - +def spin_for_category(team, project, category, random) reviewers, traintainers, maintainers = %i[reviewer? traintainer? maintainer?].map do |kind| team.select do |member| @@ -66,28 +64,57 @@ end changes = helper.changes_by_category categories = changes.keys +component_labels = helper.component_labels if changes.any? branch_name = gitlab.mr_json['source_branch'] + random = roulette.new_random(branch_name) team = team_for_project(GITLAB_PROJECT_ID) rows = categories.map do |category| - spin_for_category(team, GITLAB_PROJECT_ID, category, branch_name) + spin_for_category(team, GITLAB_PROJECT_ID, category, random) end # If these are docs-only changes, we need to pick a frontend maintainer for the final review if categories == %i[docs] - frontend_row = spin_for_category(team, GITLAB_PROJECT_ID, :frontend, branch_name) + frontend_row = spin_for_category(team, GITLAB_PROJECT_ID, :frontend, random) # We remove the frontend reviewer as the initial review will be performed by a technical writer frontend_row[:reviewer] = nil rows << frontend_row end + # Add component-specific UX reviewers + component_labels.each do |label| + ux_teammates = helper.ux_reviewers_for_label(label).map { |username| roulette.teammate_with_username(username) } + ux_reviewer = roulette.spin_for_person(ux_teammates, random: random) + component_ux_row = { + "label": "~\"#{label}\"", + "reviewer": ux_reviewer&.markdown_name, + "maintainer": nil + } + rows << component_ux_row + end + roulette_rows = rows.map do |row| "| #{row[:label]} | #{row[:reviewer] || NO_REVIEWER} | #{row[:maintainer] || NO_MAINTAINER} |" end markdown(MESSAGE) markdown(CATEGORY_TABLE_HEADER + roulette_rows.join("\n")) + unless component_labels.empty? + markdown( + <<~MARKDOWN + If your Merge Request changes one or more components, please have it reviewed by a Product Designer. + One should have been suggested above. Otherwise, or if they are not available, feel free to + assign to a UX Foundations designer: + + #{helper.foundations_ux_reviewers.map do |username| + roulette.teammate_with_username(username) + end.map do |teammate| + "* #{teammate&.markdown_name}" + end.join("\n")} + MARKDOWN + ) + end end diff --git a/lib/gitlab/danger/helper.rb b/lib/gitlab/danger/helper.rb index 126a304485960760bc46ce51591a08e42bbca0a8..001277e85e7334580139937c66dc8255230b6a92 100644 --- a/lib/gitlab/danger/helper.rb +++ b/lib/gitlab/danger/helper.rb @@ -80,12 +80,71 @@ module Gitlab CATEGORY_LABELS.fetch(category, "~#{category}") end + def component_labels + gitlab_helper&.mr_labels.select { |label| label.start_with?('component:') } + end + + def ux_reviewers_for_label(label) + component = label.sub('component:', '') + COMPONENT_UX_MAP[component.to_sym] || [] + end + + def foundations_ux_reviewers + %w[ + tauriedavis + jareko + jeldergl + ] + end + CATEGORY_LABELS = { docs: '~documentation' }.freeze CATEGORIES = { %r{\Adoc/} => :docs }.freeze + COMPONENT_UX_MAP = { + accordion: %w[kcomoli rayana], + alert: %w[andyvolpe], + avatar: %w[tauriedavis], + badge: %w[pedroms], + banner: %w[andyvolpe], + breadcrumb: %w[ameliabauerly], + 'broadcast-message': %w[kmann], + button: %w[dimitrieh], + card: %w[beckalippert], + chart: %w[ameliabauerly], + checkbox: %w[pedroms], + 'data-visualization': %w[ameliabauerly], + 'date-picker': %w[tauriedavis], + drawer: %w[andyvolpe], + dropdown: %w[hollyreynolds tauriedavis], + 'file-uploader': %w[jareko], + filter: %w[matejlatin], + form: %w[tauriedavis], + icon: %w[jeldergl], + 'infinite-scroll': %w[beckalippert], + label: %w[annabeldunstone], + link: %w[jeldergl], + list: %w[tauriedavis], + modal: %w[dimitrieh], + pagination: %w[andyvolpe], + popover: %w[tauriedavis], + 'progress-bar': %w[jareko], + radio: %w[pedroms], + search: %w[matejlatin], + 'segmented-control': %w[andyvolpe], + 'skeleton-loader': %w[dimitrieh], + sorting: %w[ameliabauerly], + spinner: %w[dimitrieh], + tab: %w[dimitrieh], + table: %w[npost], + toast: %w[tauriedavis], + toggle: %w[pedroms], + token: %w[annabeldunstone], + tooltip: %w[rayana], + tree: %w[kcomoli rayana] + }.freeze end end end diff --git a/lib/gitlab/danger/roulette.rb b/lib/gitlab/danger/roulette.rb index 45c6c372ab404ffbabab3eb42dc2e38a25d5e9ae..d5d357752848e6e710f539aaac9fc950c45e5bad 100644 --- a/lib/gitlab/danger/roulette.rb +++ b/lib/gitlab/danger/roulette.rb @@ -21,6 +21,10 @@ module Gitlab end end + def teammate_with_username(username) + team.find { |teammate| teammate.username == username } + end + # Like +team+, but only returns teammates in the current project, based on # project_name. #