Пример #1
0
    def createSummary(self, plog):
        global log
        logs = self.cmd.logs
        bqi_num_modules = None
        # buildbotURL = self.build.builder.botmaster.parent.buildbotURL
        bqi_re = re.compile(r'([^\>\|]+)(\|[^\>]+)?\> (.*)$')
        qlog_re = re.compile(r'Module: "(.+)", score: (.*)$')

        def bq2tr(bqi_name):
            return tuple(bqi_name.split('.'))

        logkeys = logs.keys()
        
        # We will be using TestResult()s for the aggregate output of our
        # steps. 
        # We use like: TestResult(name=(bqi-context), results=<num>, 
        #                         text=blist2str(blame),
        #                         logs= {'stdout': out, 'exception': exc } )
        
        if 'stdio' in logkeys:
            # Here we parse the machine-formatted output of b-q-i
            # Hopefully, it should be straightforward.
            lines = logs['stdio'].getText().split('\n')
            
            server_out = []
            server_err = []
            
            quality_logs = {}
            blame_list = []  # for the general results
            bqi_state = 'debug'
            bqi_context = False
            bqi_rest = TestResult(name=('bqi','rest'), text='', results=0, logs={'stdout': []})
            
            t_results=[] # ordered list
            cur_result= None  # The entry of t_results we are in, when bqi_context
            
            # The order that logs appeared, try to preserve in status.logs
            # May have duplicates. (less used after last refactoring)
            log_order = [ 'server.out', 'server.err', ]
            
            while len(lines):
                if not lines[0]:
                    lines = lines[1:]
                    continue
                mr = bqi_re.match(lines[0])
                i = 1
                if not mr:
                    raise RuntimeError("Stray line %r in bqi output!" % lines[0])
                blog = mr.group(1)
                blevel = mr.group(2) or '|20'
                try:
                    blevel = int(blevel[1:])
                except ValueError:
                    # bqi_rest.append('Strange level %r' % blevel)
                    pass
                bmsg = mr.group(3)
                bexc = None
                while lines[i] and lines[i].startswith('+ '):
                    bmsg += '\n'+ lines[i][2:]
                    i += 1
                
                if lines[i] and lines[i].startswith(':@'):
                    # Exception text follows
                    bexc = lines[i][3:]
                    i += 1
                    while lines[i] and lines[i].startswith(':+ '):
                        bexc += '\n' + lines[i][3:]
                        i += 1
                
                lines = lines[i:]
                # Now, process the message we have.
                
                if blog == 'server.stdout':
                    # always log the full log of the server into a
                    # summary
                    server_out.append(bmsg)
                    if bexc:
                        server_out.append(bexc)
                    if bqi_context:
                        log_order.append(bqi_context)
                        cur_result.logs['stdout'].append(bmsg) # or += ?
                        if bexc:
                            cur_result.logs.setdefault('exception',[]).append(bexc)
                elif blog == 'server.stderr':
                    server_err.append(bmsg)
                    if bexc:
                        server_err.append(bexc)
                elif blog == 'bqi.state':
                    # this is a special logger, which expects us to do sth
                    # with its lines = commands
                    bmsg = bmsg.rstrip()
                    if bmsg == 'clear context':
                        bqi_context = False
                        cur_result = None
                    elif bmsg.startswith('set context '):
                        bqi_context = bmsg[len('set context '):]
                        cur_result = None
                        for tr in t_results:
                            if tr.name == bq2tr(bqi_context):
                                cur_result = tr
                                break
                        if not cur_result:
                            cur_result = TestResult(name=bq2tr(bqi_context),
                                        results=SUCCESS,
                                        text='', logs={'stdout': []})
                            t_results.append(cur_result)
                            cur_result.blames = []
                    elif bmsg.startswith('set num_modules'):
                        bqi_num_modules = int(bmsg[16:])
                    else:
                        log.msg("Strange command %r came from b-q-i" % bmsg)
                elif blog == 'bqi.blame':
                    # our precious blame information
                    blame_dict = {}
                    
                    # it is a dict, parse it
                    for bbline in bmsg.split('\n'):
                        if ':' not in bbline:
                            # If some stderr is printed after the blame,
                            # the shell process will falsely attach it to the
                            # bqi.blame line, and hence corrupt it. 
                            # Once we see it, we know it is not bqi.blame content.
                            break
                        bkey, bval = bbline.split(':',1)
                        bkey = bkey.strip()
                        bval = bval.strip()
                        blame_dict[bkey] = bval
                    
                    if 'context' in blame_dict:
                        sumk = blame_dict['context']
                    elif 'module' in blame_dict and 'module-mode' in blame_dict:
                        sumk = '%s.%s' % ( blame_dict['module'], blame_dict['module-mode'])
                    else:
                        sumk = bqi_context
                    if not sumk:
                        sumk = 'bqi.rest'

                    blame_info = '%s' % blame_dict.get('module','')
                    blame_sev = 3 # error
                    if 'module-file' in blame_dict:
                        if blame_dict.get('module', False):
                            blame_info += '/'
                        blame_info += '%s' % blame_dict['module-file']
                        if 'file-line' in blame_dict:
                            blame_info += ':%s' % blame_dict['file-line']
                            if 'file-col' in blame_dict:
                                blame_info += ':%s' % blame_dict['file-col']
                    if 'severity' in blame_dict:
                        blame_info += '[%s]' % blame_dict['severity']
                        blame_sev = blame_severities.get(blame_dict['severity'], 3)

                    blame_info += ': '
                    if 'Exception type' in blame_dict:
                        blame_info += '%s: ' % blame_dict['Exception type']
                    if 'Message' in blame_dict:
                        blame_info += blame_dict['Message']
                    elif 'Exception' in blame_dict:
                        blame_info += blame_dict['Exception']
                    else:
                        blame_info += 'FAIL'

                    if append_fail(blame_list, [(blame_info, blame_sev),], fmax=5):
                        self.build.build_status.reason = blist2str(blame_list)

                    if True:
                        # note that we don't affect bqi_context, cur_result here
                        cur_r = None
                        for tr in t_results:
                            if tr.name == bq2tr(sumk):
                                cur_r = tr
                                break
                        if not cur_r:
                            cur_r = TestResult(name=bq2tr(sumk),
                                        results=SUCCESS,
                                        text='', logs={'stdout': []})
                            t_results.append(cur_r)
                            cur_r.blames = []
                        if blame_sev >= 3 or ((blame_info, blame_sev) not in cur_r.blames):
                            cur_r.blames.append((blame_info, blame_sev))

                elif blog == 'bqi.qlogs':
                    nline = bmsg.index('\n')
                    first_line = bmsg[:nline].strip()
                    html_log = bmsg[nline+1:]
                    
                    mq = qlog_re.match(first_line)
                    if mq:
                        # FIXME: 
                        sumk = mq.group(1)
                        qscore = mq.group(2)
                        #log_order.append(sumk)
                        test_res = True
                        try:
                            # Hard-coded criterion!
                            test_res = float(qscore) > 0.30
                        except ValueError:
                            pass
                        quality_logs[sumk] = html_log
                        # TODO use score, too.
                    else:
                        log.err("Invalid first line of quality log: %s" % first_line)
                    
                else:
                    bqi_rest.logs['stdout'].append(bmsg)
                    if blevel >= logging.ERROR:
                        bqi_rest.results = FAILURE
                    if bexc:
                        bqi_rest.logs['stdout'].append(bexc)

        if 'stdio' in logkeys:
            logkeys.remove('stdio')
        if len(logkeys):
            log.err("Remaining keys %s in logs" % (', '.join(logkeys)))

        #cleanup t_results
        for tr in t_results:
            sev = 0
            if tr.blames:
                tr.text = blist2str(tr.blames)
                sev = tr.blames[0][1]
            if tr.results < res_severities[sev]:
                tr.results = res_severities[sev]
            if self.build_result < tr.results:
                self.build_result = tr.results
            for lk in tr.logs:
                if isinstance(tr.logs[lk], list):
                    tr.logs[lk] = '\n'.join(tr.logs[lk])

            # and, after it's clean..
            self.build.build_status.addTestResult(tr)

        for qkey in quality_logs:
            self.addHTMLLog(qkey + '.qlog', quality_logs[qkey])

        build_id = self.build.requests[0].id # FIXME when builds have their class
        
        self.build.builder.db.saveTResults(build_id, self.name,
                                            self.build_result, t_results)

        if bqi_num_modules:
            self.setProperty('num_modules', bqi_num_modules)

        try:
            orm_id = self.getProperty('orm_id') or '?'
        except KeyError:
            orm_id = '?'

        if False and self.build_result == SUCCESS:
            self.setProperty('failure_tag', 'openerp-buildsuccess-%s-%s' % \
                            (orm_id, build_id) )

        if self.build_result == FAILURE:
            # Note: We only want to tag on failure, not on exception
            # or skipped, which means buildbot (and not the commmit) failed
            self.setProperty('failure_tag', 'openerp-buildfail-%s-%s' % \
                            (orm_id, build_id) )
Пример #2
0
    def createSummary(self, log):
        """ Try to read the file-lint.sh output and parse results
        """
        severity = SUCCESS
        if self.args['repo_mode'] == 'server':
            repo_expr = r'bin/addons/([^/]+)/.+$'
        else:
            repo_expr = r'([^/]+)/.+$'

        t_results= {}
        
        repo_re = re.compile(repo_expr)
        for line in StringIO(log.getText()).readlines():
            for rem, sev in self.known_res:
                m = rem.match(line)
                if not m:
                    continue
                fname = m.group(1)
                if sev > severity:
                    severity = sev
                mf = repo_re.match(fname)
                if mf:
                    module = (mf.group(1), 'lint')
                else:
                    module = ('lint', 'rest')
                
                if module not in t_results:
                    t_results[module] = TestResult(name=module,
                                        results=SUCCESS,
                                        text='', logs={'stdout': u''})
                if t_results[module].results < sev:
                    t_results[module].results = sev
                if line.endswith('\r\n'):
                    line = line[:-2] + '\n'
                elif not line.endswith('\n'):
                    line += '\n'
                if sev > SUCCESS:
                    t_results[module].text += ustr(line)
                else:
                    t_results[module].logs['stdout'] += ustr(line)
                
                break # don't attempt more matching of the same line

        # use t_results
        for tr in t_results.values():
            if self.build_result < tr.results:
                self.build_result = tr.results
            # and, after it's clean..
            self.build.build_status.addTestResult(tr)

        self.build_result = severity

        build_id = self.build.requests[0].id # FIXME when builds have their class
        # self.descriptionDone = self.descriptionDone[:]
        self.build.builder.db.saveTResults(build_id, self.name,
                                            self.build_result, t_results.values())

        if severity >= FAILURE:
            try:
                orm_id = self.getProperty('orm_id') or '?'
            except KeyError:
                orm_id = '?'
            self.setProperty('failure_tag', 'openerp-buildfail-%s-%s' % \
                                (orm_id, build_id) )