blob: 0385b2e80c3da4f32780133bd8fad990503f8c28 [file] [log] [blame]
#!/bin/env python3
import argparse
import json
import yaml
from typing import List, TypedDict
from yaml.loader import SafeLoader
# A list of Gerrit users (email addresses).
UsersList = List[str]
# A YAML node with an extra line number.
class NumberedNode(TypedDict):
line_number: int
# The root YAML node of an OWNERS file
class OwnersData(NumberedNode, TypedDict, total=False):
owners: UsersList
reviewers: UsersList
# A YAML loader that adds the start line number onto each node (for
# later linting support)
class YamlLoader(SafeLoader):
def construct_mapping(
self, node: yaml.nodes.Node, deep: bool = False
) -> NumberedNode:
mapping: NumberedNode = super(YamlLoader, self).construct_mapping(
node, deep=deep
) # type: ignore
mapping["line_number"] = node.start_mark.line + 1
return mapping
# Load a file and return the OwnersData.
@staticmethod
def load(file: str) -> OwnersData:
data: OwnersData
with open(file, "r") as f:
data = yaml.load(f, Loader=YamlLoader)
return data
# Class to match commit information with OWNERS files.
# TODO: git commit piece not yet supported.
class CommitMatch:
def __init__(self, owners: OwnersData):
self.data = owners
def owners(self) -> UsersList:
return self.data["owners"] if "owners" in self.data else []
def reviewers(self) -> UsersList:
return self.data["reviewers"] if "reviewers" in self.data else []
# The subcommand to get the reviewers.
def subcmd_reviewers(args: argparse.Namespace, data: OwnersData) -> None:
matcher = CommitMatch(data)
# Print in `git push refs/for/branch%<reviewers>` format.
if args.push_args:
result = []
for o in matcher.owners():
# Gerrit uses 'r' for the required reviewers (owners).
result.append(f"r={o}")
for r in matcher.reviewers():
# Gerrit uses 'cc' for the optional reviewers.
result.append(f"cc={r}")
print(",".join(result))
# Print as Gerrit Add Reviewers POST format.
# https://gerrit.openbmc.org/Documentation/rest-api-changes.html#add-reviewer
else:
for o in matcher.owners():
print(json.dumps({"reviewer": o, "state": "REVIEWER"}))
for r in matcher.reviewers():
print(json.dumps({"reviewer": r, "state": "CC"}))
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument(
"-p", "--path", default=".", help="Root path to analyse"
)
subparsers = parser.add_subparsers()
parser_reviewers = subparsers.add_parser(
"reviewers", help="Generate List of Reviewers"
)
parser_reviewers.add_argument(
"--push-args",
action=argparse.BooleanOptionalAction,
help="Format as git push options",
)
parser_reviewers.set_defaults(func=subcmd_reviewers)
args = parser.parse_args()
file = YamlLoader.load(args.path + "/OWNERS")
args.func(args, file)
if __name__ == "__main__":
main()