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()