blob: 0385b2e80c3da4f32780133bd8fad990503f8c28 [file] [log] [blame]
Patrick Williams6cef2552022-05-29 15:35:17 -05001#!/bin/env python3
2import argparse
3import json
4import yaml
5
6from typing import List, TypedDict
7from yaml.loader import SafeLoader
8
9# A list of Gerrit users (email addresses).
10UsersList = List[str]
11
12# A YAML node with an extra line number.
13class NumberedNode(TypedDict):
14 line_number: int
15
16
17# The root YAML node of an OWNERS file
18class OwnersData(NumberedNode, TypedDict, total=False):
19 owners: UsersList
20 reviewers: UsersList
21
22
23# A YAML loader that adds the start line number onto each node (for
24# later linting support)
25class YamlLoader(SafeLoader):
26 def construct_mapping(
27 self, node: yaml.nodes.Node, deep: bool = False
28 ) -> NumberedNode:
29 mapping: NumberedNode = super(YamlLoader, self).construct_mapping(
30 node, deep=deep
31 ) # type: ignore
32 mapping["line_number"] = node.start_mark.line + 1
33 return mapping
34
35 # Load a file and return the OwnersData.
36 @staticmethod
37 def load(file: str) -> OwnersData:
38 data: OwnersData
39 with open(file, "r") as f:
40 data = yaml.load(f, Loader=YamlLoader)
41 return data
42
43
44# Class to match commit information with OWNERS files.
45# TODO: git commit piece not yet supported.
46class CommitMatch:
47 def __init__(self, owners: OwnersData):
48 self.data = owners
49
50 def owners(self) -> UsersList:
51 return self.data["owners"] if "owners" in self.data else []
52
53 def reviewers(self) -> UsersList:
54 return self.data["reviewers"] if "reviewers" in self.data else []
55
56
57# The subcommand to get the reviewers.
58def subcmd_reviewers(args: argparse.Namespace, data: OwnersData) -> None:
59 matcher = CommitMatch(data)
60
61 # Print in `git push refs/for/branch%<reviewers>` format.
62 if args.push_args:
63 result = []
64 for o in matcher.owners():
65 # Gerrit uses 'r' for the required reviewers (owners).
66 result.append(f"r={o}")
67 for r in matcher.reviewers():
68 # Gerrit uses 'cc' for the optional reviewers.
69 result.append(f"cc={r}")
70 print(",".join(result))
71 # Print as Gerrit Add Reviewers POST format.
72 # https://gerrit.openbmc.org/Documentation/rest-api-changes.html#add-reviewer
73 else:
74 for o in matcher.owners():
75 print(json.dumps({"reviewer": o, "state": "REVIEWER"}))
76 for r in matcher.reviewers():
77 print(json.dumps({"reviewer": r, "state": "CC"}))
78
79
80def main() -> None:
81 parser = argparse.ArgumentParser()
82 parser.add_argument(
83 "-p", "--path", default=".", help="Root path to analyse"
84 )
85 subparsers = parser.add_subparsers()
86
87 parser_reviewers = subparsers.add_parser(
88 "reviewers", help="Generate List of Reviewers"
89 )
90 parser_reviewers.add_argument(
91 "--push-args",
92 action=argparse.BooleanOptionalAction,
93 help="Format as git push options",
94 )
95 parser_reviewers.set_defaults(func=subcmd_reviewers)
96
97 args = parser.parse_args()
98
99 file = YamlLoader.load(args.path + "/OWNERS")
100 args.func(args, file)
101
102
103if __name__ == "__main__":
104 main()