import argparse import codeowners import os def find_codeowners_path(p): """Searches the folder containing the path 'p' and all parents until a CODEOWNERS file is found. Returns 'None' if no file is found.""" head, tail = os.path.split(p) if tail == '': return None co_path = os.path.join(head, 'CODEOWNERS') if os.path.exists(co_path): return os.path.normpath(co_path) else: return find_codeowners_path(head) def make_relative(root, path): """Converts a path to a unix-style path relative to the root folder""" p = os.path.normpath(os.path.abspath(path)) abs_root = os.path.abspath(root) prefix = os.path.commonprefix([abs_root, p]) if prefix != abs_root: raise Exception(f'{p} does not exist under the root folder {abs_root}') relpath = os.path.relpath(p, abs_root) return relpath.replace('\\', '/') def describe_owners(file_path): co_path = find_codeowners_path(file_path) if co_path: owners = get_owners(co_path) rel_path = make_relative(os.path.split(co_path)[0], file_path) results = owners.of(rel_path) if len(results) == 0: print(f'"{file_path}",none,"No matching entries in CODEOWNERS"') else: for result in results: print(f'"{file_path}",{result[0].lower()},"{result[1]}"') else: print(f'"{file_path}",none,"Unable to find CODEOWNERS file"') def get_owners(co_path): """Get a CodeOwners object for the specified CODEOWNERS file path""" with open(co_path, "rt") as f: # process the file to remove leading /'s which don't seem to be handled properly by the # codeowners python module. contents = [] for line in f.readlines(): stripped_line = line.strip() if stripped_line.startswith('/'): stripped_line = stripped_line[1:] contents.append(stripped_line) processed = "\n".join(contents) return codeowners.CodeOwners(processed) def main(): parser = argparse.ArgumentParser(description="Show user/team ownership information for specified files") parser.add_argument("files", nargs='+') args = parser.parse_args() print('file,owner_type,owner') for file in args.files: describe_owners(file) if __name__ == "__main__": main()