Esempio n. 1
0
def start_ci():
    """
    Function that track the event occuring at the repository
    Events that are tracked:
    Push: Run the tests and update last commit
    Pull Request: If it is a pr, run the tests
    Issues: Update the status of recoded issues
    """
    if request.method != 'POST':
        return 'OK'
    else:
        abort_code = 418

        event = request.headers.get('X-GitHub-Event')
        if event == "ping":
            return json.dumps({'msg': 'Hi!'})

        x_hub_signature = request.headers.get('X-Hub-Signature')
        if not is_valid_signature(x_hub_signature, request.data,
                                  g.github['ci_key']):
            g.log.warning('CI signature failed: %s' % x_hub_signature)
            abort(abort_code)

        payload = request.get_json()
        if payload is None:
            g.log.warning('CI payload is empty: %s' % payload)
            abort(abort_code)

        gh = GitHub(access_token=g.github['bot_token'])
        repository = gh.repos(g.github['repository_owner'])(
            g.github['repository'])

        if event == "push":
            # If it's a push, and the 'after' hash is available, then it's
            # a commit, so run the tests
            if 'after' in payload:
                commit = payload['after']
                gh_commit = repository.statuses(commit)
                # Update the db to the new last commit
                ref = repository.git().refs('heads/master').get()
                last_commit = GeneralData.query.filter(
                    GeneralData.key == 'last_commit').first()
                for platform in TestPlatform.values():
                    commit_name = 'fetch_commit_' + platform
                    fetch_commit = GeneralData.query.filter(
                        GeneralData.key == commit_name).first()
                    if fetch_commit is None:
                        prev_commit = GeneralData(commit_name,
                                                  last_commit.value)
                        g.db.add(prev_commit)
                last_commit.value = ref['object']['sha']
                g.db.commit()
                queue_test(g.db, repository, gh_commit, commit,
                           TestType.commit)
            else:
                g.log.warning('Unknown push type! Dumping payload for '
                              'analysis')
                g.log.debug(payload)

        elif event == "pull_request":
            # If it's a PR, run the tests
            if payload['action'] == 'opened':
                try:
                    commit = payload['pull_request']['head']['sha']
                except KeyError:
                    g.log.critical(
                        "Didn't find a SHA value for a newly opened PR!")
                    g.log.debug(payload)
                    commit = ''
            elif payload['action'] == 'closed':
                g.log.debug('PR was closed, no after hash available')
                commit = ''
            else:
                try:
                    commit = payload['after']
                except KeyError:
                    g.log.critical("Didn't find the after SHA for the "
                                   "updated commit!")
                    g.log.debug(payload)
                    commit = ''
            pr_nr = payload['pull_request']['number']
            gh_commit = repository.statuses(commit)
            if payload['action'] == 'opened':
                # Run initial tests
                queue_test(g.db,
                           repository,
                           gh_commit,
                           commit,
                           TestType.pull_request,
                           pr_nr=pr_nr)
            elif payload['action'] == 'synchronize':
                # Run/queue a new test set
                queue_test(g.db,
                           repository,
                           gh_commit,
                           commit,
                           TestType.pull_request,
                           pr_nr=pr_nr)
            elif payload['action'] == 'closed':
                # Cancel running queue
                tests = Test.query.filter(Test.pr_nr == pr_nr).all()
                for test in tests:
                    # Add canceled status only if the test hasn't started yet
                    if len(test.progress) > 0:
                        continue
                    progress = TestProgress(test.id,
                                            TestStatus.canceled, "PR closed",
                                            datetime.datetime.now())
                    g.db.add(progress)
                    repository.statuses(test.commit).post(
                        state=Status.FAILURE,
                        description="Tests canceled",
                        context="CI - %s" % test.platform.value,
                        target_url=url_for('test.by_id',
                                           test_id=test.id,
                                           _external=True))
            elif payload['action'] == 'reopened':
                # Run tests again
                queue_test(g.db, repository, gh_commit, commit,
                           TestType.pull_request)
        elif event == "issues":
            issue_data = payload['issue']
            issue = Issue.query.filter(
                Issue.issue_id == issue_data['number']).first()
            if issue is not None:
                issue.title = issue_data['title']
                issue.status = issue_data['state']
                g.db.commit()
        else:
            # Unknown type
            g.log.warning('CI unrecognized event: %s' % event)

        return json.dumps({'msg': 'EOL'})
def start_ci():
    """
    Gets called when the webhook on GitHub is triggered. Reaction to the next events need to be processed
    (after verification):
        - Ping (for fun)
        - Push
        - Pull Request
        - Issues
    """
    if request.method != 'POST':
        return 'OK'
    else:
        abort_code = 418

        event = request.headers.get('X-GitHub-Event')
        if event == "ping":
            return json.dumps({'msg': 'Hi!'})

        x_hub_signature = request.headers.get('X-Hub-Signature')

        if not is_valid_signature(x_hub_signature, request.data,
                                  g.github['ci_key']):
            g.log.warning(
                'CI signature failed: {sig}'.format(sig=x_hub_signature))
            abort(abort_code)

        payload = request.get_json()

        if payload is None:
            g.log.warning(
                'CI payload is empty: {payload}'.format(payload=payload))
            abort(abort_code)

        gh = GitHub(access_token=g.github['bot_token'])
        repository = gh.repos(g.github['repository_owner'])(
            g.github['repository'])

        if event == "push":
            # If it's a push, and the 'after' hash is available, then it's a commit, so run the tests
            if 'after' in payload:
                commit = payload['after']
                gh_commit = repository.statuses(commit)
                # Update the db to the new last commit
                ref = repository.git().refs('heads/master').get()
                last_commit = GeneralData.query.filter(
                    GeneralData.key == 'last_commit').first()
                for platform in TestPlatform.values():
                    commit_name = 'fetch_commit_' + platform
                    fetch_commit = GeneralData.query.filter(
                        GeneralData.key == commit_name).first()

                    if fetch_commit is None:
                        prev_commit = GeneralData(commit_name,
                                                  last_commit.value)
                        g.db.add(prev_commit)

                last_commit.value = ref['object']['sha']
                g.db.commit()
                queue_test(g.db, gh_commit, commit, TestType.commit)
            else:
                g.log.warning(
                    'Unknown push type! Dumping payload for analysis')
                g.log.debug(payload)

        elif event == "pull_request":
            # If it's a valid PR, run the tests
            commit = ''
            gh_commit = None
            pr_nr = payload['pull_request']['number']
            if payload['action'] in ['opened', 'synchronize', 'reopened']:
                try:
                    commit = payload['pull_request']['head']['sha']
                    gh_commit = repository.statuses(commit)
                except KeyError:
                    g.log.critical(
                        "Didn't find a SHA value for a newly opened PR!")
                    g.log.debug(payload)

                # Check if user blacklisted
                user_id = payload['pull_request']['user']['id']
                if BlockedUsers.query.filter(
                        BlockedUsers.userID == user_id).first() is not None:
                    g.log.critical("User Blacklisted")
                    gh_commit.post(
                        state=Status.ERROR,
                        description=
                        "CI start aborted. You may be blocked from accessing this functionality",
                        target_url=url_for('home.index', _external=True))
                    return 'ERROR'

                queue_test(g.db,
                           gh_commit,
                           commit,
                           TestType.pull_request,
                           pr_nr=pr_nr)

            elif payload['action'] == 'closed':
                g.log.debug('PR was closed, no after hash available')
                # Cancel running queue
                tests = Test.query.filter(Test.pr_nr == pr_nr).all()
                for test in tests:
                    # Add canceled status only if the test hasn't started yet
                    if len(test.progress) > 0:
                        continue
                    progress = TestProgress(test.id,
                                            TestStatus.canceled, "PR closed",
                                            datetime.datetime.now())
                    g.db.add(progress)
                    repository.statuses(test.commit).post(
                        state=Status.FAILURE,
                        description="Tests canceled",
                        context="CI - {name}".format(name=test.platform.value),
                        target_url=url_for('test.by_id',
                                           test_id=test.id,
                                           _external=True))

        elif event == "issues":
            issue_data = payload['issue']
            issue = Issue.query.filter(
                Issue.issue_id == issue_data['number']).first()

            if issue is not None:
                issue.title = issue_data['title']
                issue.status = issue_data['state']
                g.db.commit()

        else:
            # Unknown type
            g.log.warning('CI unrecognized event: {event}'.format(event=event))

        return json.dumps({'msg': 'EOL'})
Esempio n. 3
0
def start_ci():
    if request.method != 'POST':
        return 'OK'
    else:
        abort_code = 418

        event = request.headers.get('X-GitHub-Event')
        if event == "ping":
            return json.dumps({'msg': 'Hi!'})

        x_hub_signature = request.headers.get('X-Hub-Signature')
        if not is_valid_signature(x_hub_signature, request.data,
                                  g.github['ci_key']):
            g.log.warning('CI signature failed: %s' % x_hub_signature)
            abort(abort_code)

        payload = request.get_json()
        if payload is None:
            g.log.warning('CI payload is empty: %s' % payload)
            abort(abort_code)

        gh = GitHub(access_token=g.github['bot_token'])

        if event == "push":  # If it's a push, run the tests
            commit = payload['after']
            gh_commit = gh.repos(g.github['repository_owner'])(
                g.github['repository']).statuses(commit)
            queue_test(g.db, gh_commit, commit, TestType.commit)
            # Update the db to the new last commit
            ref = gh.repos(g.github['repository_owner'])(
                g.github['repository']).git().refs('heads/master').get()
            last_commit = GeneralData.query.filter(GeneralData.key ==
                                                   'last_commit').first()
            last_commit.value = ref['object']['sha']
            g.db.commit()

        elif event == "pull_request":  # If it's a PR, run the tests
            if payload['action'] == 'opened':
                try:
                    commit = payload['pull_request']['head']['sha']
                except KeyError:
                    g.log.critical(
                        "Didn't find a SHA value for a newly opened PR!")
                    g.log.debug(payload)
                    commit = ''
            elif payload['action'] == 'closed':
                g.log.debug('PR was closed, no after hash available')
                commit = ''
            else:
                try:
                    commit = payload['after']
                except KeyError:
                    g.log.critical("Didn't find the after SHA for the "
                                   "updated commit!")
                    g.log.debug(payload)
                    commit = ''
            pr_nr = payload['pull_request']['number']
            gh_commit = gh.repos(g.github['repository_owner'])(
                g.github['repository']).statuses(commit)
            if payload['action'] == 'opened':
                # Run initial tests
                queue_test(g.db, gh_commit, commit, TestType.pull_request,
                           pr_nr=pr_nr)
            elif payload['action'] == 'synchronize':
                # Run/queue a new test set
                queue_test(g.db, gh_commit, commit, TestType.pull_request,
                           pr_nr=pr_nr)
            elif payload['action'] == 'closed':
                # Cancel running queue
                tests = Test.query.filter(Test.pr_nr == pr_nr).all()
                for test in tests:
                    # Add canceled status only if the test hasn't started yet
                    if len(test.progress) > 0:
                        continue
                    progress = TestProgress(test.id, TestStatus.canceled,
                                            "PR closed",
                                            datetime.datetime.now())
                    g.db.add(progress)
                    gh.repos(g.github['repository_owner'])(
                        g.github['repository']).statuses(test.commit).post(
                        state=Status.FAILURE, description="Tests canceled",
                        context="CI - %s" % test.platform.value,
                        target_url=url_for(
                            'test.by_id', test_id=test.id, _external=True))
            elif payload['action'] == 'reopened':
                # Run tests again
                queue_test(g.db, gh_commit, commit, TestType.pull_request)
        else:
            # Unknown type
            g.log.warning('CI unrecognized event: %s' % event)

        return json.dumps({'msg': 'EOL'})