def queue_webhook(event_type, payload): if event_type == 'ping': # We want to return success on ping return elif event_type not in SUPPORTED_EVENTS: raise WebhookQueueError('Event type not supported') if payload is None: logger.warning( 'Received empty payload for {} event'.format(event_type)) return if 'repository' in payload: if payload['repository']['private']: logger.debug('Ignoring private repo...') # We only support public repos... return if payload['action'] not in HANDLED_PR_ACTIONS: # No need to raise an exception, just do nothing. return # Only take action on :scroll: comments for CLA reruns if payload['action'] == 'created': scroll_character = re.compile(ur'[^\U0001f4dc]+') try: comment = payload['comment']['body'] except UnicodeError: return if scroll_character.match(comment): logger.debug('Skipping unactionable comment') return full_repo_name = payload['repository']['full_name'] pull_request_number = payload.get('number') if pull_request_number is None: pull_request_number = payload['issue']['number'] _queue_repo_action(payload['action'], full_repo_name, pull_request_number)
def handle_webhook(message): data = json.loads(message['Body']) if data['action'] not in gh.HANDLED_PR_ACTIONS: logger.debug('Skipping unhandled action {}'.format(data['action'])) return if data['action'] == 'closed': logger.debug('Skipping closed action') return gh.update_pr_status(data['full_repo_name'], data['pr_number'])
def handle_message(client, queue_url): try: response = client.receive_message( QueueUrl=queue_url, AttributeNames=['SentTimestamp'], MaxNumberOfMessages=1, MessageAttributeNames=['All'], VisibilityTimeout=60, WaitTimeSeconds=10 ) if 'Messages' in response: messages = response['Messages'] message = messages[0] if 'type' not in message['MessageAttributes']: logger.error('SQS message does not have a type attribute.') return m_type = message['MessageAttributes']['type']['StringValue'] logger.debug('Received SQS message of type {}'.format(m_type)) if m_type == 'github_webhook': try: handle_webhook(message) except Exception: logger.exception( 'Failed to handle webhook SQS message' ) return elif m_type == 'signature': try: handle_signature(message) except Exception: logger.exception( 'Failed to handle signature SQS message' ) return else: logger.error( '{} is an unsupported message type.'.format(m_type) ) client.delete_message( QueueUrl=queue_url, ReceiptHandle=message['ReceiptHandle'] ) else: logger.debug('No messages, continuing') return except Exception: logger.exception('General error')
def update_prs_for_username(username): logger.debug('Updating PRs for {}'.format(username)) for pr in PullRequest.scan(username__eq=username): full_repo_name, pr_number = pr.pr.split(':') logger.debug('Adding an SQS message for {}, {}'.format( full_repo_name, pr_number)) try: # Fake a synchronize repo action, to enqueue a PR check _queue_repo_action('synchronize', full_repo_name, int(pr_number)) except Exception: logger.exception('Failed to queue SQS message for {}/{}'.format( full_repo_name, pr_number)) try: # We know this user signed, so we can get rid of this PR in dynamo. pr.delete() except Exception: logger.exception('Failed to delete PR {}/{}'.format( full_repo_name, pr_number))
def _get_addr(): if app.config['IP_HEADER']: addr = request.headers[app.config['IP_HEADER']] logger.debug('Using {}, got {}'.format(app.config['IP_HEADER'], addr)) elif app.config['USE_XFF']: addr = request.access_route[-1] logger.debug('Using XFF, got {}'.format(addr)) else: if request.remote_addr is None or request.remote_addr == '': addr = 'n/a' else: addr = request.remote_addr logger.debug('Using remote_addr, got {}'.format(addr)) return addr
def update_pr_status(full_repo_name, pr_number): # We care about the author of all commits in the PR, so we'll find the # author of every commit, and ensure they have signatures. logger.debug('Updating PR status for PR {}/{}'.format( full_repo_name, pr_number)) ghc = get_github_client() repo = ghc.get_repo(full_repo_name) pr = repo.get_pull(pr_number) commits = pr.get_commits() authors = [] author_without_login = False for commit in commits: last_commit = commit try: authors.append(commit.author.login) except Exception: logger.exception('Failed to access the login name for a commit') author_without_login = True if author_without_login: last_commit.create_status( 'failure', description=( 'An author in one of the commits has no associated github name' ), target_url=app.config['SITE_URL'], context=app.config['GITHUB_STATUS_CONTEXT']) return else: last_commit.create_status('pending', context=app.config['GITHUB_STATUS_CONTEXT']) authors = list(set(authors)) missing_authors = [] # Check to see if the authors have signed the CLA for author in authors: if check_org_membership(author): # User is in a github org we have an org CLA with logger.debug('User {} has an org CLA'.format(author)) continue try: Signature.get(author) except Signature.DoesNotExist: missing_authors.append(author) if missing_authors: for missing_author in missing_authors: # Save the PR info, so we can re-check the PR when signatures # occur. try: _pr = PullRequest(username=missing_author, pr='{0}:{1}'.format(repo.full_name, pr_number)) _pr.save(pr__null=True) logger.debug( 'Saved PR for missing author {}'.format(missing_author)) except PutError: logger.debug('Skipping creation of existing PR in dynamo.') msg = ('The following authors related to commits in this PR have' ' not signed the CLA: {0}') msg = msg.format(', '.join(missing_authors)) last_commit.create_status('failure', description=msg, target_url=app.config['SITE_URL'], context=app.config['GITHUB_STATUS_CONTEXT']) logger.debug('Submitted status for missing authors {0}.'.format( ','.join(missing_authors))) else: last_commit.create_status( 'success', description='All authors have signed the CLA.', target_url=app.config['SITE_URL'], context=app.config['GITHUB_STATUS_CONTEXT'])