blob: 5a48c77a4c34f5a50446b6158dc03ef38d87ff94 [file] [log] [blame]
# Copyright 2016 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Generates reports base on bisect result data."""
import copy
_CONFIDENCE_THRESHOLD = 99.5
_BISECT_REPORT_TEMPLATE = """
===== BISECT JOB RESULTS =====
Status: %(status)s
%(result)s
Bisect job ran on: %(bisect_bot)s
Bug ID: %(bug_id)s
Test Command: %(command)s
Test Metric: %(metric)s
Relative Change: %(change)s
Score: %(score)s
Buildbot stdio: %(buildbot_log_url)s
Job details: %(issue_url)s
"""
_RESULTS_REVISION_INFO = """
===== SUSPECTED CL(s) =====
Subject : %(subject)s
Author : %(author)s
Commit description:
%(commit_info)s
Commit : %(cl)s
Date : %(cl_date)s
"""
_ABORTED_REASON_TEMPLATE = """
=== Bisection aborted ===
The bisect was aborted because %s
Please contact the the team (see below) if you believe this is in error.
"""
_WARNINGS_TEMPLATE = """
=== Warnings ===
The following warnings were raised by the bisect job:
* %s
"""
_REVISION_TABLE_TEMPLATE = """
===== TESTED REVISIONS =====
%(table)s"""
_RESULTS_THANK_YOU = """
| O O | Visit http://www.chromium.org/developers/speed-infra/perf-bug-faq
| X | for more information addressing perf regression bugs. For feedback,
| / \\ | file a bug with component Tests>AutoBisect. Thank you!"""
_REPORT_BAD_BISECT_TEMPLATE = """
Not what you expected? We'll investigate and get back to you!
https://chromeperf.appspot.com/bad_bisect?try_job_id=%s
"""
def GetReport(try_job_entity):
"""Generates a report for bisect results.
This was ported from recipe_modules/auto_bisect/bisect_results.py.
Args:
try_job_entity: A TryJob entity.
Returns:
Bisect report string.
"""
results_data = copy.deepcopy(try_job_entity.results_data)
if not results_data:
return ''
result = ''
if results_data.get('aborted_reason'):
result += _ABORTED_REASON_TEMPLATE % results_data['aborted_reason']
if results_data.get('warnings'):
warnings = '\n'.join(results_data['warnings'])
result += _WARNINGS_TEMPLATE % warnings
if results_data.get('culprit_data'):
result += _RESULTS_REVISION_INFO % results_data['culprit_data']
if results_data.get('revision_data'):
result += _RevisionTable(results_data)
results_data['result'] = result
report = _BISECT_REPORT_TEMPLATE % results_data
if try_job_entity.bug_id > 0:
report += _REPORT_BAD_BISECT_TEMPLATE % try_job_entity.bug_id
report += _RESULTS_THANK_YOU
return report
def _MakeLegacyRevisionString(r):
result = 'chromium@' + str(r.get('commit_pos', 'unknown'))
if r.get('depot_name', 'chromium') != 'chromium':
result += ',%s@%s' % (r['depot_name'], r.get('deps_revision', 'unknown'))
return result
def _RevisionTable(results_data):
is_return_code = results_data.get('test_type') == 'return_code'
culprit_commit_hash = None
if 'culprit_data' in results_data and results_data['culprit_data']:
culprit_commit_hash = results_data['culprit_data']['cl']
def RevisionRow(r):
result = [
r.get('revision_string', _MakeLegacyRevisionString(r)),
_FormatNumber(r['mean_value']),
_FormatNumber(r['std_dev']),
len(r['values']),
r['result'],
'<-' if r['commit_hash'] == culprit_commit_hash else '',
]
return map(str, result)
revision_rows = [RevisionRow(r) for r in results_data['revision_data']]
headers_row = [[
'Revision',
'Mean Value' if not is_return_code else 'Exit Code',
'Std. Dev.',
'Num Values',
'Good?',
'',
]]
all_rows = headers_row + revision_rows
return _REVISION_TABLE_TEMPLATE % {'table': _PrettyTable(all_rows)}
def _FormatNumber(x):
if x is None:
return 'N/A'
if isinstance(x, int):
return str(x)
return str(round(x, 6))
def _PrettyTable(data):
results = []
for row in data:
results.append(
(('%-24s' + '%-12s' * (len(row) - 1)) % tuple(row)).rstrip())
return '\n'.join(results)