def create_or_update_build(self, build, event_id):
        """
        Use the Koji Task Result to create or update a ContainerKojiBuild.

        :param dict build: the build represented in Freshmaker being created or updated
        :param int event_id: the id of the Freshmaker event
        :return: the created/updated ContainerKojiBuild or None if it cannot be created
        :rtype: ContainerKojiBuild or None
        """
        # Builds in Koji only exist when the Koji task this Freshmaker build represents completes
        if build['state_name'] != 'DONE':
            log.debug(
                'Skipping build update for event {0} because the build is not complete yet'
                .format(event_id))
            return None
        try:
            koji_task_result = self.koji_session.getTaskResult(
                build['build_id'])
        except Exception:
            log.error('Failed to get the Koji task result with ID {0}'.format(
                build['build_id']))
            raise

        if not koji_task_result.get('koji_builds'):
            log.warn(
                'The task result of {0} does not contain the koji_builds key'.
                format(build['build_id']))
            return None
        # The ID is returned as a string so it must be cast to an int
        koji_build_id = int(koji_task_result['koji_builds'][0])
        # It's always going to be a container build when the build comes from Freshmaker, so we can
        # just set force_container_label to avoid unncessary heuristic checks
        return self.get_or_create_build(koji_build_id,
                                        build['original_nvr'],
                                        force_container_label=True)
Пример #2
0
    def build_handler(self, msg):
        """
        Handle a build state message and update Neo4j if necessary.

        :param dict msg: a message to be processed
        """
        if not msg['body']['msg']['info']['source']:
            return
        commit_hash_pattern = re.compile(r'(?:\#)([0-9a-f]{40})$')
        commit_hash = re.findall(commit_hash_pattern,
                                 msg['body']['msg']['info']['source'])

        # Container builds and rpms have commit hashes, so we want to process them
        if commit_hash:
            commit = DistGitCommit.get_or_create({'hash_': commit_hash[0]})[0]
            build = self.get_or_create_build(msg['body']['msg']['info']['id'])

            if build.__label__ == ModuleKojiBuild.__label__:
                extra_json = msg['body']['msg']['info']['extra']
                module_extra_info = extra_json.get('typeinfo',
                                                   {}).get('module')
                module_build_tag_name = module_extra_info.get(
                    'content_koji_tag')
                if module_build_tag_name:
                    try:
                        tag_info = self.koji_session.getTag(
                            module_build_tag_name)
                    except Exception:
                        log.error('Failed to get tag {0}'.format(
                            module_build_tag_name))
                        raise
                    module_build_tag = KojiTag.create_or_update({
                        'id_':
                        tag_info['id'],
                        'name':
                        module_build_tag_name
                    })[0]

                    module_build_tag.module_builds.connect(build)

                    _, components = self.koji_session.listTaggedRPMS(
                        module_build_tag_name)
                    for component in components:
                        component_build = self.get_or_create_build(component)
                        build.components.connect(component_build)

            build.conditional_connect(build.commit, commit)
Пример #3
0
    def get_or_create_build(self,
                            identifier,
                            original_nvr=None,
                            force_container_label=False):
        """
        Get a Koji build from Neo4j, or create it if it does not exist in Neo4j.

        :param str/int identifier: an NVR (str) or build ID (int), or a dict of info from Koji API
        :kwarg str original_nvr: original_nvr property for the ContainerKojiBuild
        :kwarg bool force_container_label: when true, this skips the check to see if the build is a
            container and just creates the build with the ContainerKojiBuild label
        :rtype: KojiBuild
        :return: the Koji Build retrieved or created from Neo4j
        """
        if type(identifier) is dict:
            build_info = identifier
        else:
            try:
                build_info = self.koji_session.getBuild(identifier,
                                                        strict=True)
            except Exception:
                log.error(
                    'Failed to get brew build using the identifier {0}'.format(
                        identifier))
                raise

        build_params = {
            'epoch': build_info['epoch'],
            'id_': str(build_info['id']),
            'name': build_info['package_name'],
            'release': build_info['release'],
            'state': build_info['state'],
            'version': build_info['version']
        }

        if build_info.get('extra'):
            build_params['extra'] = json.dumps(build_info['extra'])

        # To handle the case when a message has a null timestamp
        for time_key in ('completion_time', 'creation_time', 'start_time'):
            # Certain Koji API endpoints omit the *_ts values but have the *_time values, so that's
            # why the *_time values are used
            if build_info[time_key]:
                ts_format = r'%Y-%m-%d %H:%M:%S'
                if len(build_info[time_key].rsplit('.', 1)) == 2:
                    # If there are microseconds, go ahead and parse that too
                    ts_format += r'.%f'
                build_params[time_key] = datetime.strptime(
                    build_info[time_key], ts_format)

        owner = User.create_or_update({
            'username':
            build_info['owner_name'],
            'email':
            '{0}@redhat.com'.format(build_info['owner_name'])
        })[0]

        if force_container_label or self.is_container_build(build_info):
            if original_nvr:
                build_params['original_nvr'] = original_nvr
            build = ContainerKojiBuild.create_or_update(build_params)[0]
        elif self.is_module_build(build_info):
            module_extra_info = build_info['extra'].get('typeinfo',
                                                        {}).get('module')
            build_params['context'] = module_extra_info.get('context')
            build_params['mbs_id'] = module_extra_info.get(
                'module_build_service_id')
            build_params['module_name'] = module_extra_info.get('name')
            build_params['module_stream'] = module_extra_info.get('stream')
            build_params['module_version'] = module_extra_info.get('version')
            try:
                build = ModuleKojiBuild.create_or_update(build_params)[0]
            except neomodel.exceptions.ConstraintValidationFailed:
                # This must have errantly been created as a KojiBuild instead of a
                # ModuleKojiBuild, so let's fix that.
                build = KojiBuild.nodes.get_or_none(id_=build_params['id_'])
                if not build:
                    # If there was a constraint validation failure and the build isn't just the
                    # wrong label, then we can't recover.
                    raise
                build.add_label(ModuleKojiBuild.__label__)
                build = ModuleKojiBuild.create_or_update(build_params)[0]
        else:
            build = KojiBuild.create_or_update(build_params)[0]

        build.conditional_connect(build.owner, owner)

        return build