Blame pagureCI/pagure_ci_server.py

Pierre-Yves Chibon dd38bc
#!/usr/bin/env python
Pierre-Yves Chibon dd38bc
# -*- coding: utf-8 -*-
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
"""
Pierre-Yves Chibon dd38bc
 (c) 2016 - Copyright Red Hat Inc
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
 Authors:
Pierre-Yves Chibon dd38bc
   Pierre-Yves Chibon <pingou@pingoured.fr></pingou@pingoured.fr>
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
This server listens to message sent via redis and send the corresponding
Pierre-Yves Chibon dd38bc
web-hook request.
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
Using this mechanism, we no longer block the main application if the
Pierre-Yves Chibon dd38bc
receiving end is offline or so.
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
"""
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
import datetime
Pierre-Yves Chibon dd38bc
import hashlib
Pierre-Yves Chibon dd38bc
import hmac
Pierre-Yves Chibon dd38bc
import json
Pierre-Yves Chibon dd38bc
import logging
Pierre-Yves Chibon dd38bc
import os
Pierre-Yves Chibon dd38bc
import requests
Pierre-Yves Chibon dd38bc
import time
Pierre-Yves Chibon dd38bc
import uuid
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
import six
Pierre-Yves Chibon dd38bc
import trollius
Pierre-Yves Chibon dd38bc
import trollius_redis
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
from kitchen.text.converters import to_bytes
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
log = logging.getLogger(__name__)
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
if 'PAGURE_CONFIG' not in os.environ \
Pierre-Yves Chibon dd38bc
        and os.path.exists('/etc/pagure/pagure.cfg'):
Pierre-Yves Chibon dd38bc
    print 'Using configuration file `/etc/pagure/pagure.cfg`'
Pierre-Yves Chibon dd38bc
    os.environ['PAGURE_CONFIG'] = '/etc/pagure/pagure.cfg'
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
import pagure
Pierre-Yves Chibon dd38bc
import pagure.lib
Pierre-Yves Chibon dd38bc
from pagure.exceptions import PagureEvException
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
_i = 0
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
@trollius.coroutine
Pierre-Yves Chibon dd38bc
def handle_messages():
Pierre-Yves Chibon dd38bc
    connection = yield trollius.From(trollius_redis.Connection.create(
Pierre-Yves Chibon dd38bc
        host='0.0.0.0', port=6379, db=0))
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
    # Create subscriber.
Pierre-Yves Chibon dd38bc
    subscriber = yield trollius.From(connection.start_subscribe())
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
    # Subscribe to channel.
Pierre-Yves Chibon dd38bc
    yield trollius.From(subscriber.subscribe(['pagure.ci']))
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
    # Inside a while loop, wait for incoming events.
Pierre-Yves Chibon dd38bc
    while True:
Pierre-Yves Chibon dd38bc
        reply = yield trollius.From(subscriber.next_published())
Pierre-Yves Chibon dd38bc
        log.info(
Pierre-Yves Chibon dd38bc
            'Received: %s on channel: %s',
Pierre-Yves Chibon dd38bc
            repr(reply.value), reply.channel)
Pierre-Yves Chibon dd38bc
        data = json.loads(reply.value)
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
        pr_id = data['pr']['id']
Pierre-Yves Chibon dd38bc
        project = data['pr']['project']['name']
Pierre-Yves Chibon dd38bc
        branch = data['pr']['branch_from']
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
        username = None
Pierre-Yves Chibon dd38bc
        projectname = data['pr']['project']
Pierre-Yves Chibon dd38bc
        if data['pr'].get('parent'):
Pierre-Yves Chibon dd38bc
            username, data['pr']['project']['user']['user']
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
        project = pagure.lib.get_project(
Pierre-Yves Chibon dd38bc
            session=pagure.SESSION, name=projectname, user=username)
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
        if not project:
Pierre-Yves Chibon dd38bc
            log.warning(
Pierre-Yves Chibon dd38bc
                'No project could be found from the message %s' % data)
Pierre-Yves Chibon dd38bc
            continue
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
        repo = data['pr'].get('remote_git')
Pierre-Yves Chibon dd38bc
        if not repo:
Pierre-Yves Chibon dd38bc
            base = pagure.APP.config['APP_URL']
Pierre-Yves Chibon dd38bc
            if base.endswith('/'):
Pierre-Yves Chibon dd38bc
                base[:-1]
Pierre-Yves Chibon dd38bc
            base += '/%s' % project.path
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
        log.info("Trigger on %s PR #%s from %s: %s",
Pierre-Yves Chibon dd38bc
                      project.fullname, pr_id, repo, branch)
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon 54793f
        url = project.ci_hook[0].ci_url
Pierre-Yves Chibon dd38bc
        if url.endswith('/'):
Pierre-Yves Chibon dd38bc
            url = url[:-1]
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
        if data['ci_type'] == 'jenkins':
Pierre-Yves Chibon dd38bc
            url += '/buildWithParameters'
Pierre-Yves Chibon dd38bc
            request.post(
Pierre-Yves Chibon dd38bc
                url,
Pierre-Yves Chibon dd38bc
                data={
Pierre-Yves Chibon dd38bc
                    'token': cfg.jenkins_token,
Pierre-Yves Chibon dd38bc
                    'cause': pr_id,
Pierre-Yves Chibon dd38bc
                    'REPO': repo.fullname,
Pierre-Yves Chibon dd38bc
                    'BRANCH': branch
Pierre-Yves Chibon dd38bc
                }
Pierre-Yves Chibon dd38bc
            )
Pierre-Yves Chibon dd38bc
        else:
Pierre-Yves Chibon dd38bc
            log.warning('Un-supported CI type')
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
def main():
Pierre-Yves Chibon dd38bc
    server = None
Pierre-Yves Chibon dd38bc
    try:
Pierre-Yves Chibon dd38bc
        loop = trollius.get_event_loop()
Pierre-Yves Chibon dd38bc
        tasks = [
Pierre-Yves Chibon dd38bc
            trollius.async(handle_messages()),
Pierre-Yves Chibon dd38bc
        ]
Pierre-Yves Chibon dd38bc
        loop.run_until_complete(trollius.wait(tasks))
Pierre-Yves Chibon dd38bc
        loop.run_forever()
Pierre-Yves Chibon dd38bc
    except KeyboardInterrupt:
Pierre-Yves Chibon dd38bc
        pass
Pierre-Yves Chibon dd38bc
    except trollius.ConnectionResetError:
Pierre-Yves Chibon dd38bc
        pass
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
    log.info("End Connection")
Pierre-Yves Chibon dd38bc
    loop.close()
Pierre-Yves Chibon dd38bc
    log.info("End")
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
if __name__ == '__main__':
Pierre-Yves Chibon dd38bc
    log = logging.getLogger("")
Pierre-Yves Chibon dd38bc
    formatter = logging.Formatter(
Pierre-Yves Chibon dd38bc
        "%(asctime)s %(levelname)s [%(module)s:%(lineno)d] %(message)s")
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
    # setup console logging
Pierre-Yves Chibon dd38bc
    log.setLevel(logging.DEBUG)
Pierre-Yves Chibon dd38bc
    ch = logging.StreamHandler()
Pierre-Yves Chibon dd38bc
    ch.setLevel(logging.DEBUG)
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
    aslog = logging.getLogger("asyncio")
Pierre-Yves Chibon dd38bc
    aslog.setLevel(logging.DEBUG)
Pierre-Yves Chibon dd38bc
Pierre-Yves Chibon dd38bc
    ch.setFormatter(formatter)
Pierre-Yves Chibon dd38bc
    log.addHandler(ch)
Pierre-Yves Chibon dd38bc
    main()