Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(12)

Side by Side Diff: appengine/findit/handlers/triage_analysis.py

Issue 2086113004: [Findit] Show build analysis references in UI for Findit Cross-platform auto-triage (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@build-matching
Patch Set: Merged with ("rebased" on) Issue 2029873002's code. Other changes. Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 # Copyright 2014 The Chromium Authors. All rights reserved. 1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 """This module is to handle manual triage of analysis result. 5 """This module is to handle manual triage of analysis result.
6 6
7 This handler will flag the analysis result as correct or incorrect. 7 This handler will flag the analysis result as correct or incorrect.
8 TODO: work on an automatic or semi-automatic way to triage analysis result. 8 TODO: work on an automatic or semi-automatic way to triage analysis result.
9 """ 9 """
10 10
(...skipping 30 matching lines...) Expand all
41 41
42 or could look like: 42 or could look like:
43 43
44 (step_name, revision) 44 (step_name, revision)
45 """ 45 """
46 potential_culprit_tuple_list = [] 46 potential_culprit_tuple_list = []
47 47
48 # Iterates through the failures, tests, and suspected_cls, appending potential 48 # Iterates through the failures, tests, and suspected_cls, appending potential
49 # (step_name, test_name, revision) and (step_name, revision) culprit tuples to 49 # (step_name, test_name, revision) and (step_name, revision) culprit tuples to
50 # the list. 50 # the list.
51
lijeffrey 2016/06/27 20:38:22 nit: delete this empty line
josiahk 2016/06/28 22:59:23 Done.
51 for failure in analysis.result['failures']: 52 for failure in analysis.result['failures']:
52 if failure.get('tests'): 53 if failure.get('tests'):
53 for test in failure['tests']: 54 for test in failure['tests']:
54 for suspected_cl in test.get('suspected_cls', []): 55 for suspected_cl in test.get('suspected_cls', []):
55 potential_culprit_tuple_list.append(( 56 potential_culprit_tuple_list.append((
56 failure['step_name'], 57 failure['step_name'],
57 test['test_name'], 58 test['test_name'],
58 suspected_cl['revision'])) 59 suspected_cl['revision']))
59 else: 60 else:
60 for suspected_cl in failure['suspected_cls']: 61 for suspected_cl in failure['suspected_cls']:
(...skipping 22 matching lines...) Expand all
83 84
84 # Both analyses must have non-empty potential culprit lists. 85 # Both analyses must have non-empty potential culprit lists.
85 if not potential_culprit_tuple_list_1 or not potential_culprit_tuple_list_2: 86 if not potential_culprit_tuple_list_1 or not potential_culprit_tuple_list_2:
86 return False 87 return False
87 88
88 # Both analyses must have matching potential culprit lists. 89 # Both analyses must have matching potential culprit lists.
89 return (sorted(potential_culprit_tuple_list_1) == 90 return (sorted(potential_culprit_tuple_list_1) ==
90 sorted(potential_culprit_tuple_list_2)) 91 sorted(potential_culprit_tuple_list_2))
91 92
92 93
93 def _AppendTriageHistoryRecord(analysis, is_correct, user_name): 94 def _AppendTriageHistoryRecord(
95 analysis, is_correct, user_name, is_duplicate=False):
94 """Appends a triage history record to the given analysis. 96 """Appends a triage history record to the given analysis.
95 97
96 Args: 98 Args:
97 analysis: The analysis to which to append the history record. 99 analysis: The analysis to which to append the history record.
98 is_correct: True if the history record should indicate a correct judgement, 100 is_correct: True if the history record should indicate a correct judgement,
99 otherwise False. 101 otherwise False.
100 user_name: The user_name of the person to include in the triage record. 102 user_name: The user_name of the person to include in the triage record.
103 is_duplicate: True if the history record should indicate that this triage is
104 a duplicate, otherwise False.
101 """ 105 """
102 if is_correct: 106 if is_correct:
103 if analysis.suspected_cls: 107 if analysis.suspected_cls:
104 analysis.result_status = result_status.FOUND_CORRECT 108 if is_duplicate:
109 analysis.result_status = result_status.FOUND_CORRECT_DUPLICATE
110 else:
111 analysis.result_status = result_status.FOUND_CORRECT
105 analysis.culprit_cls = analysis.suspected_cls 112 analysis.culprit_cls = analysis.suspected_cls
106 else: 113 else:
107 analysis.result_status = result_status.NOT_FOUND_CORRECT 114 analysis.result_status = result_status.NOT_FOUND_CORRECT
108 analysis.culprit_cls = None 115 analysis.culprit_cls = None
109 else: 116 else:
110 analysis.culprit_cls = None 117 analysis.culprit_cls = None
111 if analysis.suspected_cls: 118 if analysis.suspected_cls:
112 analysis.result_status = result_status.FOUND_INCORRECT 119 if is_duplicate:
120 analysis.result_status = result_status.FOUND_INCORRECT_DUPLICATE
121 else:
122 analysis.result_status = result_status.FOUND_INCORRECT
113 else: 123 else:
114 analysis.result_status = result_status.NOT_FOUND_INCORRECT 124 analysis.result_status = result_status.NOT_FOUND_INCORRECT
115 125
116 triage_record = { 126 triage_record = {
117 'triage_timestamp': calendar.timegm(datetime.utcnow().timetuple()), 127 'triage_timestamp': calendar.timegm(datetime.utcnow().timetuple()),
118 'user_name': user_name, 128 'user_name': user_name,
119 'result_status': analysis.result_status, 129 'result_status': analysis.result_status,
120 'version': analysis.version, 130 'version': analysis.version,
121 } 131 }
122 if not analysis.triage_history: 132 if not analysis.triage_history:
123 analysis.triage_history = [] 133 analysis.triage_history = []
124 analysis.triage_history.append(triage_record) 134 analysis.triage_history.append(triage_record)
125 135
126 analysis.put() 136 analysis.put()
127 137
128 138
129 @ndb.transactional 139 @ndb.transactional
130 def _UpdateAnalysisResultStatus( 140 def _UpdateAnalysisResultStatus(
131 master_name, builder_name, build_number, is_correct, user_name=None): 141 master_name, builder_name, build_number, is_correct, user_name=None):
132 analysis = WfAnalysis.Get(master_name, builder_name, build_number) 142 analysis = WfAnalysis.Get(master_name, builder_name, build_number)
133 if not analysis or not analysis.completed: 143 if not analysis or not analysis.completed:
134 return False, None 144 return False, None
135 145
146 analysis.triage_reference_analysis_master_name = None
lijeffrey 2016/06/27 20:38:22 so what are these for, and why are we setting them
chanli 2016/06/27 22:27:56 +1
josiahk 2016/06/28 22:59:23 When another "first-cause" build analysis is triag
lijeffrey 2016/06/29 00:48:23 you don't need to initialize them to None, if they
josiahk 2016/06/29 22:40:00 Yes, I want to potentially overwrite previously se
lijeffrey 2016/06/30 01:09:46 It appears with what you have triage duplicate res
josiahk 2016/06/30 22:34:56 _UpdateAnalysisResultStatus() operates on a single
147 analysis.triage_reference_analysis_builder_name = None
148 analysis.triage_reference_analysis_build_number = None
149
136 _AppendTriageHistoryRecord(analysis, is_correct, user_name) 150 _AppendTriageHistoryRecord(analysis, is_correct, user_name)
137 151
138 return True, analysis 152 return True, analysis
139 153
140 154
141 def _GetDuplicateAnalyses(original_analysis): 155 def _GetDuplicateAnalyses(original_analysis):
142 start_time = (original_analysis.build_start_time - 156 start_time = (original_analysis.build_start_time -
143 timedelta(hours=MATCHING_ANALYSIS_HOURS_AGO_START)) 157 timedelta(hours=MATCHING_ANALYSIS_HOURS_AGO_START))
144 end_time = (original_analysis.build_start_time + 158 end_time = (original_analysis.build_start_time +
145 timedelta(hours=MATCHING_ANALYSIS_HOURS_AGO_END)) 159 timedelta(hours=MATCHING_ANALYSIS_HOURS_AGO_END))
(...skipping 22 matching lines...) Expand all
168 182
169 # Retrieve potential duplicate build analyses. 183 # Retrieve potential duplicate build analyses.
170 analysis_results = WfAnalysis.query(ndb.AND( 184 analysis_results = WfAnalysis.query(ndb.AND(
171 WfAnalysis.build_start_time >= start_time, 185 WfAnalysis.build_start_time >= start_time,
172 WfAnalysis.build_start_time <= end_time, 186 WfAnalysis.build_start_time <= end_time,
173 WfAnalysis.result_status == result_status.FOUND_UNTRIAGED 187 WfAnalysis.result_status == result_status.FOUND_UNTRIAGED
174 )).fetch() 188 )).fetch()
175 189
176 # Further filter potential duplicates and return them. 190 # Further filter potential duplicates and return them.
177 return [analysis for analysis in analysis_results if 191 return [analysis for analysis in analysis_results if
192 analysis.completed and
193 analysis.result and
178 _DoAnalysesMatch(original_analysis, analysis) and 194 _DoAnalysesMatch(original_analysis, analysis) and
179 original_analysis.key is not analysis.key and 195 original_analysis.key is not analysis.key]
180 analysis.completed]
181 196
182 197
183 def _TriageDuplicateResults(original_analysis, is_correct, user_name=None): 198 def _TriageDuplicateResults(original_analysis, is_correct, user_name=None):
184 matching_analyses = _GetDuplicateAnalyses(original_analysis) 199 matching_analyses = _GetDuplicateAnalyses(original_analysis)
185 200
186 for analysis in matching_analyses: 201 for analysis in matching_analyses:
187 _AppendTriageHistoryRecord(analysis, is_correct, user_name) 202 analysis.triage_reference_analysis_master_name = (
203 original_analysis.master_name)
204 analysis.triage_reference_analysis_builder_name = (
205 original_analysis.builder_name)
206 analysis.triage_reference_analysis_build_number = (
207 original_analysis.build_number)
208 _AppendTriageHistoryRecord(analysis, is_correct, user_name,
209 is_duplicate=True)
210
211 return len(matching_analyses)
lijeffrey 2016/06/27 20:38:22 It looks like you're returning the number of match
josiahk 2016/06/28 22:59:23 Renamed to _TriageAndCountDuplicateResults()
188 212
189 213
190 class TriageAnalysis(BaseHandler): 214 class TriageAnalysis(BaseHandler):
191 PERMISSION_LEVEL = Permission.CORP_USER 215 PERMISSION_LEVEL = Permission.CORP_USER
192 216
193 def HandleGet(self): # pragma: no cover 217 def HandleGet(self): # pragma: no cover
194 return self.HandlePost() 218 return self.HandlePost()
195 219
196 def HandlePost(self): 220 def HandlePost(self):
197 """Sets the manual triage result for the analysis. 221 """Sets the manual triage result for the analysis.
198 222
199 Mark the analysis result as correct/wrong/etc. 223 Mark the analysis result as correct/wrong/etc.
200 TODO: make it possible to set the real culprit CLs. 224 TODO: make it possible to set the real culprit CLs.
201 """ 225 """
202 url = self.request.get('url').strip() 226 url = self.request.get('url').strip()
203 build_info = buildbot.ParseBuildUrl(url) 227 build_info = buildbot.ParseBuildUrl(url)
204 if not build_info: 228 if not build_info:
205 return {'data': {'success': False}} 229 return {'data': {'success': False}}
206 master_name, builder_name, build_number = build_info 230 master_name, builder_name, build_number = build_info
207 231
208 is_correct = self.request.get('correct').lower() == 'true' 232 is_correct = self.request.get('correct').lower() == 'true'
209 # As the permission level is CORP_USER, we could assume the current user 233 # As the permission level is CORP_USER, we could assume the current user
210 # already logged in. 234 # already logged in.
211 user_name = users.get_current_user().email().split('@')[0] 235 user_name = users.get_current_user().email().split('@')[0]
212 success, original_analysis = _UpdateAnalysisResultStatus( 236 success, original_analysis = _UpdateAnalysisResultStatus(
213 master_name, builder_name, build_number, is_correct, user_name) 237 master_name, builder_name, build_number, is_correct, user_name)
238 num_duplicate_analyses = 0
214 if success: 239 if success:
215 _TriageDuplicateResults(original_analysis, is_correct, user_name) 240 num_duplicate_analyses = _TriageDuplicateResults(
216 return {'data': {'success': success}} 241 original_analysis, is_correct, user_name)
242 return {'data': {'success': success,
243 'num_duplicate_analyses': num_duplicate_analyses}}
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698