Chih-Hung Hsieh | b298bcd | 2020-08-17 23:13:59 -0700 | [diff] [blame] | 1 | # Copyright (C) 2020 The Android Open Source Project |
| 2 | # |
| 3 | # Licensed under the Apache License, Version 2.0 (the 'License'); |
| 4 | # you may not use this file except in compliance with the License. |
| 5 | # You may obtain a copy of the License at |
| 6 | # |
| 7 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | # |
| 9 | # Unless required by applicable law or agreed to in writing, software |
| 10 | # distributed under the License is distributed on an 'AS IS' BASIS, |
| 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | # See the License for the specific language governing permissions and |
| 13 | # limitations under the License. |
Chih-Hung Hsieh | aa48555 | 2020-08-20 15:45:09 -0700 | [diff] [blame] | 14 | """Find main reviewers for git push commands.""" |
Chih-Hung Hsieh | b298bcd | 2020-08-17 23:13:59 -0700 | [diff] [blame] | 15 | |
Chih-Hung Hsieh | aa48555 | 2020-08-20 15:45:09 -0700 | [diff] [blame] | 16 | import math |
Chih-Hung Hsieh | b298bcd | 2020-08-17 23:13:59 -0700 | [diff] [blame] | 17 | import random |
Chih-Hung Hsieh | 4f2dd23 | 2020-08-19 18:52:53 -0700 | [diff] [blame] | 18 | from typing import List, Mapping, Set, Union |
| 19 | |
Chih-Hung Hsieh | aa48555 | 2020-08-20 15:45:09 -0700 | [diff] [blame] | 20 | # To randomly pick one of multiple reviewers, we put them in a List[str] |
Chih-Hung Hsieh | 4f2dd23 | 2020-08-19 18:52:53 -0700 | [diff] [blame] | 21 | # to work with random.choice efficiently. |
Chih-Hung Hsieh | aa48555 | 2020-08-20 15:45:09 -0700 | [diff] [blame] | 22 | # To pick all of multiple reviewers, we use a Set[str]. |
Chih-Hung Hsieh | 4f2dd23 | 2020-08-19 18:52:53 -0700 | [diff] [blame] | 23 | |
| 24 | # A ProjMapping maps a project path string to |
Chih-Hung Hsieh | aa48555 | 2020-08-20 15:45:09 -0700 | [diff] [blame] | 25 | # (1) a single reviewer email address as a string, or |
| 26 | # (2) a List of multiple reviewers to be randomly picked, or |
| 27 | # (3) a Set of multiple reviewers to be all added. |
Chih-Hung Hsieh | 4f2dd23 | 2020-08-19 18:52:53 -0700 | [diff] [blame] | 28 | ProjMapping = Mapping[str, Union[str, List[str], Set[str]]] |
Chih-Hung Hsieh | b298bcd | 2020-08-17 23:13:59 -0700 | [diff] [blame] | 29 | |
Chih-Hung Hsieh | aa48555 | 2020-08-20 15:45:09 -0700 | [diff] [blame] | 30 | # Rust crate owners (reviewers). |
| 31 | RUST_CRATE_OWNERS: ProjMapping = { |
Chih-Hung Hsieh | b298bcd | 2020-08-17 23:13:59 -0700 | [diff] [blame] | 32 | 'rust/crates/anyhow': 'mmaurer@google.com', |
Chih-Hung Hsieh | aa48555 | 2020-08-20 15:45:09 -0700 | [diff] [blame] | 33 | # more rust crate owners could be added later |
Joel Galenson | 6592d49 | 2021-07-26 10:31:54 -0700 | [diff] [blame] | 34 | # if so, consider modifying the quotas in RUST_REVIEWERS |
Chih-Hung Hsieh | b298bcd | 2020-08-17 23:13:59 -0700 | [diff] [blame] | 35 | } |
| 36 | |
Chih-Hung Hsieh | aa48555 | 2020-08-20 15:45:09 -0700 | [diff] [blame] | 37 | PROJ_REVIEWERS: ProjMapping = { |
| 38 | # define non-rust project reviewers here |
| 39 | } |
| 40 | |
| 41 | # Combine all roject reviewers. |
| 42 | PROJ_REVIEWERS.update(RUST_CRATE_OWNERS) |
| 43 | |
Chih-Hung Hsieh | b298bcd | 2020-08-17 23:13:59 -0700 | [diff] [blame] | 44 | # Reviewers for external/rust/crates projects not found in PROJ_REVIEWER. |
Chih-Hung Hsieh | aa48555 | 2020-08-20 15:45:09 -0700 | [diff] [blame] | 45 | # Each person has a quota, the number of projects to review. |
Joel Galenson | 6592d49 | 2021-07-26 10:31:54 -0700 | [diff] [blame] | 46 | # The sum of these quotas should ideally be at least the number of Rust |
| 47 | # projects, but this only matters if we have many entries in RUST_CRATE_OWNERS, |
| 48 | # as we subtract a person's owned crates from their quota. |
Chih-Hung Hsieh | aa48555 | 2020-08-20 15:45:09 -0700 | [diff] [blame] | 49 | RUST_REVIEWERS: Mapping[str, int] = { |
Chih-Hung Hsieh | 470cdc4 | 2021-01-11 15:06:55 -0800 | [diff] [blame] | 50 | 'ivanlozano@google.com': 20, |
| 51 | 'jeffv@google.com': 20, |
Chih-Hung Hsieh | 470cdc4 | 2021-01-11 15:06:55 -0800 | [diff] [blame] | 52 | 'mmaurer@google.com': 20, |
| 53 | 'srhines@google.com': 20, |
| 54 | 'tweek@google.com': 20, |
Chih-Hung Hsieh | aa48555 | 2020-08-20 15:45:09 -0700 | [diff] [blame] | 55 | # If a Rust reviewer needs to take a vacation, comment out the line, |
| 56 | # and distribute the quota to other reviewers. |
| 57 | } |
| 58 | |
| 59 | |
Thiébaud Weksteen | 4ac289b | 2020-09-28 15:23:29 +0200 | [diff] [blame] | 60 | # pylint: disable=invalid-name |
Chih-Hung Hsieh | aa48555 | 2020-08-20 15:45:09 -0700 | [diff] [blame] | 61 | def add_proj_count(projects: Mapping[str, float], reviewer: str, n: float): |
| 62 | """Add n to the number of projects owned by the reviewer.""" |
| 63 | if reviewer in projects: |
| 64 | projects[reviewer] += n |
| 65 | else: |
| 66 | projects[reviewer] = n |
| 67 | |
| 68 | |
| 69 | # Random Rust reviewers are selected from RUST_REVIEWER_LIST, |
| 70 | # which is created from RUST_REVIEWERS and PROJ_REVIEWERS. |
| 71 | # A person P in RUST_REVIEWERS will occur in the RUST_REVIEWER_LIST N times, |
| 72 | # if N = RUST_REVIEWERS[P] - (number of projects owned by P in PROJ_REVIEWERS) |
| 73 | # is greater than 0. N is rounded up by math.ceil. |
| 74 | def create_rust_reviewer_list() -> List[str]: |
| 75 | """Create a list of duplicated reviewers for weighted random selection.""" |
| 76 | # Count number of projects owned by each reviewer. |
| 77 | rust_reviewers = set(RUST_REVIEWERS.keys()) |
| 78 | projects = {} # map from owner to number of owned projects |
| 79 | for value in PROJ_REVIEWERS.values(): |
| 80 | if isinstance(value, str): # single reviewer for a project |
| 81 | add_proj_count(projects, value, 1) |
| 82 | continue |
| 83 | # multiple reviewers share one project, count only rust_reviewers |
Thiébaud Weksteen | 4ac289b | 2020-09-28 15:23:29 +0200 | [diff] [blame] | 84 | # pylint: disable=bad-builtin |
Chih-Hung Hsieh | aa48555 | 2020-08-20 15:45:09 -0700 | [diff] [blame] | 85 | reviewers = set(filter(lambda x: x in rust_reviewers, value)) |
| 86 | if reviewers: |
| 87 | count = 1.0 / len(reviewers) # shared among all reviewers |
| 88 | for name in reviewers: |
| 89 | add_proj_count(projects, name, count) |
| 90 | result = [] |
| 91 | for (x, n) in RUST_REVIEWERS.items(): |
| 92 | if x in projects: # reduce x's quota by the number of assigned ones |
| 93 | n = n - projects[x] |
| 94 | if n > 0: |
| 95 | result.extend([x] * math.ceil(n)) |
| 96 | if result: |
| 97 | return result |
| 98 | # Something was wrong or quotas were too small so that nobody |
| 99 | # was selected from the RUST_REVIEWERS. Select everyone!! |
| 100 | return list(RUST_REVIEWERS.keys()) |
| 101 | |
| 102 | |
| 103 | RUST_REVIEWER_LIST: List[str] = create_rust_reviewer_list() |
Chih-Hung Hsieh | b298bcd | 2020-08-17 23:13:59 -0700 | [diff] [blame] | 104 | |
| 105 | |
Chih-Hung Hsieh | 4f2dd23 | 2020-08-19 18:52:53 -0700 | [diff] [blame] | 106 | def find_reviewers(proj_path: str) -> str: |
| 107 | """Returns an empty string or a reviewer parameter(s) for git push.""" |
Chih-Hung Hsieh | b298bcd | 2020-08-17 23:13:59 -0700 | [diff] [blame] | 108 | index = proj_path.find('/external/') |
| 109 | if index >= 0: # full path |
| 110 | proj_path = proj_path[(index + len('/external/')):] |
| 111 | elif proj_path.startswith('external/'): # relative path |
| 112 | proj_path = proj_path[len('external/'):] |
Chih-Hung Hsieh | 4f2dd23 | 2020-08-19 18:52:53 -0700 | [diff] [blame] | 113 | if proj_path in PROJ_REVIEWERS: |
| 114 | reviewers = PROJ_REVIEWERS[proj_path] |
Thiébaud Weksteen | 4ac289b | 2020-09-28 15:23:29 +0200 | [diff] [blame] | 115 | # pylint: disable=isinstance-second-argument-not-valid-type |
Chih-Hung Hsieh | 4f2dd23 | 2020-08-19 18:52:53 -0700 | [diff] [blame] | 116 | if isinstance(reviewers, List): # pick any one reviewer |
| 117 | return 'r=' + random.choice(reviewers) |
Chih-Hung Hsieh | aa48555 | 2020-08-20 15:45:09 -0700 | [diff] [blame] | 118 | if isinstance(reviewers, Set): # add all reviewers in sorted order |
Thiébaud Weksteen | 4ac289b | 2020-09-28 15:23:29 +0200 | [diff] [blame] | 119 | # pylint: disable=bad-builtin |
Chih-Hung Hsieh | aa48555 | 2020-08-20 15:45:09 -0700 | [diff] [blame] | 120 | return ','.join(map(lambda x: 'r=' + x, sorted(reviewers))) |
Chih-Hung Hsieh | 4f2dd23 | 2020-08-19 18:52:53 -0700 | [diff] [blame] | 121 | # reviewers must be a string |
| 122 | return 'r=' + reviewers |
Chih-Hung Hsieh | b298bcd | 2020-08-17 23:13:59 -0700 | [diff] [blame] | 123 | if proj_path.startswith('rust/crates/'): |
Chih-Hung Hsieh | aa48555 | 2020-08-20 15:45:09 -0700 | [diff] [blame] | 124 | return 'r=' + random.choice(RUST_REVIEWER_LIST) |
Chih-Hung Hsieh | b298bcd | 2020-08-17 23:13:59 -0700 | [diff] [blame] | 125 | return '' |