github.com/hugh712/snapd@v0.0.0-20200910133618-1a99902bd583/check-pr-has-label.py (about)

     1  #!/usr/bin/python3
     2  
     3  import argparse
     4  import urllib.request
     5  import logging
     6  
     7  from html.parser import HTMLParser
     8  
     9  LABELS = {
    10      # PR label indicating that spread job should be skipped
    11      'LABEL_SKIP_SPREAD_JOB': "Skip spread",
    12      # PR label indicating that nested tests need to be executed
    13      'LABEL_RUN_SPREAD_NESTED': "Run nested"
    14      }
    15  
    16  
    17  class GithubLabelsParser(HTMLParser):
    18      def __init__(self):
    19          super().__init__()
    20          self.in_labels = False
    21          self.deep = 0
    22          self.labels = []
    23  
    24      def handle_starttag(self, tag, attributes):
    25          logging.debug(attributes)
    26  
    27          if not self.in_labels:
    28              attr_class = [attr[1] for attr in attributes if attr[0] == "class"]
    29              if len(attr_class) == 0:
    30                  return
    31              # labels are in separate div defined like:
    32              # <div class=".. labels .." .. >
    33              elems = attr_class[0].split(" ")
    34              if "labels" in elems:
    35                  self.in_labels = True
    36                  self.deep = 1
    37                  logging.debug("labels start")
    38          else:
    39              # nesting counter
    40              self.deep += 1
    41  
    42              # inside labels
    43              # label entry has
    44              # <a class=".." data-name="<label name>" />
    45              attr_data_name = [attr[1] for attr in attributes if attr[0] == "data-name"]
    46              if len(attr_data_name) == 0:
    47                  return
    48              data_name = attr_data_name[0]
    49              logging.debug("found label: %s", data_name)
    50              self.labels.append(data_name)
    51  
    52      def handle_endtag(self, tag):
    53          if self.in_labels:
    54              self.deep -= 1
    55              if self.deep < 1:
    56                  logging.debug("labels end")
    57                  self.in_labels = False
    58  
    59      def handle_data(self, data):
    60          if self.in_labels:
    61              logging.debug("data: %s", data)
    62  
    63  
    64  def grab_pr_labels(pr_number: int):
    65      # ideally we would use the github API - however we can't because:
    66      # a) its rate limiting and travis IPs hit the API a lot so we regularly
    67      #    get errors
    68      # b) using a API token is tricky because travis will not allow the secure
    69      #    vars for forks
    70      # so instead we just scrape the html title which is unlikely to change
    71      # radically
    72      parser = GithubLabelsParser()
    73      with urllib.request.urlopen(
    74          "https://github.com/snapcore/snapd/pull/{}".format(pr_number)
    75      ) as f:
    76          parser.feed(f.read().decode("utf-8"))
    77      return parser.labels
    78  
    79  
    80  def main():
    81      parser = argparse.ArgumentParser()
    82      parser.add_argument(
    83          "pr_number", 
    84          metavar="PR number", 
    85          help="the github PR number to check"
    86      )
    87      parser.add_argument(
    88          "label", 
    89          metavar="Label name", 
    90          choices=LABELS.keys(), 
    91          help="the github PR label to check"
    92      )
    93      parser.add_argument(
    94          "-d", "--debug", help="enable debug logging", action="store_true"
    95      )
    96      args = parser.parse_args()
    97  
    98      lvl = logging.INFO
    99      if args.debug:
   100          lvl = logging.DEBUG
   101      logging.basicConfig(level=lvl)
   102  
   103      pr_labels = grab_pr_labels(args.pr_number)
   104      print("pr labels:", pr_labels)
   105  
   106      if LABELS.get(args.label) not in pr_labels:
   107          raise SystemExit(1)
   108  
   109      print("Label: '{}' found in PR: '{}'".format(
   110          LABELS.get(args.label), args.pr_number))
   111  
   112  
   113  if __name__ == "__main__":
   114      main()