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

Side by Side Diff: appengine/findit/waterfall/send_notification_for_culprit_pipeline.py

Issue 2302223002: [Findit] Change the criteria of sending notification to code review. (Closed)
Patch Set: . Created 4 years, 3 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 2016 The Chromium Authors. All rights reserved. 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 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 from datetime import datetime 5 from datetime import datetime
6 import logging 6 import logging
7 import textwrap 7 import textwrap
8 8
9 from google.appengine.ext import ndb 9 from google.appengine.ext import ndb
10 10
11 from common import time_util 11 from common import time_util
12 from common.git_repository import GitRepository 12 from common.git_repository import GitRepository
13 from common.http_client_appengine import HttpClientAppengine as HttpClient 13 from common.http_client_appengine import HttpClientAppengine as HttpClient
14 from common.pipeline_wrapper import BasePipeline 14 from common.pipeline_wrapper import BasePipeline
15 from common.rietveld import Rietveld 15 from common.rietveld import Rietveld
16 from model import analysis_status as status 16 from model import analysis_status as status
17 from model.wf_analysis import WfAnalysis
17 from model.wf_culprit import WfCulprit 18 from model.wf_culprit import WfCulprit
18 from waterfall import build_util 19 from waterfall import build_util
19 from waterfall import waterfall_config 20 from waterfall import waterfall_config
20 21
21 22
23 def _PassAdditionalCriteria(additional_criteria):
24 """Check if the all the additional criteria have passed.
25
26 Checks for individual criterion have been done before this function.
27 """
28 return False if False in additional_criteria.values() else True
stgao 2016/09/03 06:14:23 return all(additional_criteria.values())
chanli 2016/09/05 21:49:45 Done.
29
30
22 @ndb.transactional 31 @ndb.transactional
23 def _ShouldSendNotification( 32 def _ShouldSendNotification(
24 master_name, builder_name, build_number, repo_name, revision, 33 master_name, builder_name, build_number, repo_name, revision,
25 commit_position, build_num_threshold, time_limit_passed): 34 commit_position, build_num_threshold, additional_criteria,
35 send_notification_right_now):
26 """Returns True if a notification for the culprit should be sent.""" 36 """Returns True if a notification for the culprit should be sent."""
27 culprit = (WfCulprit.Get(repo_name, revision) or 37 culprit = (WfCulprit.Get(repo_name, revision) or
28 WfCulprit.Create(repo_name, revision, commit_position)) 38 WfCulprit.Create(repo_name, revision, commit_position))
29 if [master_name, builder_name, build_number] in culprit.builds: 39 if [master_name, builder_name, build_number] in culprit.builds:
30 return False 40 return False
31 41
32 culprit.builds.append([master_name, builder_name, build_number]) 42 culprit.builds.append([master_name, builder_name, build_number])
33 # Send notification only when: 43 # Send notification only when:
34 # 1. It was not processed yet. 44 # 1. It was not processed yet.
35 # 2. The culprit is for multiple failures in different builds to avoid false 45 # 2. It is not too late after the culprit was committed.
stgao 2016/09/03 06:14:24 Should we still keep this one?
chanli 2016/09/05 21:49:45 Done.
36 # positive due to flakiness.
37 # 3. It is not too late after the culprit was committed.
38 # * Try-job takes too long to complete and the failure got fixed. 46 # * Try-job takes too long to complete and the failure got fixed.
39 # * The whole analysis was rerun a long time after the failure occurred. 47 # * The whole analysis was rerun a long time after the failure occurred.
40 should_send = not (culprit.cr_notification_processed or 48 should_send = not (culprit.cr_notification_processed or
41 len(culprit.builds) < build_num_threshold or 49 not _PassAdditionalCriteria(additional_criteria))
42 time_limit_passed) 50 if not send_notification_right_now:
51 should_send = should_send and len(culprit.builds) >= build_num_threshold
52
43 if should_send: 53 if should_send:
44 culprit.cr_notification_status = status.RUNNING 54 culprit.cr_notification_status = status.RUNNING
45 culprit.put() 55 culprit.put()
46 return should_send 56 return should_send
47 57
48 58
49 @ndb.transactional 59 @ndb.transactional
50 def _UpdateNotificationStatus(repo_name, revision, new_status): 60 def _UpdateNotificationStatus(repo_name, revision, new_status):
51 culprit = WfCulprit.Get(repo_name, revision) 61 culprit = WfCulprit.Get(repo_name, revision)
52 culprit.cr_notification_status = new_status 62 culprit.cr_notification_status = new_status
53 if culprit.cr_notified: 63 if culprit.cr_notified:
54 culprit.cr_notification_time = time_util.GetUTCNow() 64 culprit.cr_notification_time = time_util.GetUTCNow()
55 culprit.put() 65 culprit.put()
56 66
57 67
58 def _SendNotificationForCulprit( 68 def _SendNotificationForCulprit(
59 repo_name, revision, commit_position, code_review_url): 69 repo_name, revision, commit_position, code_review_url):
60 sent = False 70 sent = False
61 if code_review_url: 71 if code_review_url:
62 # Occasionally, a commit was not uploaded for code-review. 72 # Occasionally, a commit was not uploaded for code-review.
63 culprit = WfCulprit.Get(repo_name, revision) 73 culprit = WfCulprit.Get(repo_name, revision)
64 rietveld = Rietveld() 74 rietveld = Rietveld()
65 message = textwrap.dedent(""" 75 message = textwrap.dedent("""
66 FYI: Findit try jobs (rerunning failed compile or tests) identified this CL 76 FYI: Findit identified this CL at revision %s as the culprit for
67 at revision %s as the culprit for failures in the build cycles as shown on: 77 failures in the build cycles as shown on:
68 https://findit-for-me.appspot.com/waterfall/culprit?key=%s 78 https://findit-for-me.appspot.com/waterfall/culprit?key=%s""") % (
69 """) % (commit_position or revision, culprit.key.urlsafe()) 79 commit_position or revision, culprit.key.urlsafe())
70 sent = rietveld.PostMessage(code_review_url, message) 80 sent = rietveld.PostMessage(code_review_url, message)
71 else: 81 else:
72 logging.error('No code-review url for %s/%s', repo_name, revision) 82 logging.error('No code-review url for %s/%s', repo_name, revision)
73 83
74 _UpdateNotificationStatus(repo_name, revision, 84 _UpdateNotificationStatus(repo_name, revision,
75 status.COMPLETED if sent else status.ERROR) 85 status.COMPLETED if sent else status.ERROR)
76 return sent 86 return sent
77 87
78 88
79 def _GetCulpritInfo(repo_name, revision): 89 def _GetCulpritInfo(repo_name, revision):
80 """Returns commit position/time and code-review url of the given revision.""" 90 """Returns commit position/time and code-review url of the given revision."""
81 # TODO(stgao): get repo url at runtime based on the given repo name. 91 # TODO(stgao): get repo url at runtime based on the given repo name.
82 # unused arg - pylint: disable=W0612,W0613 92 # unused arg - pylint: disable=W0612,W0613
83 repo = GitRepository( 93 repo = GitRepository(
84 'https://chromium.googlesource.com/chromium/src.git', HttpClient()) 94 'https://chromium.googlesource.com/chromium/src.git', HttpClient())
85 change_log = repo.GetChangeLog(revision) 95 change_log = repo.GetChangeLog(revision)
86 return change_log.commit_position, change_log.code_review_url 96 return change_log.commit_position, change_log.code_review_url
87 97
88 98
89 def _NotificationTimeLimitPassed(build_end_time, latency_limit_minutes): 99 def _WithinNotificationTimeLimit(build_end_time, latency_limit_minutes):
90 """Returns True if it is too late to send notification.""" 100 """Returns True if it is still in time to send notification."""
91 latency_seconds = (time_util.GetUTCNow() - build_end_time).total_seconds() 101 latency_seconds = (time_util.GetUTCNow() - build_end_time).total_seconds()
92 return latency_seconds > latency_limit_minutes * 60 102 return latency_seconds <= latency_limit_minutes * 60
93 103
94 104
95 class SendNotificationForCulpritPipeline(BasePipeline): 105 class SendNotificationForCulpritPipeline(BasePipeline):
96 106
97 # Arguments number differs from overridden method - pylint: disable=W0221 107 # Arguments number differs from overridden method - pylint: disable=W0221
98 def run(self, master_name, builder_name, build_number, repo_name, revision): 108 def run(
109 self, master_name, builder_name, build_number, repo_name, revision,
110 send_notification_right_now):
99 action_settings = waterfall_config.GetActionSettings() 111 action_settings = waterfall_config.GetActionSettings()
100 # Set some impossible default values to prevent notification by default. 112 # Set some impossible default values to prevent notification by default.
101 build_threshold = action_settings.get( 113 build_num_threshold = action_settings.get(
102 'cr_notification_build_threshold', 100000) 114 'cr_notification_build_threshold', 100000)
103 latency_limit_minutes = action_settings.get( 115 latency_limit_minutes = action_settings.get(
104 'cr_notification_latency_limit_minutes', 1) 116 'cr_notification_latency_limit_minutes', 1)
105 117
106 commit_position, code_review_url = _GetCulpritInfo( 118 commit_position, code_review_url = _GetCulpritInfo(
107 repo_name, revision) 119 repo_name, revision)
108 build_end_time = build_util.GetBuildEndTime( 120 build_end_time = build_util.GetBuildEndTime(
109 master_name, builder_name, build_number) 121 master_name, builder_name, build_number)
110 time_limit_passed = _NotificationTimeLimitPassed( 122 within_time_limit = _WithinNotificationTimeLimit(
111 build_end_time, latency_limit_minutes) 123 build_end_time, latency_limit_minutes)
112 124
125 # Additional criteria that will help decide if a notification
126 # should be sent.
127 # TODO (chanli): Add check for if confidence for the culprit is
128 # over threshold.
129 additional_criteria = {
130 'within_time_limit': within_time_limit
131 }
132
113 if not _ShouldSendNotification( 133 if not _ShouldSendNotification(
114 master_name, builder_name, build_number, repo_name, 134 master_name, builder_name, build_number, repo_name,
115 revision, commit_position, build_threshold, time_limit_passed): 135 revision, commit_position, build_num_threshold, additional_criteria,
136 send_notification_right_now):
116 return False 137 return False
117 return _SendNotificationForCulprit( 138 return _SendNotificationForCulprit(
118 repo_name, revision, commit_position, code_review_url) 139 repo_name, revision, commit_position, code_review_url)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698