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

Side by Side Diff: sky/tools/webkitpy/tool/bot/commitannouncer.py

Issue 675343003: Prune a bunch of webkitpy. (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 6 years, 1 month 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
(Empty)
1 # Copyright (C) 2013 Google Inc. All rights reserved.
2 #
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are
5 # met:
6 #
7 # * Redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer.
9 # * Redistributions in binary form must reproduce the above
10 # copyright notice, this list of conditions and the following disclaimer
11 # in the documentation and/or other materials provided with the
12 # distribution.
13 #
14 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
26 import logging
27 import re
28 import threading
29 import time
30
31 from webkitpy.common.checkout.scm.git import Git
32 from webkitpy.common.config.irc import server, port, channel, nickname
33 from webkitpy.common.config.irc import update_wait_seconds, retry_attempts
34 from webkitpy.common.system.executive import ScriptError
35 from webkitpy.thirdparty.irc.ircbot import SingleServerIRCBot
36
37 _log = logging.getLogger(__name__)
38
39
40 class CommitAnnouncer(SingleServerIRCBot):
41 _commit_detail_format = "%H\n%cn\n%s\n%b" # commit-sha1, author, subject, b ody
42
43 def __init__(self, tool, irc_password):
44 SingleServerIRCBot.__init__(self, [(server, port, irc_password)], nickna me, nickname)
45 self.git = Git(cwd=tool.scm().checkout_root, filesystem=tool.filesystem, executive=tool.executive)
46 self.commands = {
47 'help': self.help,
48 'quit': self.stop,
49 }
50
51 def start(self):
52 if not self._update():
53 return
54 self.last_commit = self.git.latest_git_commit()
55 SingleServerIRCBot.start(self)
56
57 def post_new_commits(self):
58 if not self.connection.is_connected():
59 return
60 if not self._update(force_clean=True):
61 self.stop("Failed to update repository!")
62 return
63 new_commits = self.git.git_commits_since(self.last_commit)
64 if new_commits:
65 self.last_commit = new_commits[-1]
66 for commit in new_commits:
67 commit_detail = self._commit_detail(commit)
68 if commit_detail:
69 _log.info('%s Posting commit %s' % (self._time(), commit))
70 _log.info('%s Posted message: %s' % (self._time(), repr(comm it_detail)))
71 self._post(commit_detail)
72 else:
73 _log.error('Malformed commit log for %s' % commit)
74
75 # Bot commands.
76
77 def help(self):
78 self._post('Commands available: %s' % ' '.join(self.commands.keys()))
79
80 def stop(self, message=""):
81 self.connection.execute_delayed(0, lambda: self.die(message))
82
83 # IRC event handlers.
84
85 def on_nicknameinuse(self, connection, event):
86 connection.nick('%s_' % connection.get_nickname())
87
88 def on_welcome(self, connection, event):
89 connection.join(channel)
90
91 def on_pubmsg(self, connection, event):
92 message = event.arguments()[0]
93 command = self._message_command(message)
94 if command:
95 command()
96
97 def _update(self, force_clean=False):
98 if not self.git.is_cleanly_tracking_remote_master():
99 if not force_clean:
100 confirm = raw_input('This repository has local changes, continue ? (uncommitted changes will be lost) y/n: ')
101 if not confirm.lower() == 'y':
102 return False
103 try:
104 self.git.ensure_cleanly_tracking_remote_master()
105 except ScriptError, e:
106 _log.error('Failed to clean repository: %s' % e)
107 return False
108
109 attempts = 1
110 while attempts <= retry_attempts:
111 if attempts > 1:
112 # User may have sent a keyboard interrupt during the wait.
113 if not self.connection.is_connected():
114 return False
115 wait = int(update_wait_seconds) << (attempts - 1)
116 if wait < 120:
117 _log.info('Waiting %s seconds' % wait)
118 else:
119 _log.info('Waiting %s minutes' % (wait / 60))
120 time.sleep(wait)
121 _log.info('Pull attempt %s out of %s' % (attempts, retry_attempt s))
122 try:
123 self.git.pull()
124 return True
125 except ScriptError, e:
126 _log.error('Error pulling from server: %s' % e)
127 _log.error('Output: %s' % e.output)
128 attempts += 1
129 _log.error('Exceeded pull attempts')
130 _log.error('Aborting at time: %s' % self._time())
131 return False
132
133 def _time(self):
134 return time.strftime('[%x %X %Z]', time.localtime())
135
136 def _message_command(self, message):
137 prefix = '%s:' % self.connection.get_nickname()
138 if message.startswith(prefix):
139 command_name = message[len(prefix):].strip()
140 if command_name in self.commands:
141 return self.commands[command_name]
142 return None
143
144 def _commit_detail(self, commit):
145 return self._format_commit_detail(self.git.git_commit_detail(commit, sel f._commit_detail_format))
146
147 def _format_commit_detail(self, commit_detail):
148 if commit_detail.count('\n') < self._commit_detail_format.count('\n'):
149 return ''
150
151 commit, email, subject, body = commit_detail.split('\n', 3)
152 review_string = 'Review URL: '
153 svn_string = 'git-svn-id: svn://svn.chromium.org/blink/trunk@'
154 red_flag_strings = ['NOTRY=true', 'TBR=']
155 review_url = ''
156 svn_revision = ''
157 red_flags = []
158
159 for line in body.split('\n'):
160 if line.startswith(review_string):
161 review_url = line[len(review_string):]
162 if line.startswith(svn_string):
163 tokens = line[len(svn_string):].split()
164 if not tokens:
165 continue
166 revision = tokens[0]
167 if not revision.isdigit():
168 continue
169 svn_revision = 'r%s' % revision
170 for red_flag_string in red_flag_strings:
171 if line.lower().startswith(red_flag_string.lower()):
172 red_flags.append(line.strip())
173
174 if review_url:
175 match = re.search(r'(?P<review_id>\d+)', review_url)
176 if match:
177 review_url = 'http://crrev.com/%s' % match.group('review_id')
178 first_url = review_url if review_url else 'https://chromium.googlesource .com/chromium/blink/+/%s' % commit[:8]
179
180 red_flag_message = '\x037%s\x03' % (' '.join(red_flags)) if red_flags el se ''
181
182 return ('%s %s %s committed "%s" %s' % (svn_revision, first_url, email, subject, red_flag_message)).strip()
183
184 def _post(self, message):
185 self.connection.execute_delayed(0, lambda: self.connection.privmsg(chann el, self._sanitize_string(message)))
186
187 def _sanitize_string(self, message):
188 return message.encode('ascii', 'backslashreplace')
189
190
191 class CommitAnnouncerThread(threading.Thread):
192 def __init__(self, tool, irc_password):
193 threading.Thread.__init__(self)
194 self.bot = CommitAnnouncer(tool, irc_password)
195
196 def run(self):
197 self.bot.start()
198
199 def stop(self):
200 self.bot.stop()
201 self.join()
OLDNEW
« no previous file with comments | « sky/tools/webkitpy/tool/bot/__init__.py ('k') | sky/tools/webkitpy/tool/bot/commitannouncer_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698