github.com/shashidharatd/test-infra@v0.0.0-20171006011030-71304e1ca560/gubernator/github/models.py (about)

     1  # Copyright 2016 The Kubernetes Authors.
     2  #
     3  # Licensed under the Apache License, Version 2.0 (the "License");
     4  # you may not use this file except in compliance with the License.
     5  # You may obtain a copy of the License at
     6  #
     7  #     http://www.apache.org/licenses/LICENSE-2.0
     8  #
     9  # Unless required by applicable law or agreed to in writing, software
    10  # distributed under the License is distributed on an "AS IS" BASIS,
    11  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  # See the License for the specific language governing permissions and
    13  # limitations under the License.
    14  
    15  import datetime
    16  import json
    17  
    18  import google.appengine.ext.ndb as ndb
    19  
    20  
    21  class GithubResource(ndb.Model):
    22      # A key holder used to define an entitygroup for
    23      # each Issue/PR, for easy ancestor queries.
    24      @staticmethod
    25      def make_key(repo, number):
    26          return ndb.Key(GithubResource, '%s %s' % (repo, number))
    27  
    28  
    29  def shrink(body):
    30      '''
    31      Recursively remove Github API urls from an object, to make it
    32      more human-readable.
    33      '''
    34      toremove = []
    35      for key, value in body.iteritems():
    36          if isinstance(value, basestring):
    37              if key.endswith('url'):
    38                  if (value.startswith('https://api.github.com/') or
    39                      value.startswith('https://avatars.githubusercontent.com')):
    40                      toremove.append(key)
    41          elif isinstance(value, dict):
    42              shrink(value)
    43          elif isinstance(value, list):
    44              for el in value:
    45                  if isinstance(el, dict):
    46                      shrink(el)
    47      for key in toremove:
    48          body.pop(key)
    49      return body
    50  
    51  
    52  class GithubWebhookRaw(ndb.Model):
    53      repo = ndb.StringProperty()
    54      number = ndb.IntegerProperty(indexed=False)
    55      event = ndb.StringProperty()
    56      timestamp = ndb.DateTimeProperty(auto_now_add=True)
    57      body = ndb.TextProperty(compressed=True)
    58  
    59      def to_tuple(self):
    60          return (self.event, shrink(json.loads(self.body)), float(self.timestamp.strftime('%s.%f')))
    61  
    62  
    63  def from_iso8601(t):
    64      return t and datetime.datetime.strptime(t, '%Y-%m-%dT%H:%M:%SZ')
    65  
    66  
    67  def make_kwargs(body, fields):
    68      kwargs = {}
    69      for field in fields:
    70          if field.endswith('_at'):
    71              kwargs[field] = from_iso8601(body[field])
    72          else:
    73              kwargs[field] = body[field]
    74      return kwargs
    75  
    76  
    77  class GHStatus(ndb.Model):
    78      # Key: {repo}\t{sha}\t{context}
    79      state = ndb.StringProperty(indexed=False)
    80      target_url = ndb.StringProperty(indexed=False)
    81      description = ndb.TextProperty()
    82  
    83      created_at = ndb.DateTimeProperty(indexed=False)
    84      updated_at = ndb.DateTimeProperty(indexed=False)
    85  
    86  
    87      @staticmethod
    88      def make_key(repo, sha, context):
    89          return ndb.Key(GHStatus, '%s\t%s\t%s' % (repo, sha, context))
    90  
    91      @staticmethod
    92      def make(repo, sha, context, **kwargs):
    93          return GHStatus(key=GHStatus.make_key(repo, sha, context), **kwargs)
    94  
    95      @staticmethod
    96      def query_for_sha(repo, sha):
    97          before = GHStatus.make_key(repo, sha, '')
    98          after = GHStatus.make_key(repo, sha, '\x7f')
    99          return GHStatus.query(GHStatus.key > before, GHStatus.key < after)
   100  
   101      @staticmethod
   102      def from_json(body):
   103          kwargs = make_kwargs(body,
   104              'sha context state target_url description '
   105              'created_at updated_at'.split())
   106          kwargs['repo'] = body['name']
   107          return GHStatus.make(**kwargs)
   108  
   109      @property
   110      def repo(self):
   111          return self.key.id().split('\t', 1)[0]
   112  
   113      @property
   114      def sha(self):
   115          return self.key.id().split('\t', 2)[1]
   116  
   117      @property
   118      def context(self):
   119          return self.key.id().split('\t', 2)[2]
   120  
   121  
   122  class GHIssueDigest(ndb.Model):
   123      # Key: {repo} {number}
   124      is_pr = ndb.BooleanProperty()
   125      is_open = ndb.BooleanProperty()
   126      involved = ndb.StringProperty(repeated=True)
   127      xref = ndb.StringProperty(repeated=True)
   128      payload = ndb.JsonProperty()
   129      updated_at = ndb.DateTimeProperty()
   130      head = ndb.StringProperty()
   131  
   132      @staticmethod
   133      def make_key(repo, number):
   134          return ndb.Key(GHIssueDigest, '%s %s' % (repo, number))
   135  
   136      @staticmethod
   137      def make(repo, number, is_pr, is_open, involved, payload, updated_at):
   138          return GHIssueDigest(key=GHIssueDigest.make_key(repo, number),
   139              is_pr=is_pr, is_open=is_open, involved=involved, payload=payload,
   140              updated_at=updated_at, head=payload.get('head'),
   141              xref=payload.get('xrefs', []))
   142  
   143      @staticmethod
   144      def get(repo, number):
   145          return GHIssueDigest.make_key(repo, number).get()
   146  
   147      @property
   148      def repo(self):
   149          return self.key.id().split()[0]
   150  
   151      @property
   152      def number(self):
   153          return int(self.key.id().split()[1])
   154  
   155      @staticmethod
   156      def find_head(repo, head):
   157          return GHIssueDigest.query(GHIssueDigest.key > GHIssueDigest.make_key(repo, ''),
   158                                     GHIssueDigest.key < GHIssueDigest.make_key(repo, '~'),
   159                                     GHIssueDigest.head == head)
   160  
   161      @staticmethod
   162      def find_xrefs(xref):
   163          return GHIssueDigest.query(GHIssueDigest.xref == xref)
   164  
   165  
   166  class GHUserState(ndb.Model):
   167      # Key: {github username}
   168      acks = ndb.JsonProperty()  # dict of issue keys => ack time (seconds since epoch)
   169  
   170      @staticmethod
   171      def make_key(user):
   172          return ndb.Key(GHUserState, user)
   173  
   174      @staticmethod
   175      def make(user, acks=None):
   176          return GHUserState(key=GHUserState.make_key(user), acks=acks or {})
   177  
   178  
   179  @ndb.transactional
   180  def save_if_newer(obj):
   181      assert obj.updated_at is not None
   182      old = obj.key.get()
   183      if old is None:
   184          obj.put()
   185          return True
   186      else:
   187          if old.updated_at is None or obj.updated_at >= old.updated_at:
   188              obj.put()
   189              return True
   190          return False