lysandre/github-release
13
1from dataclasses import dataclass2from tqdm import tqdm3import requests4 5 6@dataclass7class User:8 name: str9 organizations: list[str]10 11 12@dataclass13class Commit:14 message: str15 user: User16 additions: int17 deletions: int18 19 20def call_with_query(query, token):21 url = 'https://api.github.com/graphql'22 r = requests.post(url, json={'query': query}, headers={'Authorization': f'Bearer {token}'})23 return r.json()24 25 26def get_tag_commit_date(token, repository, tag):27 owner, name = repository.split('/')28 query = f"""29 query GetTagCommit {{30 repository(owner: "{owner}", name: "{name}"){{31 object(expression: "{tag}") {{32 ... on Commit {{33 oid34 message35 committedDate36 author {{37 user {{38 login39 }}40 }}41 }}42 }}43 }}44 }}45 """46 47 response = call_with_query(query, token)48 49 try:50 repository = response['data']['repository']['object']51 52 if repository is None:53 if 'errors' in response:54 raise ValueError(response['errors'][0]['message'])55 raise ValueError('Invalid tag. Does this tag exist?')56 57 committed_date = repository['committedDate']58 except (KeyError, TypeError):59 raise ValueError('Invalid token. Does your token have the valid permissions?')60 61 return committed_date62 63 64def get_commits(token, repository, branch, since):65 owner, name = repository.split('/')66 67 def get_page_result(next_page=''):68 query = f"""69 query GetCommits {{70 repository(owner: "{owner}", name: "{name}"){{71 nameWithOwner72 object(expression: "{branch}") {{73 ... on Commit {{74 oid75 history(first: 100, since: "{since}"{next_page}) {{76 nodes {{77 message78 deletions79 additions80 author {{81 user {{82 login83 organizations(first: 100) {{84 nodes {{85 name86 }}87 }}88 }}89 }}90 }}91 pageInfo {{92 endCursor93 hasNextPage94 }}95 }}96 }}97 }}98 }}99 }}100 """101 result = call_with_query(query, token)102 103 if 'data' not in result:104 raise ValueError(result['errors'][0]['message'])105 106 if result['data']['repository']['object'] is None:107 raise ValueError("Either the tag or the branch were incorrect.")108 109 nodes = result['data']['repository']['object']['history']['nodes']110 cursor = result['data']['repository']['object']['history']['pageInfo']['endCursor']111 return nodes, cursor112 113 nodes, cursor = get_page_result()114 115 while cursor is not None:116 _nodes, cursor = get_page_result(f' after:"{cursor}"')117 nodes.extend(_nodes)118 119 120 commits = []121 for node in tqdm(nodes):122 try:123 if node['author']['user'] is None:124 commits.append(Commit(125 message=node['message'].split('\n')[0],126 user=User(name='<NOT FOUND>', organizations=[]),127 additions=node.get('additions'),128 deletions=node.get('deletions')129 ))130 else:131 commits.append(Commit(132 message=node['message'].split('\n')[0],133 user=User(name=node['author']['user']['login'], organizations=[n['name'] for n in node['author']['user']['organizations']['nodes']]),134 additions=node.get('additions'),135 deletions=node.get('deletions')136 ))137 except TypeError:138 print(f"Failed processing {node}")139 140 return commits141 