Beispiel #1
0
    def get(self):
        """
        Gets the list of open tasks associated with quarantined tests. We find
        them based on the fact that they're always created by the same
        bot/user.
        """

        try:
            quarantine_user = current_app.config['QUARANTINE_PHID']
            if not quarantine_user:
                return self.respond({
                    'fetched_data_from_phabricator': False
                })

            request = PhabricatorClient()
            request.connect()
            task_info = request.call('maniphest.query', {'authorPHIDs': [quarantine_user]})

            # we need to get the names of the task owners too
            user_info = {}
            owner_phids = [t['ownerPHID'] for t in task_info.values() if t.get('ownerPHID')]
            if owner_phids:
                user_info = request.call('phid.query', {'phids': owner_phids})

            return self.respond({
                'fetched_data_from_phabricator': True,
                'tasks': task_info,
                'users': user_info
            })

        except requests.exceptions.ConnectionError:
            return 'Unable to connect to Phabricator', 503
Beispiel #2
0
    def get(self, author_id):
        authors = Author.find(author_id, get_current_user())
        if not authors and author_id == 'me':
            return '''Either there is no current user or you are not in the
              author table''', 401
        elif not authors:
            return 'author not found', 404

        try:
            author_email = authors[0].email
            request = PhabricatorClient()
            request.connect()
            user_info = request.call('user.query', {'emails': [author_email]})

            if not user_info:
                return 'phabricator: %s not found' % author_email, 404

            author_phid = user_info[0]["phid"]

            diff_info = request.call('differential.query', {
                'authors': [author_phid],
                'status': "status-open"
            })

            diff_info.sort(key=lambda k: -1 * int(k['dateModified']))

        except requests.exceptions.ConnectionError:
            return 'Unable to connect to Phabricator', 503

        if not diff_info:
            # No diffs, no point in trying to find builds.
            return self.respond([])

        rows = list(db.session.query(
            PhabricatorDiff, Build
        ).join(
            Build, Build.source_id == PhabricatorDiff.source_id
        ).filter(
            PhabricatorDiff.revision_id.in_([d['id'] for d in diff_info])
        ))

        serialized_builds = zip(
            self.serialize([row.Build for row in rows]),
            [row.PhabricatorDiff for row in rows]
        )

        builds_map = defaultdict(list)
        for build, phabricator_diff in serialized_builds:
            builds_map[str(phabricator_diff.revision_id)].append(build)

        for d in diff_info:
            d['builds'] = builds_map[str(d['id'])]

        return self.respond(diff_info)
Beispiel #3
0
    def get(self):
        """
        Gets the list of open tasks associated with quarantined tests. We find
        them based on the fact that they're always created by the same
        bot/user.
        """

        try:
            quarantine_user = current_app.config['QUARANTINE_PHID']
            if not quarantine_user:
                return self.respond({'fetched_data_from_phabricator': False})

            request = PhabricatorClient()
            request.connect()
            task_info = request.call('maniphest.query',
                                     {'authorPHIDs': [quarantine_user]})

            # we need to get the names of the task owners too
            user_info = {}
            owner_phids = [
                t['ownerPHID'] for t in task_info.values()
                if t.get('ownerPHID')
            ]
            if owner_phids:
                user_info = request.call('phid.query', {'phids': owner_phids})

            return self.respond({
                'fetched_data_from_phabricator': True,
                'tasks': task_info,
                'users': user_info
            })

        except requests.exceptions.ConnectionError:
            return 'Unable to connect to Phabricator', 503
Beispiel #4
0
    def get(self, author_id):
        if author_id == 'me' and not get_current_user():
            return error('Must be logged in to ask about yourself',
                         http_code=401)
        authors = Author.find(author_id, get_current_user())
        if not authors:
            return self.respond([])

        try:
            author_email = authors[0].email
            request = PhabricatorClient()
            request.connect()
            user_info = request.call('user.query', {'emails': [author_email]})

            if not user_info:
                return 'phabricator: %s not found' % author_email, 404

            author_phid = user_info[0]["phid"]

            diff_info = request.call('differential.query', {
                'authors': [author_phid],
                'status': "status-open"
            })

            diff_info.sort(key=lambda k: -1 * int(k['dateModified']))

        except requests.exceptions.ConnectionError:
            return 'Unable to connect to Phabricator', 503

        if not diff_info:
            # No diffs, no point in trying to find builds.
            return self.respond([])

        rows = list(
            db.session.query(PhabricatorDiff, Build).join(
                Build, Build.source_id == PhabricatorDiff.source_id).filter(
                    PhabricatorDiff.revision_id.in_(
                        [d['id'] for d in diff_info])))

        serialized_builds = zip(self.serialize([row.Build for row in rows]),
                                [row.PhabricatorDiff for row in rows])

        builds_map = defaultdict(list)
        for build, phabricator_diff in serialized_builds:
            builds_map[str(phabricator_diff.revision_id)].append(build)

        for d in diff_info:
            d['builds'] = builds_map[str(d['id'])]

        return self.respond(diff_info)
def build_finished_handler(build_id, **kwargs):
    build = Build.query.get(build_id)
    if build is None:
        return

    if build.tags and 'arc test' in build.tags:
        # 'arc test' builds have an associated Phabricator diff, but
        # aren't necessarily for the diff under review, so we don't
        # want to notify with them.
        return

    options = get_options(build.project_id)
    if options.get('phabricator.notify', '0') != '1':
        return

    target = build.target
    is_diff_build = target and target.startswith(u'D')
    is_commit_build = (build.source is not None and build.source.is_commit()
                       and build.tags and 'commit' in build.tags)

    phab = PhabricatorClient()

    if options.get('phabricator.coverage',
                   '0') == '1' and (is_diff_build or is_commit_build):
        coverage = merged_coverage_data(get_coverage_by_build_id(build_id))
        if coverage:
            if is_diff_build:
                logger.info("Posting coverage to %s", target)
                post_diff_coverage(target[1:], coverage, phab)
            elif is_commit_build:
                # commits update diffs in phabricator, so post the coverage there too
                revision_id = parse_revision_id(build.message)
                if revision_id:
                    post_diff_coverage(revision_id, coverage, phab)

                callsign, branch, commit = commit_details(build.source)
                if callsign and commit:
                    logger.info("Posting coverage to %s, %s, %s", callsign,
                                branch, commit)
                    post_commit_coverage(callsign, branch, commit, coverage,
                                         phab)

    if not is_diff_build:
        # Not a diff build
        return

    builds = list(
        Build.query.filter(Build.collection_id == build.collection_id))

    # Exit if there are no builds for the given build_id, or any build hasn't
    # finished.
    if not builds or any(map(lambda b: b.status != Status.finished, builds)):
        return

    # if comment has already been posted for this set of builds, don't do anything
    if _comment_posted_for_collection_of_build(build):
        return

    context = build_context_lib.get_collection_context(builds)

    message = '\n\n'.join(
        [_get_message_for_build_context(x) for x in context['builds']])

    post_comment(target, message, phab)
Beispiel #6
0
def build_finished_handler(build_id, **kwargs):
    build = Build.query.get(build_id)
    if build is None:
        return

    if build_type.is_arc_test_build(build):
        # 'arc test' builds have an associated Phabricator diff, but
        # aren't necessarily for the diff under review, so we don't
        # want to notify with them.
        return

    options = get_options(build.project_id)
    if options.get('phabricator.notify', '0') != '1':
        return

    target = build.target
    is_diff_build = build_type.is_phabricator_diff_build(build)
    is_commit_build = build_type.is_initial_commit_build(build)

    phab = PhabricatorClient()

    if options.get('phabricator.coverage',
                   '0') == '1' and (is_diff_build or is_commit_build):
        coverage = merged_coverage_data(get_coverage_by_build_id(build_id))
        if coverage:
            if is_diff_build:
                logger.info("Posting coverage to %s", target)
                post_diff_coverage(target[1:], coverage, phab)
            elif is_commit_build:
                # commits update diffs in phabricator, so post the coverage there too
                revision_id = parse_revision_id(build.message)
                if revision_id:
                    post_diff_coverage(revision_id, coverage, phab)

                callsign, branch, commit = commit_details(build.source)
                if callsign and commit:
                    logger.info("Posting coverage to %s, %s, %s", callsign,
                                branch, commit)
                    post_commit_coverage(callsign, branch, commit, coverage,
                                         phab)

    if not is_diff_build:
        # Not a diff build
        return

    builds = list(
        Build.query.filter(Build.collection_id == build.collection_id))

    # Filter collection of builds down to only consider/report builds for
    # projects with phabricator.notify set.
    options = ProjectOptionsHelper.get_options([b.project for b in builds],
                                               ['phabricator.notify'])
    builds = [
        b for b in builds
        if options[b.project.id].get('phabricator.notify', '0') == '1'
    ]

    # Exit if there are no builds for the given build_id, or any build hasn't
    # finished.
    if not builds or any(map(lambda b: b.status != Status.finished, builds)):
        return

    # if comment has already been posted for this set of builds, don't do anything
    if _comment_posted_for_collection_of_build(build):
        return

    context = build_context_lib.get_collection_context(builds)

    good_builds = [
        b for b in context.builds if b['build'].result == Result.passed
    ]
    bad_builds = [
        b for b in context.builds if b['build'].result != Result.passed
    ]

    message = ""
    if bad_builds:
        message += '(IMPORTANT) Failing builds!\n\n'
        message += '\n'.join(
            [_get_message_for_build_context(x) for x in bad_builds])
    if good_builds:
        if bad_builds:
            message += '\n\n'
        message += '(NOTE) Passing builds:\n\n'
        message += '\n'.join(
            [_get_message_for_build_context(x) for x in good_builds])

    post_comment(target, message, phab)
    def get(self, diff_ident):
        if not diff_ident.startswith('D') or not diff_ident[1:].isdigit():
            return error('diff id not valid')

        # grab diff info from phabricator.
        phabricator_info = {}
        try:
            request = PhabricatorClient()
            request.connect()

            phabricator_info = request.call('differential.query',
                                            {'ids': [int(diff_ident[1:])]})
            if len(phabricator_info) == 0:
                return error('%s not found in phabricator' % diff_ident,
                             http_code=404)
            assert len(phabricator_info) == 1
            phabricator_info = phabricator_info[0]
            phabricator_info["fetched_data_from_phabricator"] = True
        except Exception as e:
            # If the phabricator call fails for whatever reason, we'll still
            # return the builds info from changes. We don't want changes to
            # be unusable if phabricator is down
            print e
            phabricator_info = {"fetched_data_from_phabricator": False}
            pass

        # TODO: if we want the name/email of the author of the diff, we'd have
        # to make another conduit call. Instead, we'll let the frontend rely
        # on the fact that any phabricator-tagged build always has the same
        # author as the diff

        # grab builds
        rows = list(
            db.session.query(Build, PhabricatorDiff).join(
                PhabricatorDiff,
                Build.source_id == PhabricatorDiff.source_id,
            ).filter(PhabricatorDiff.revision_id == diff_ident[1:]))

        build_ids = set([row.Build.id for row in rows])

        jobs = []
        if len(build_ids) > 0:
            jobs = self.serialize(
                list(Job.query.filter(Job.build_id.in_(build_ids))))

        serialized_builds = zip(self.serialize([row.Build for row in rows]),
                                [row.PhabricatorDiff for row in rows])

        build_info = {}
        for build, phabricator_diff in serialized_builds:
            # we may have multiple diffs within a single differential revision
            single_diff_id = phabricator_diff.diff_id
            if single_diff_id not in build_info:
                build_info[single_diff_id] = {
                    'id': phabricator_diff.id,
                    'builds': [],
                    'diff_id': phabricator_diff.diff_id,
                    'revision_id': phabricator_diff.revision_id,
                    'url': phabricator_diff.url,
                    'source_id': phabricator_diff.source_id,
                    'dateCreated': phabricator_diff.date_created
                }
            build['jobs'] = [
                j for j in jobs if j['build']['id'] == build['id']
            ]
            build_info[single_diff_id]['builds'].append(build)

        phabricator_info['changes'] = build_info

        return self.respond(phabricator_info)
Beispiel #8
0
    def get(self, diff_ident):
        if not diff_ident.startswith('D') or not diff_ident[1:].isdigit():
            return 400, 'diff id not valid'

        # grab diff info from phabricator.
        phabricator_info = {}
        try:
            request = PhabricatorClient()
            request.connect()

            phabricator_info = request.call('differential.query', {
                'ids': [int(diff_ident[1:])]
            })
            if len(phabricator_info) == 0:
                return 404, '%s not found in phabricator' % diff_ident
            assert len(phabricator_info) == 1
            phabricator_info = phabricator_info[0]
            phabricator_info["fetched_data_from_phabricator"] = True
        except Exception as e:
            # If the phabricator call fails for whatever reason, we'll still
            # return the builds info from changes. We don't want changes to
            # be unusable if phabricator is down
            print e
            phabricator_info = {
                "fetched_data_from_phabricator": False
            }
            pass

        # TODO: if we want the name/email of the author of the diff, we'd have
        # to make another conduit call. Instead, we'll let the frontend rely
        # on the fact that any phabricator-tagged build always has the same
        # author as the diff

        # grab builds
        rows = list(db.session.query(
            Build, PhabricatorDiff
        ).join(
            PhabricatorDiff, Build.source_id == PhabricatorDiff.source_id,
        ).filter(
            PhabricatorDiff.revision_id == diff_ident[1:]
        ))

        build_ids = set([row.Build.id for row in rows])

        jobs = []
        if len(build_ids) > 0:
            jobs = self.serialize(list(Job.query.filter(
                Job.build_id.in_(build_ids)
            )))

        serialized_builds = zip(
            self.serialize([row.Build for row in rows]),
            [row.PhabricatorDiff for row in rows]
        )

        build_info = {}
        for build, phabricator_diff in serialized_builds:
            # we may have multiple diffs within a single differential revision
            single_diff_id = phabricator_diff.diff_id
            if single_diff_id not in build_info:
                build_info[single_diff_id] = {
                    'id': phabricator_diff.id,
                    'builds': [],
                    'diff_id': phabricator_diff.diff_id,
                    'revision_id': phabricator_diff.revision_id,
                    'url': phabricator_diff.url,
                    'source_id': phabricator_diff.source_id,
                    'dateCreated': phabricator_diff.date_created
                }
            build['jobs'] = [j for j in jobs if j['build']['id'] == build['id']]
            build_info[single_diff_id]['builds'].append(build)

        phabricator_info['changes'] = build_info

        return self.respond(phabricator_info, serialize=False)