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

Side by Side Diff: scripts/master/cros_try_job_git.py

Issue 1344673003: CrOS: Switch tryserver over to recipes, Gitiles. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Update comment. Created 5 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 | Annotate | Revision Log
OLDNEW
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 # Copyright (c) 2012 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 import base64
5 import json 6 import json
6 import os 7 import os
7 import re 8 import re
8 import shutil 9 import shutil
9 10
10 from StringIO import StringIO 11 from StringIO import StringIO
11 12
12 try: 13 try:
13 # Create a block to work around evil sys.modules manipulation in 14 # Create a block to work around evil sys.modules manipulation in
14 # email/__init__.py that triggers pylint false positives. 15 # email/__init__.py that triggers pylint false positives.
15 # pylint: disable=E0611,F0401 16 # pylint: disable=E0611,F0401
16 from email.Message import Message 17 from email.Message import Message
17 from email.Utils import formatdate 18 from email.Utils import formatdate
18 except ImportError: 19 except ImportError:
19 raise 20 raise
20 21
21 from buildbot.process.properties import Properties 22 from buildbot.process.properties import Properties
22 from buildbot.schedulers.trysched import TryBase 23 from buildbot.schedulers.trysched import TryBase
23 24
24 from twisted.internet import defer, reactor, utils 25 from twisted.internet import defer, reactor, utils
25 from twisted.mail.smtp import SMTPSenderFactory 26 from twisted.mail.smtp import SMTPSenderFactory
26 from twisted.python import log 27 from twisted.python import log
27 28
29 from common.twisted_util.response import StringResponse
30 from master import gitiles_poller
28 from master.try_job_base import BadJobfile 31 from master.try_job_base import BadJobfile
29 32
30 33
31 class InvalidEtcBuild(BadJobfile): 34 class InvalidEtcBuild(BadJobfile):
32 pass 35 pass
33 36
34 37
35 def get_file_contents(poller, branch, file_path):
36 """Returns a Deferred to returns the file's content."""
37 return utils.getProcessOutput(
38 poller.gitbin,
39 ['show', 'origin/%s:%s' % (branch, file_path)],
40 path=poller.workdir,
41 )
42
43
44 def translate_v1_to_v2(parsed_job): 38 def translate_v1_to_v2(parsed_job):
45 """Translate tryjob desc from V1 to V2.""" 39 """Translate tryjob desc from V1 to V2."""
46 parsed_job.setdefault('extra_args', []).append('--remote-trybot') 40 parsed_job.setdefault('extra_args', []).append('--remote-trybot')
47 parsed_job['version'] = 2 41 parsed_job['version'] = 2
48 42
49 43
50 def translate_v2_to_v3(parsed_job): 44 def translate_v2_to_v3(parsed_job):
51 """Translate tryjob desc from V2 to V3.""" 45 """Translate tryjob desc from V2 to V3."""
52 # V3 --remote-patches format is not backwards compatible. 46 # V3 --remote-patches format is not backwards compatible.
53 if any(a.startswith('--remote-patches') 47 if any(a.startswith('--remote-patches')
(...skipping 15 matching lines...) Expand all
69 _TRANSLATION_FUNCS = { 63 _TRANSLATION_FUNCS = {
70 1 : translate_v1_to_v2, 64 1 : translate_v1_to_v2,
71 2 : translate_v2_to_v3, 65 2 : translate_v2_to_v3,
72 } 66 }
73 67
74 # Valid 'etc' builder targets. Specifically, this ensures: 68 # Valid 'etc' builder targets. Specifically, this ensures:
75 # - The build name doesn't begin with a flag ('--') 69 # - The build name doesn't begin with a flag ('--')
76 # - The build name doesn't contain spaces (to spill into extra args). 70 # - The build name doesn't contain spaces (to spill into extra args).
77 ETC_TARGET_RE = re.compile(r'^[a-zA-Z][\w-]+\w$') 71 ETC_TARGET_RE = re.compile(r'^[a-zA-Z][\w-]+\w$')
78 72
73 # Template path URL component to retrieve the Base64 contents of a file from
74 # Gitiles.
75 _GITILES_PATH_TMPL = '%(repo)s/+/%(revision)s/%(path)s?format=text'
76
79 @classmethod 77 @classmethod
80 def updateJobDesc(cls, parsed_job): 78 def updateJobDesc(cls, parsed_job):
81 """Ensure job description is in the format we expect.""" 79 """Ensure job description is in the format we expect."""
82 while parsed_job['version'] < cls._TRYJOB_FORMAT_VERSION: 80 while parsed_job['version'] < cls._TRYJOB_FORMAT_VERSION:
83 prev_ver = parsed_job['version'] 81 prev_ver = parsed_job['version']
84 translation_func = cls._TRANSLATION_FUNCS[parsed_job['version']] 82 translation_func = cls._TRANSLATION_FUNCS[parsed_job['version']]
85 translation_func(parsed_job) 83 translation_func(parsed_job)
86 if parsed_job['version'] <= prev_ver: 84 if parsed_job['version'] <= prev_ver:
87 raise AssertionError('translation function %s not incrementing version!' 85 raise AssertionError('translation function %s not incrementing version!'
88 % str(translation_func)) 86 % str(translation_func))
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
192 # Calculate the buildroot for builds. 190 # Calculate the buildroot for builds.
193 config_dict = self.cbuildbot_configs.get(config) 191 config_dict = self.cbuildbot_configs.get(config)
194 if config_dict is None: 192 if config_dict is None:
195 buildroot = '/b/cbuild/etc_master' 193 buildroot = '/b/cbuild/etc_master'
196 elif config_dict['internal']: 194 elif config_dict['internal']:
197 buildroot = '/b/cbuild/internal_master' 195 buildroot = '/b/cbuild/internal_master'
198 else: 196 else:
199 buildroot = '/b/cbuild/external_master' 197 buildroot = '/b/cbuild/external_master'
200 props.setProperty('buildroot', buildroot, self._PROPERTY_SOURCE) 198 props.setProperty('buildroot', buildroot, self._PROPERTY_SOURCE)
201 199
202 props.setProperty('extra_args', options.get('extra_args', []),
203 self._PROPERTY_SOURCE)
204 props.setProperty('slaves_request', options.get('slaves_request', []), 200 props.setProperty('slaves_request', options.get('slaves_request', []),
205 self._PROPERTY_SOURCE) 201 self._PROPERTY_SOURCE)
206 props.setProperty('chromeos_config', config, self._PROPERTY_SOURCE) 202 props.setProperty('cbb_config', config, self._PROPERTY_SOURCE)
207 203
208 return props 204 return props
209 205
210 def create_buildset(self, ssid, parsed_job): 206 def create_buildset(self, ssid, parsed_job):
211 """Overriding base class method.""" 207 """Overriding base class method."""
212 dlist = [] 208 dlist = []
213 buildset_name = '%s:%s' % (parsed_job['user'], parsed_job['name']) 209 buildset_name = '%s:%s' % (parsed_job['user'], parsed_job['name'])
214 for bot in parsed_job['bot']: 210 for bot in parsed_job['bot']:
215 config = self.cbuildbot_configs.get(bot) 211 config = self.cbuildbot_configs.get(bot)
216 if config: 212 if config:
(...skipping 27 matching lines...) Expand all
244 m.set_type("text/html") 240 m.set_type("text/html")
245 m['Date'] = formatdate(localtime=True) 241 m['Date'] = formatdate(localtime=True)
246 m['Subject'] = 'Tryjob failed validation' 242 m['Subject'] = 'Tryjob failed validation'
247 m['From'] = self.from_addr 243 m['From'] = self.from_addr
248 m['Reply-To'] = self.reply_to 244 m['Reply-To'] = self.reply_to
249 result = defer.Deferred() 245 result = defer.Deferred()
250 sender_factory = SMTPSenderFactory(self.from_addr, emails, 246 sender_factory = SMTPSenderFactory(self.from_addr, emails,
251 StringIO(m.as_string()), result) 247 StringIO(m.as_string()), result)
252 reactor.connectTCP(self.smtp_host, 25, sender_factory) 248 reactor.connectTCP(self.smtp_host, 25, sender_factory)
253 249
254 @defer.deferredGenerator 250 @defer.inlineCallbacks
255 def gotChange(self, change, important): 251 def gotChange(self, change, important):
256 """Process the received data and send the queue buildset.""" 252 """Process the received data and send the queue buildset."""
257 # Implicitly skips over non-files like directories.
258 if len(change.files) != 1:
259 # We only accept changes with 1 diff file.
260 raise BadJobfile(
261 'Try job with too many files %s' % (','.join(change.files)))
262
263 # Find poller that this change came from. 253 # Find poller that this change came from.
264 for poller in self.pollers: 254 for poller in self.pollers:
265 if poller.repourl == change.repository: 255 if not isinstance(poller, gitiles_poller.GitilesPoller):
256 continue
257 if poller.repo_url == change.repository:
266 break 258 break
267 else: 259 else:
268 raise BadJobfile( 260 raise BadJobfile(
269 'Received tryjob from unsupported repository %s' % change.repository) 261 'Received tryjob from unsupported repository %s' % change.repository)
270 262
271 # pylint: disable=W0631 263 # pylint: disable=W0631
272 wfd = defer.waitForDeferred( 264 file_contents = yield self.loadGitilesChangeFile(poller, change)
273 get_file_contents(poller, change.branch, change.files[0]))
274 yield wfd
275 265
276 parsed = None 266 parsed = {}
277 try: 267 try:
278 parsed = self.load_job(wfd.getResult()) 268 parsed = self.load_job(file_contents)
279 self.validate_job(parsed) 269 self.validate_job(parsed)
280 self.updateJobDesc(parsed) 270 self.updateJobDesc(parsed)
281 except BadJobfile as e: 271 except BadJobfile as e:
282 self.send_validation_fail_email(parsed.setdefault('name', ''), 272 self.send_validation_fail_email(parsed.setdefault('name', ''),
283 parsed['email'], str(e)) 273 parsed['email'], str(e))
284 raise 274 raise
285 except Exception as e: 275 except Exception as e:
286 print 'EXCEPTION:', e 276 print 'EXCEPTION:', e
287 import traceback 277 import traceback
288 traceback.print_exc() 278 traceback.print_exc()
289 raise 279 raise
290 280
291 # The sourcestamp/buildsets created will be merge-able. 281 # The sourcestamp/buildsets created will be merge-able.
292 d = self.master.db.sourcestamps.addSourceStamp( 282 ssid = yield self.master.db.sourcestamps.addSourceStamp(
293 branch=change.branch, 283 branch=change.branch,
294 revision=change.revision, 284 revision=change.revision,
295 project=change.project, 285 project=change.project,
296 repository=change.repository, 286 repository=change.repository,
297 changeids=[change.number]) 287 changeids=[change.number])
298 d.addCallback(self.create_buildset, parsed) 288 yield self.create_buildset(ssid, parsed)
299 d.addErrback(log.err, "Failed to queue a try job!") 289
290 @defer.inlineCallbacks
291 def loadGitilesChangeFile(self, poller, change):
292 if len(change.files) != 1:
293 # We only accept changes with 1 diff file.
294 raise BadJobfile(
David James 2015/09/15 19:35:51 What happens when somebody has a commit that affec
phobbs 2015/09/15 21:27:49 I think there would still be only one diff in that
David James 2015/09/15 21:34:37 I mean that somebody did a manual commit in the tr
dnj 2015/09/15 21:55:52 Yes, we expect a push that has been formulated by
295 'Try job with too many files %s' % (','.join(change.files)))
296
297 # Load the contents of the modified file.
298 path = self._GITILES_PATH_TMPL % {
299 'repo': poller.repo_path,
300 'revision': change.revision,
301 'path': change.files[0],
302 }
303 contents_b64 = yield poller.agent.request('GET', path, retry=5,
304 protocol=StringResponse.Get)
305 defer.returnValue(base64.b64decode(contents_b64))
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698