Last active
August 24, 2022 22:01
-
-
Save tiffany352/c0a17b6ef0dd8ff5ee0276b9d3bad43f to your computer and use it in GitHub Desktop.
I think I got whoowns.py from someone on slack, but I modified it to output CSV.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import io | |
import subprocess | |
import whoowns | |
import argparse | |
def main(): | |
parser = argparse.ArgumentParser(description="Generates a CSV of all files in the repo and which codeowner is set.") | |
parser.add_argument("out") | |
args = parser.parse_args() | |
owners = whoowns.get_owners('./CODEOWNERS') | |
file = io.open(args.out, "w", encoding="utf-8") | |
file.write("path,owners\n") | |
all_files = subprocess.run(["git", "ls-files"], capture_output=True, text=True).stdout.split('\n') | |
for path in all_files: | |
file_owners = owners.of(path) | |
file.write("%s,%s\n" % (path, " ".join(map(lambda o: o[1], file_owners)))) | |
file.flush() | |
file.close() | |
if __name__ == "__main__": | |
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Returns list of codeowners for files touched in current branch. | |
def "whoowns" [] { | |
let root = (git rev-parse --show-toplevel | str trim) | |
enter $root | |
let changed_files = (git diff --name-only upstream/master...HEAD | lines) | |
let files = (python ~\Documents\Scripts\whoowns.py $changed_files) | |
exit | |
$files | from csv | sort-by owner file | |
} | |
def "flag-status" [] { | |
ls flags\tbennett\ | | |
par-each {|it| | |
do -i { | |
git log -1 --pretty=format:%ci $it.name | |
} | | |
complete | | |
select stdout | | |
update stdout { |it| | |
$it.stdout | | |
into datetime | |
} | | |
insert flag { | |
$it.name | | |
parse "flags\\tbennett\\{flag}.json" | | |
get flag | |
} | |
} | | |
rename date flag | | |
flatten | | |
sort-by date | |
} | |
def "merge-stable" [branch] { | |
git checkout $branch; | |
git pull --set-upstream origin $branch; | |
git fetch upstream; | |
git merge upstream/stable; | |
git push | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import glob | |
import argparse | |
import json | |
import os | |
import subprocess | |
import re | |
import sys | |
from codeowners import CodeOwners | |
import whoowns | |
flag_regex = re.compile('FASTFLAGVARIABLE\((\w+),\s*\w+\)') | |
def main(): | |
parser = argparse.ArgumentParser(description="Find fast flags owned by the given team") | |
parser.add_argument("team") | |
parser.add_argument("fflags_repo") | |
args = parser.parse_args() | |
team = args.team | |
fflags_repo = args.fflags_repo | |
co_path = whoowns.find_codeowners_path(os.getcwd()) | |
dir, filename = os.path.split(co_path) | |
os.chdir(dir) | |
files = list(filter(lambda f: f.endswith((".h", ".cpp")), subprocess.run(["git", "ls-files"], capture_output=True, text=True).stdout.split('\n'))) | |
owner = ('TEAM', team) | |
with open(co_path, "rt") as f: | |
owners = CodeOwners(f.read()) | |
found = [] | |
count = 0 | |
last = None | |
for file in files: | |
next = count / len(files) * 100.0 | |
if last != next: | |
if last != None: | |
sys.stdout.write("\x1b[1A\x1b[2K") # move up cursor and delete whole line | |
print("Running... %d%%" % (next)) | |
last = next | |
count += 1 | |
# print("testing", file) | |
# print("owners", owners.of(file)) | |
# print("needle", owner) | |
if owner in owners.of(file): | |
# print("have match!!!!", file) | |
with open(file, "rt") as f: | |
for flag in flag_regex.findall(f.read()): | |
# print(file, flag) | |
flag_glob = "flags/*/*%s.json" % flag | |
# print(flag_glob) | |
# print(fflags_repo) | |
flag_value = None | |
flag_age = '' | |
flag_timestamp = 0 | |
for match in glob.glob(flag_glob, root_dir=fflags_repo, recursive=True): | |
with open(fflags_repo + "/" + match, "rt") as f: | |
data = json.load(f) | |
flag_age = subprocess.run(["git", "log", "-n", "1", "--pretty=format:%cr", file], capture_output=True, text=True).stdout | |
flag_timestamp = int(subprocess.run(["git", "log", "-n", "1", "--pretty=format:%ct", file], capture_output=True, text=True).stdout) | |
if 'Buckets' in data: | |
flag_value = "complex" | |
else: | |
for bucket, value in data.items(): | |
flag_value = "%s in %s" % (value, bucket) | |
# print("| % 50s | % 50s | % 20s | % 15s |" % (file, flag, flag_value, flag_age)) | |
found.append({ | |
"file": file.removeprefix('Client/'), | |
"flag": flag, | |
"value": flag_value, | |
"age": flag_age, | |
"timestamp": flag_timestamp, | |
}) | |
found.sort(key=lambda item: item["timestamp"]) | |
sys.stdout.write("\x1b[1A\x1b[2K") # delete progress bar | |
for item in found: | |
print("| % 50s | % 50s | % 20s | % 15s |" % (item["file"], item["flag"], item["value"], item["age"])) | |
if __name__ == "__main__": | |
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment