summaryrefslogtreecommitdiff
path: root/Biz/Dragons
diff options
context:
space:
mode:
Diffstat (limited to 'Biz/Dragons')
-rwxr-xr-xBiz/Dragons/main.py69
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")