OLD | NEW |
(Empty) | |
| 1 # Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. |
| 4 |
| 5 """Generates reports base on bisect result data.""" |
| 6 |
| 7 import copy |
| 8 |
| 9 _CONFIDENCE_THRESHOLD = 99.5 |
| 10 |
| 11 _BISECT_REPORT_TEMPLATE = """ |
| 12 ===== BISECT JOB RESULTS ===== |
| 13 Status: %(status)s |
| 14 |
| 15 %(result)s |
| 16 |
| 17 Bisect job ran on: %(bisect_bot)s |
| 18 Bug ID: %(bug_id)s |
| 19 |
| 20 Test Command: %(command)s |
| 21 Test Metric: %(metric)s |
| 22 Relative Change: %(change)s |
| 23 Score: %(score)s |
| 24 |
| 25 Buildbot stdio: %(buildbot_log_url)s |
| 26 Job details: %(issue_url)s |
| 27 |
| 28 """ |
| 29 |
| 30 _RESULTS_REVISION_INFO = """ |
| 31 ===== SUSPECTED CL(s) ===== |
| 32 Subject : %(subject)s |
| 33 Author : %(author)s |
| 34 Commit description: |
| 35 %(commit_info)s |
| 36 Commit : %(cl)s |
| 37 Date : %(cl_date)s |
| 38 |
| 39 """ |
| 40 |
| 41 # When the bisect was aborted without a bisect failure the following template |
| 42 # is used. |
| 43 _ABORT_REASON_TEMPLATE = """ |
| 44 === Bisection aborted === |
| 45 The bisect was aborted because %(abort_reason)s |
| 46 Please contact the the team (see below) if you believe this is in error. |
| 47 |
| 48 """ |
| 49 |
| 50 _WARNINGS_TEMPLATE = """ |
| 51 === Warnings === |
| 52 The following warnings were raised by the bisect job: |
| 53 |
| 54 * %(warnings)s |
| 55 |
| 56 """ |
| 57 |
| 58 _REVISION_TABLE_TEMPLATE = """ |
| 59 ===== TESTED REVISIONS ===== |
| 60 %(table)s""" |
| 61 |
| 62 _RESULTS_THANKYOU = """ |
| 63 | O O | Visit http://www.chromium.org/developers/speed-infra/perf-bug-faq |
| 64 | X | for more information addressing perf regression bugs. For feedback, |
| 65 | / \\ | file a bug with label Cr-Tests-AutoBisect. Thank you!""" |
| 66 |
| 67 |
| 68 def GetReport(try_job_entity): |
| 69 """Generates a report for bisect results. |
| 70 |
| 71 This was ported from recipe_modules/auto_bisect/bisect_results.py. |
| 72 |
| 73 Args: |
| 74 try_job_entity: A TryJob entity. |
| 75 |
| 76 Returns: |
| 77 Bisect report string. |
| 78 """ |
| 79 results_data = copy.deepcopy(try_job_entity.results_data) |
| 80 if not results_data: |
| 81 return '' |
| 82 result = '' |
| 83 if results_data.get('aborted_reason'): |
| 84 result += _ABORT_REASON_TEMPLATE % results_data['aborted_reason'] |
| 85 |
| 86 if results_data.get('warnings'): |
| 87 result += _WARNINGS_TEMPLATE % results_data['warnings'] |
| 88 |
| 89 if results_data.get('culprit_data'): |
| 90 result += _RESULTS_REVISION_INFO % results_data['culprit_data'] |
| 91 |
| 92 if results_data.get('revision_data'): |
| 93 result += _RevisionTable(results_data) |
| 94 |
| 95 results_data['result'] = result |
| 96 report = _BISECT_REPORT_TEMPLATE % results_data |
| 97 report += _RESULTS_THANKYOU |
| 98 return report |
| 99 |
| 100 |
| 101 def _RevisionTable(results_data): |
| 102 is_return_code = results_data.get('test_type') == 'return_code' |
| 103 has_culprit = 'culprit_data' in results_data |
| 104 |
| 105 def RevisionRow(r): |
| 106 result = [ |
| 107 r['depot_name'], |
| 108 r['deps_revision'] or 'r' + str(r['commit_pos']), |
| 109 _FormatNumber(r['mean_value']), |
| 110 _FormatNumber(r['std_dev']), |
| 111 len(r['values']), |
| 112 r['result'], |
| 113 '<-' if has_culprit == r else '', |
| 114 ] |
| 115 return map(str, result) |
| 116 revision_rows = [RevisionRow(r) for r in results_data['revision_data']] |
| 117 |
| 118 headers_row = [[ |
| 119 'Depot', |
| 120 'Revision', |
| 121 'Mean Value' if not is_return_code else 'Exit Code', |
| 122 'Std. Dev.', |
| 123 'Num Values', |
| 124 'Good?', |
| 125 '', |
| 126 ]] |
| 127 all_rows = headers_row + revision_rows |
| 128 return _REVISION_TABLE_TEMPLATE % {'table': _PrettyTable(all_rows)} |
| 129 |
| 130 |
| 131 def _FormatNumber(x): |
| 132 if x is None: |
| 133 return 'N/A' |
| 134 if isinstance(x, int): |
| 135 return str(x) |
| 136 return str(round(x, 6)) |
| 137 |
| 138 |
| 139 def _PrettyTable(data): |
| 140 results = [] |
| 141 for row in data: |
| 142 results.append(('%-12s' * len(row) % tuple(row)).rstrip()) |
| 143 return '\n'.join(results) |
OLD | NEW |