Home | History | Annotate | Download | only in bionicbb
      1 #
      2 # Copyright (C) 2015 The Android Open Source Project
      3 #
      4 # Licensed under the Apache License, Version 2.0 (the 'License');
      5 # you may not use this file except in compliance with the License.
      6 # You may obtain a copy of the License at
      7 #
      8 #      http://www.apache.org/licenses/LICENSE-2.0
      9 #
     10 # Unless required by applicable law or agreed to in writing, software
     11 # distributed under the License is distributed on an 'AS IS' BASIS,
     12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 # See the License for the specific language governing permissions and
     14 # limitations under the License.
     15 #
     16 import httplib
     17 import httplib2
     18 import logging
     19 import re
     20 import socket
     21 
     22 import apiclient.errors
     23 
     24 import gerrit
     25 import gmail
     26 import presubmit
     27 
     28 
     29 def get_gerrit_info(body):
     30     info = {}
     31     gerrit_pattern = r'^Gerrit-(\S+): (.+)$'
     32     for match in re.finditer(gerrit_pattern, body, flags=re.MULTILINE):
     33         info[match.group(1)] = match.group(2).strip()
     34     return info
     35 
     36 
     37 def process_message(msg, dry_run):
     38     try:
     39         body = gmail.get_body(msg)
     40         gerrit_info = get_gerrit_info(body)
     41         if not gerrit_info:
     42             logging.fatal('No Gerrit info found: %s', msg.subject)
     43         msg_type = gerrit_info['MessageType']
     44         handlers = {
     45             'comment': presubmit.handle_comment,
     46             'newchange': presubmit.handle_change,
     47             'newpatchset': presubmit.handle_change,
     48 
     49             'abandon': presubmit.skip_handler,
     50             'merge-failed': presubmit.skip_handler,
     51             'merged': presubmit.skip_handler,
     52             'restore': presubmit.skip_handler,
     53             'revert': presubmit.skip_handler,
     54         }
     55 
     56         message_type = gerrit_info['MessageType']
     57         if message_type in handlers:
     58             return handlers[message_type](gerrit_info, body, dry_run)
     59         else:
     60             logging.warning('MessageType %s unhandled.', msg_type)
     61         return False
     62     except NotImplementedError as ex:
     63         logging.error("%s", ex)
     64         return False
     65     except gerrit.GerritError as ex:
     66         change_id = gerrit_info['Change-Id']
     67         logging.error('Gerrit error (%d): %s %s', ex.code, change_id, ex.url)
     68         return ex.code == 404
     69 
     70 
     71 def get_and_process_jobs():
     72     dry_run = False
     73 
     74     gmail_service = gmail.build_service()
     75     msg_service = gmail_service.users().messages()
     76 
     77     # We run in a loop because some of the exceptions thrown here mean we just
     78     # need to retry. For errors where we should back off (typically any gmail
     79     # API exceptions), process_changes catches the error and returns normally.
     80     while True:
     81         try:
     82             process_changes(gmail_service, msg_service, dry_run)
     83             return
     84         except httplib.BadStatusLine:
     85             pass
     86         except httplib2.ServerNotFoundError:
     87             pass
     88         except socket.error:
     89             pass
     90 
     91 
     92 def process_changes(gmail_service, msg_service, dry_run):
     93     try:
     94         labels = gmail_service.users().labels().list(userId='me').execute()
     95         if not labels['labels']:
     96             logging.error('Could not retrieve Gmail labels')
     97             return
     98         label_id = gmail.get_gerrit_label(labels['labels'])
     99         if not label_id:
    100             logging.error('Could not find gerrit label')
    101             return
    102 
    103         for msg in gmail.get_all_messages(gmail_service, label_id):
    104             msg = msg_service.get(userId='me', id=msg['id']).execute()
    105             if process_message(msg, dry_run) and not dry_run:
    106                 msg_service.trash(userId='me', id=msg['id']).execute()
    107     except apiclient.errors.HttpError as ex:
    108         logging.error('API Client HTTP error: %s', ex)
    109