def summarize_patch(codereview_hostname, issue, patch, now): attempts = [ summarize_attempt(raw_attempt, now) for raw_attempt in get_raw_attempts(codereview_hostname, issue, patch) ] attempts.reverse() return { 'success': any(attempt['success'] for attempt in attempts), 'begin': maybe_min(attempt['begin'] for attempt in attempts), 'end': maybe_max(attempt['end'] for attempt in attempts), 'durations': { field: sum(attempt['durations'][field] for attempt in attempts) for field in blank_durations_summary() }, 'job_counts': { state: sum(len(attempt['jobs'][state]) for attempt in attempts) for state in JOB_STATE.itervalues() }, 'flaky_jobs': get_flaky_jobs(attempts), 'attempt_count': len(attempts), 'attempt_fail_count': sum( 1 for attempt in attempts if attempt['success'] == False), 'attempts': attempts, }
def blank_attempt_summary(): # pragma: no cover return { "success": None, "fail_reason": None, "begin": None, "end": None, "durations": blank_durations_summary(), "jobs": {state: [] for state in JOB_STATE.itervalues()}, }
def blank_attempt_summary(): return { 'success': None, 'fail_reason': None, 'begin': None, 'end': None, 'durations': blank_durations_summary(), 'jobs': {state: [] for state in JOB_STATE.itervalues()}, }
def summarize_jobs(self, attempt_ended, last_timestamp): summaries = {state: [] for state in JOB_STATE.itervalues()} for builds in self.jobs.itervalues(): for jobs in builds.itervalues(): for job in jobs.itervalues(): if job['end'] == None: # pragma: no cover if attempt_ended: job['end'] = last_timestamp job['duration'] = last_timestamp - job['begin'] summaries[job['state']].append(job) for jobs in summaries.itervalues(): jobs.sort(key=lambda x: x['begin'], reverse=True) return summaries
def summarize_jobs(self, attempt_ended, last_timestamp): summaries = {state: [] for state in JOB_STATE.itervalues()} for builds in self.jobs.itervalues(): for jobs in builds.itervalues(): for job in jobs.itervalues(): if job["end"] == None: if attempt_ended: job["end"] = last_timestamp job["duration"] = last_timestamp - job["begin"] summaries[job["state"]].append(job) for jobs in summaries.itervalues(): jobs.sort(cmp=lambda x, y: cmp(y["begin"], x["begin"])) return summaries
def summarize_jobs(self, attempt_ended, last_timestamp): summaries = {state: [] for state in JOB_STATE.itervalues()} for builds in self.jobs.itervalues(): for jobs in builds.itervalues(): for job in jobs.itervalues(): if job['end'] == None: if attempt_ended: job['end'] = last_timestamp job['duration'] = last_timestamp - job['begin'] summaries[job['state']].append(job) for jobs in summaries.itervalues(): jobs.sort(cmp=lambda x, y: cmp(y['begin'], x['begin'])) return summaries
def update_jobs(self, record): job_states = record.fields.get('jobs', {}) for cq_job_state, jobs in job_states.iteritems(): job_state = JOB_STATE.get(cq_job_state) if not job_state: # pragma: no cover logging.warning('Unknown job state: %s', cq_job_state) continue for job_info in jobs: build_number = job_info.get('buildnumber') if not build_number: # pragma: no cover # NOTE: this is outdated assumption. In LUCI world, many try builds # don't have buildnumber ever. It apperas this app assumes buildnumber # to exist, but since this is deprecated, this is a NOTE, not a FIXME. continue master = job_info.get('master') builder = job_info.get('builder') self.jobs.setdefault(master, {}) self.jobs[master].setdefault(builder, {}) job_info = job_info or {} timestamp = parse_rietveld_timestamp( job_info.get('created_ts') or job_info.get('timestamp')) # Ignore jobs from past attempts. if (not timestamp or # pragma: no branch timestamp < self.cutoff_timestamp): continue job = self.jobs[master][builder].setdefault(build_number, {}) if len(job) == 0: job.update(blank_job_summary()) job.update({ 'begin': timestamp, 'master': master, 'builder': builder, 'slave': job_info.get('slave'), 'build_number': build_number, }) if job_state != 'running': job['end'] = timestamp job['duration'] = timestamp - job['begin'] job['state'] = job_state job['retry'] = any( same_builder(job, test_job) and job['build_number'] != test_job['build_number'] and test_job['begin'] < job['begin'] for test_job in self.jobs[master][builder].itervalues()) # The build URL is sometimes missing so ensure we set it # if it was not already set. job['url'] = job['url'] or job_info.get('url')
def update_jobs(self, record): job_states = record.fields.get("jobs", {}) for cq_job_state, jobs in job_states.iteritems(): job_state = JOB_STATE.get(cq_job_state) if not job_state: logging.warning("Unknown job state: %s", cq_job_state) continue for job_info in jobs: master = job_info.get("master") builder = job_info.get("builder") self.jobs.setdefault(master, {}) self.jobs[master].setdefault(builder, {}) job_info = job_info or {} timestamp = self.rietveld_timestamp(job_info.get("timestamp")) # Ignore jobs from past attempts. if not timestamp or timestamp < self.cutoff_timestamp: continue build_number = job_info.get("buildnumber") if not build_number: logging.warning("No build number for %s %s at %s." % (master, builder, timestamp)) continue job = self.jobs[master][builder].setdefault(build_number, {}) if len(job) == 0: job.update(blank_job_summary()) job.update( { "begin": timestamp, "master": master, "builder": builder, "slave": job_info.get("slave"), "build_number": build_number, } ) if job_state != "running": job["end"] = timestamp job["duration"] = timestamp - job["begin"] job["state"] = job_state job["retry"] = any( same_builder(job, test_job) and job["build_number"] != test_job["build_number"] and test_job["begin"] < job["begin"] for test_job in self.jobs[master][builder].itervalues() ) # The build URL is sometimes missing so ensure we set it # if it was not already set. job["url"] = job["url"] or job_info.get("url")
def update_jobs(self, record): job_states = record.fields.get('jobs', {}) for cq_job_state, jobs in job_states.iteritems(): job_state = JOB_STATE.get(cq_job_state) if not job_state: # pragma: no cover logging.warning('Unknown job state: %s', cq_job_state) continue for job_info in jobs: build_number = job_info.get('buildnumber') if not build_number: # pragma: no cover # Early exit: CQ is now scheduling with buildbucket, # which means first events won't have a buildnumber, just build_id. continue master = job_info.get('master') builder = job_info.get('builder') self.jobs.setdefault(master, {}) self.jobs[master].setdefault(builder, {}) job_info = job_info or {} timestamp = parse_rietveld_timestamp( job_info.get('created_ts') or job_info.get('timestamp')) # Ignore jobs from past attempts. if (not timestamp or # pragma: no branch timestamp < self.cutoff_timestamp): continue job = self.jobs[master][builder].setdefault(build_number, {}) if len(job) == 0: job.update(blank_job_summary()) job.update({ 'begin': timestamp, 'master': master, 'builder': builder, 'slave': job_info.get('slave'), 'build_number': build_number, }) if job_state != 'running': job['end'] = timestamp job['duration'] = timestamp - job['begin'] job['state'] = job_state job['retry'] = any( same_builder(job, test_job) and job['build_number'] != test_job['build_number'] and test_job['begin'] < job['begin'] for test_job in self.jobs[master][builder].itervalues()) # The build URL is sometimes missing so ensure we set it # if it was not already set. job['url'] = job['url'] or job_info.get('url')
def update_jobs(self, record): job_states = record.fields.get('jobs', {}) for cq_job_state, jobs in job_states.iteritems(): job_state = JOB_STATE.get(cq_job_state) if not job_state: logging.warning('Unknown job state: %s', cq_job_state) continue for job_info in jobs: master = job_info.get('master') builder = job_info.get('builder') self.jobs.setdefault(master, {}) self.jobs[master].setdefault(builder, {}) job_info = job_info or {} timestamp = self.rietveld_timestamp(job_info.get('timestamp')) # Ignore jobs from past attempts. if not timestamp or timestamp < self.cutoff_timestamp: continue build_number = job_info.get('buildnumber') if not build_number: logging.warning('No build number for %s %s at %s.' % (master, builder, timestamp)) continue job = self.jobs[master][builder].setdefault(build_number, {}) if len(job) == 0: job.update(blank_job_summary()) job.update({ 'begin': timestamp, 'master': master, 'builder': builder, 'slave': job_info.get('slave'), 'build_number': build_number, }) if job_state != 'running': job['end'] = timestamp job['duration'] = timestamp - job['begin'] job['state'] = job_state job['retry'] = any( same_builder(job, test_job) and job['build_number'] != test_job['build_number'] and test_job['begin'] < job['begin'] for test_job in self.jobs[master][builder].itervalues()) # The build URL is sometimes missing so ensure we set it # if it was not already set. job['url'] = job['url'] or job_info.get('url')
def summarize_patch(issue, patch, now): # pragma: no cover attempts = [summarize_attempt(raw_attempt, now) for raw_attempt in get_raw_attempts(issue, patch)][::-1] return { "success": any(attempt["success"] for attempt in attempts), "begin": maybe_min(attempt["begin"] for attempt in attempts), "end": maybe_max(attempt["end"] for attempt in attempts), "durations": { field: sum(attempt["durations"][field] for attempt in attempts) for field in blank_durations_summary() }, "job_counts": { state: sum(len(attempt["jobs"][state]) for attempt in attempts) for state in JOB_STATE.itervalues() }, "flaky_jobs": get_flaky_jobs(attempts), "attempt_count": len(attempts), "attempt_fail_count": sum(1 for attempt in attempts if attempt["success"] == False), "attempts": attempts, }
def record_to_events(record, attempt_number): # pragma: no cover """Given a single CQ record, creates a generator for Trace Viewer events. A single record in CQ can correspond to any number of events, depending on the action performed in the record. The conversion from each action to Trace Viewer event is listed below. patch_start: single 'B' event representing the start of the attempt. patch_ready_to_commit: single 'B' event representing start of commit attempt patch_committed: single 'E' event representing successful commit patch_failed: single 'E' event representing completed patch attempt patch_stop: single 'E' event representing the end of the attempt. verifier_trigger: multiple 'B' events, one for each builder triggered. verifier_jobs_update: multiple 'E' events, one for each builder success or failure. """ action = record.fields.get('action') attempt_string = 'Attempt %d' % attempt_number timestamp = record.fields.get('timestamp') if action == 'verifier_trigger': masters = record.fields.get('trybots', {}) for master in masters: for builder in masters[master]: yield TraceViewerEvent(builder, master, 'B', timestamp, attempt_string, builder, 'cq_build_running') elif action == 'verifier_jobs_update': job_states = record.fields.get('jobs', {}) # CQ splits jobs into lists based on their state. for cq_job_state, jobs in job_states.iteritems(): # Jobs can be in many different states, JOB_STATE maps them to # 'running' or not. job_state = JOB_STATE.get(cq_job_state) if not job_state: continue elif job_state == 'running': for job_info in jobs: master = job_info['master'] builder = job_info['builder'] args = {'build_url': job_info.get('url')} yield MetaEvent(builder, master, args) else: for job_info in jobs: master = job_info['master'] builder = job_info['builder'] timestamp = rietveld_timestamp(job_info['timestamp']) cname = 'cq_build_' + job_state args = { 'build_url': job_info.get('url'), } yield TraceViewerEvent(builder, master, 'E', timestamp, attempt_string, builder, cname, args) elif action == 'patch_start': yield TraceViewerEvent(attempt_string, 'Patch Progress', 'B', timestamp, attempt_string, 'Patch Progress', 'cq_build_attempt_running') elif action == 'patch_ready_to_commit': yield TraceViewerEvent('Patch Committing', 'Patch Progress', 'B', timestamp, attempt_string, 'Patch Progress', 'cq_build_attempt_running') elif action == 'patch_committed': yield TraceViewerEvent('Patch Committing', 'Patch Progress', 'E', timestamp, attempt_string, 'Patch Progress', 'cq_build_attempt_passed') elif action == 'patch_stop': cname = 'cq_build_attempt_' if 'successfully committed' in record.fields['message']: cname += 'passed' else: cname += 'failed' yield TraceViewerEvent(attempt_string, 'Patch Progress', 'E', timestamp, attempt_string, 'Patch Progress', cname, {'action': action})