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