k8s.io/test-infra@v0.0.0-20240520184403-27c6b4c223d8/experiment/graphql_issue_example.py (about) 1 #!/usr/bin/env python3 2 3 # Copyright 2017 The Kubernetes Authors. 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # you may not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 17 # USAGE: find_issues.py <github_token> 18 19 import sys 20 import json 21 import argparse 22 23 import requests 24 25 GITHUB_API_URL = "https://api.github.com" 26 27 28 def do_github_graphql_request(query, token, variables=None): 29 """performs a requests.put with the correct headers for a GitHub request. 30 31 see: https://developer.github.com/v4/ 32 33 Args: 34 query: the graphQL query string (excluding the variables section) 35 token: a GitHub API token string 36 variables: a dict of key=value variables that will be sent with the query 37 38 Returns: 39 A requests.Response object 40 """ 41 url = "https://api.github.com/graphql" 42 headers = { 43 "Authorization": "bearer " + token, 44 } 45 data = json.dumps({"query": query, "variables": json.dumps(variables)}) 46 return requests.post(url, headers=headers, data=data) 47 48 49 ISSUES_QUERY = """ 50 query($owner:String!, $name:String!, $after:String) { 51 repository(owner:$owner, name:$name) { 52 issues(first:100, after:$after) { 53 nodes{ 54 number 55 title 56 state 57 createdAt 58 labels(first:100){ 59 nodes{ 60 name 61 } 62 } 63 assignees(first:100){ 64 nodes{ 65 login 66 } 67 } 68 } 69 pageInfo{ 70 hasNextPage 71 endCursor 72 } 73 } 74 } 75 rateLimit { 76 limit 77 cost 78 remaining 79 resetAt 80 } 81 } 82 """ 83 84 def get_issues(owner, name, token, after=None): 85 """returns the result of do_github_graphql_request for a repo issues query. 86 87 This query requests the first 100 issues for a repo with the first 100 88 assignee logins and labels as well as the issue title, number, state, 89 creation time and the pageInfo for getting the next page of results 90 91 Args: 92 owner: the GitHub repo owner as in github.com/kubernetes/test-infra -> 93 owner="kubernetes" 94 name: this GitHub repo name as in github.com.kubernetes/test-infra -> 95 name = "test-infra" 96 token: a GitHub API token string 97 after: this should be None or the endCursor from pageInfo 98 99 Returns: 100 A requests.Response object 101 """ 102 variables = {"owner": owner, "name": name} 103 if after is not None: 104 variables["after"] = after 105 return do_github_graphql_request(ISSUES_QUERY, token, variables) 106 107 108 def get_all_issues(owner, name, token, issue_func, show_progress=False): 109 """gets all issues for a repo and applies issue_func to each. 110 111 Args: 112 owner: the GitHub repo owner as in github.com/kubernetes/test-infra -> 113 owner="kubernetes" 114 name: this GitHub repo name as in github.com.kubernetes/test-infra -> 115 name = "test-infra" 116 token: a GitHub API token string 117 issue_func: a function that takes one argument (the json of each issue) 118 this will be applied to each issue object returned by the GitHub API 119 show_progress: if True then print '.' for each request made 120 121 Raises: 122 IOError: an error occurred while getting the issues 123 """ 124 response = get_issues(owner, name, token) 125 while True: 126 if show_progress: 127 print(".", end="") 128 sys.stdout.flush() 129 if response.status_code != 200: 130 raise IOError("failed to fetch issues for repo: %s/%s" % (owner, name)) 131 response_json = response.json() 132 # NOTE: this will also contain the rate limit info if we need that later 133 # https://developer.github.com/v4/guides/resource-limitations/ 134 data = response_json["data"] 135 issues = data["repository"]["issues"]["nodes"] 136 for entry in issues: 137 issue_func(entry) 138 page_info = data["repository"]["issues"]["pageInfo"] 139 if not page_info["hasNextPage"]: 140 break 141 response = get_issues(owner, name, token, page_info["endCursor"]) 142 143 144 def main(): 145 parser = argparse.ArgumentParser() 146 parser.add_argument('--org', default='kubernetes') 147 parser.add_argument('--repo', default='test-infra') 148 parser.add_argument('token', help='GitHub auth token.') 149 options = parser.parse_args() 150 print("getting issues for: %s/%s" % (options.org, options.repo)) 151 # TODO: replace this with something more useful? 152 def issue_func(issue): 153 print(issue) 154 get_all_issues(options.org, options.repo, options.token, issue_func) 155 print("done") 156 157 158 if __name__ == "__main__": 159 main()