109 lines
2.7 KiB
Python
Executable File
109 lines
2.7 KiB
Python
Executable File
#!/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))
|