diff options
Diffstat (limited to 'Biz/Dragons/main.py')
-rwxr-xr-x | Biz/Dragons/main.py | 69 |
1 files changed, 39 insertions, 30 deletions
diff --git a/Biz/Dragons/main.py b/Biz/Dragons/main.py index bb10441..7813f45 100755 --- a/Biz/Dragons/main.py +++ b/Biz/Dragons/main.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +# : out dragons.py """ Analyze developer allocation across a codebase. """ @@ -10,15 +11,16 @@ import os import re import subprocess import sys +import typing -def find_user(line): +def find_user(line: str) -> typing.Any: """Given 'Ben Sima <ben@bsima.me>', finds `Ben Sima'. Returns the first matching string.""" return re.findall(r"^[^<]*", line)[0].strip() -def authors_for(path, active_users): +def authors_for(path: str, active_users: typing.List[str]) -> typing.Dict[str, str]: """Return a dictionary of {author: commits} for given path. Usernames not in the 'active_users' list will be filtered out.""" raw = subprocess.check_output( @@ -35,10 +37,10 @@ def authors_for(path, active_users): return data -def mailmap_users(): +def mailmap_users() -> typing.List[str]: """Returns users from the .mailmap file.""" users = [] - with open(".mailmap") as file: + with open(".mailmap", encoding="utf-8") as file: lines = file.readlines() for line in lines: users.append(find_user(line)) @@ -48,7 +50,7 @@ def mailmap_users(): MAX_SCORE = 10 -def score(blackhole, liability, good, total): +def score(blackhole: float, liability: float, good: int, total: int) -> float: "Calculate the score." weights = { "blackhole": 0.5, @@ -65,9 +67,10 @@ def score(blackhole, liability, good, total): ) -def get_args(): +def get_args() -> typing.Any: "Parse CLI arguments." cli = argparse.ArgumentParser(description=__doc__) + cli.add_argument("test", action="store_true", help="run the test suite") cli.add_argument("repo", default=".", help="the git repo to run on", metavar="REPO") cli.add_argument( "-b", @@ -88,7 +91,11 @@ def get_args(): help="print stale files (haven't been touched in 6 months)", ) cli.add_argument( - "-i", "--ignored", nargs="+", default=[], help="patterns to ignore in paths", + "-i", + "--ignored", + nargs="+", + default=[], + help="patterns to ignore in paths", ) cli.add_argument( "--active-users", @@ -106,19 +113,7 @@ def get_args(): return cli.parse_args() -def guard_git(repo): - "Guard against non-git repos." - is_git = subprocess.run( - ["git", "rev-parse"], - stderr=subprocess.PIPE, - stdout=subprocess.PIPE, - check=False, - ).returncode - if is_git != 0: - sys.exit(f"error: not a git repository: {repo}") - - -def staleness(path, now): +def staleness(path: str, now: datetime.datetime) -> int: "How long has it been since this file was touched?" timestamp = datetime.datetime.strptime( subprocess.check_output(["git", "log", "-n1", "--pretty=%aI", path]) @@ -133,7 +128,9 @@ def staleness(path, now): class Repo: "Represents a repo and stats for the repo." - def __init__(self, ignored_paths, active_users): + def __init__( + self, ignored_paths: typing.List[str], active_users: typing.List[str] + ) -> None: self.paths = [ p for p in subprocess.check_output(["git", "ls-files", "--no-deleted"]) @@ -158,7 +155,7 @@ class Repo: if _staleness > 180: self.stale[path] = _staleness - def print_blackholes(self, full): + def print_blackholes(self, full: bool) -> None: "Print number of blackholes, or list of all blackholes." # note: file renames may result in false positives n_blackhole = len(self.blackholes) @@ -167,7 +164,7 @@ class Repo: for path in self.blackholes: print(f" {path}") - def print_liabilities(self, full): + def print_liabilities(self, full: bool) -> None: "Print number of liabilities, or list of all liabilities." n_liabilities = len(self.liabilities) print(f"Liabilities: {n_liabilities}") @@ -175,20 +172,17 @@ class Repo: for path, authors in self.liabilities.items(): print(f" {path} ({', '.join(authors)})") - def print_score(self): + def print_score(self) -> None: "Print the overall score." n_total = len(self.stats.keys()) n_blackhole = len(self.blackholes) n_liabilities = len(self.liabilities) n_good = n_total - n_blackhole - n_liabilities print("Total:", n_total) - print( - "Score: {:.2f}/{}".format( - score(n_blackhole, n_liabilities, n_good, n_total), MAX_SCORE - ) - ) + this_score = score(n_blackhole, n_liabilities, n_good, n_total) + print(f"Score: {this_score:.2f}/{MAX_SCORE}".format()) - def print_stale(self, full): + def print_stale(self, full: bool) -> None: "Print stale files" n_stale = len(self.stale) print(f"Stale files: {n_stale}") @@ -197,8 +191,23 @@ class Repo: print(f" {path} ({days} days)") +def guard_git(repo: Repo) -> None: + "Guard against non-git repos." + is_git = subprocess.run( + ["git", "rev-parse"], + stderr=subprocess.PIPE, + stdout=subprocess.PIPE, + check=False, + ).returncode + if is_git != 0: + sys.exit(f"error: not a git repository: {repo}") + + if __name__ == "__main__": ARGS = get_args() + if ARGS.test: + print("ok") + sys.exit() logging.basicConfig(stream=sys.stderr, level=ARGS.verbosity.upper()) logging.debug("starting") |