From 11e8cac4719020c6dbed14e3a1f180ac2a095754 Mon Sep 17 00:00:00 2001 From: Jonas L Date: Thu, 2 Mar 2023 21:09:32 +0100 Subject: [PATCH] chore: add contributors listing tool (#2417) Yet another contributors listing script, sorry... --- tools/Makefile | 4 +- tools/contibutors.py | 108 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 1 deletion(-) create mode 100755 tools/contibutors.py diff --git a/tools/Makefile b/tools/Makefile index 30a3814e3..221fa7aa1 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -2,7 +2,9 @@ all: lint test include python.mk -PIP_INSTALL = +PIP_INSTALL = \ + requests \ + types-requests PYLINT_ARG = tools MYPY_ARG = . PYTEST_ARG = . diff --git a/tools/contibutors.py b/tools/contibutors.py new file mode 100755 index 000000000..1876041e2 --- /dev/null +++ b/tools/contibutors.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python3 +# pylint: disable=invalid-name + +import logging +from argparse import ArgumentParser +from os import environ +from subprocess import check_output +from typing import Any, Generator, List, Tuple + +from requests import Session + +logger = logging.getLogger("contributors") + +REPOSITORY = "libretime/libretime" +EXCLUDED_CONTRIBUTORS = { + "dependabot[bot]", + "invalid-email-address", + "libretime-bot", + "renovate-bot", + "renovate[bot]", + "web-flow", + "weblate", +} + + +def extract_date_range(commit_range: str) -> Tuple[str, str]: + output = check_output( + ["git", "log", "--reverse", "--format=%cI", commit_range], text=True + ) + lines = output.splitlines() + return lines[0], lines[-1] + + +def gh_get_commits( + client: Session, + since: str, + until: str, +) -> Generator[dict[str, Any], None, None]: + per_page = 100 + page = 1 + + while True: + logger.info("querying page %s", page) + with client.get( + f"https://api.github.com/repos/{REPOSITORY}/commits", + params={ # type: ignore[arg-type] + "per_page": per_page, + "page": page, + "since": since, + "until": until, + }, + timeout=5, + ) as resp: + resp.raise_for_status() + commits: List[dict] = resp.json() + yield from commits + + if len(commits) < per_page: + break + + page += 1 + + +def main(commit_range: str) -> int: + client = Session() + if "GITHUB_TOKEN" in environ: + logger.info("loading GITHUB_TOKEN") + github_token = environ["GITHUB_TOKEN"] + client.headers.update({"Authorization": f"token {github_token}"}) + + contributors = set() + + since, until = extract_date_range(commit_range) + logger.info("%s: %s => %s", commit_range, since, until) + + for commit in gh_get_commits(client, since, until): + if commit["author"] is None or commit["committer"] is None: + continue + + try: + author: str = commit["author"]["login"] + committer: str = commit["committer"]["login"] + contributors.add(author.casefold()) + contributors.add(committer.casefold()) + except (KeyError, TypeError) as exception: + logger.error("%s: %s", exception, commit) + + contributors -= EXCLUDED_CONTRIBUTORS + + print() + for contributor in sorted(contributors): + print(f"- @{contributor}") + print() + + return 0 + + +if __name__ == "__main__": + logging.basicConfig( + level=logging.INFO, + format="%(levelname)s:\t%(message)s", + ) + + parser = ArgumentParser() + parser.add_argument("commit_range") + + args = parser.parse_args() + raise SystemExit(main(commit_range=args.commit_range))