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) )
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) )