from dataclasses import dataclass import requests @dataclass class User: name: str organizations: list[str] @dataclass class Commit: message: str user: User additions: int deletions: int def call_with_query(query, token): url = "https://api.github.com/graphql" r = requests.post(url, json={"query": query}, headers={"Authorization": f"Bearer {token}"}) return r.json() def get_tag_commit_date(token, repository, tag): owner, name = repository.split("/") query = f""" query GetTagCommit {{ repository(owner: "{owner}", name: "{name}"){{ object(expression: "{tag}") {{ ... on Commit {{ oid message committedDate author {{ user {{ login }} }} }} }} }} }} """ response = call_with_query(query, token) try: repository = response["data"]["repository"]["object"] if repository is None: if "errors" in response: raise ValueError(response["errors"][0]["message"]) raise ValueError("Invalid tag. Does this tag exist?") committed_date = repository["committedDate"] except (KeyError, TypeError): raise ValueError("Invalid token. Does your token have the valid permissions?") return committed_date def get_commits(token, repository, branch, since): owner, name = repository.split("/") def get_page_result(next_page=""): query = f""" query GetCommits {{ repository(owner: "{owner}", name: "{name}"){{ nameWithOwner object(expression: "{branch}") {{ ... on Commit {{ oid history(first: 100, since: "{since}"{next_page}) {{ nodes {{ message deletions additions author {{ user {{ login organizations(first: 100) {{ nodes {{ name }} }} }} }} }} pageInfo {{ endCursor hasNextPage }} }} }} }} }} }} """ result = call_with_query(query, token) if "data" not in result: raise ValueError(result["errors"][0]["message"]) if result["data"]["repository"]["object"] is None: raise ValueError("Either the tag or the branch were incorrect.") nodes = result["data"]["repository"]["object"]["history"]["nodes"] cursor = result["data"]["repository"]["object"]["history"]["pageInfo"]["endCursor"] return nodes, cursor nodes, cursor = get_page_result() while cursor is not None: _nodes, cursor = get_page_result(f' after:"{cursor}"') nodes.extend(_nodes) commits = [] for node in nodes: if node["author"]["user"] is None: commits.append( Commit( message=node["message"].split("\n")[0], user=User(name="", organizations=[]), additions=node.get("additions"), deletions=node.get("deletions"), ) ) else: commits.append( Commit( message=node["message"].split("\n")[0], user=User( name=node["author"]["user"]["login"], organizations=[n["name"] for n in node["author"]["user"]["organizations"]["nodes"]], ), additions=node.get("additions"), deletions=node.get("deletions"), ) ) return commits