Re-add the CQ directory to chrome/trunk/tools.
[chromium/tools/commit-queue.git] / projects.py
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
3 # found in the LICENSE file.
4 """Define the supported projects."""
5
6 import json
7 import logging
8 import os
9 import re
10 import sys
11 import urllib2
12
13 import find_depot_tools  # pylint: disable=W0611
14 import checkout
15
16 import async_push
17 import context
18 import creds
19 import errors
20 import pending_manager
21 from verification import presubmit_check
22 from verification import project_base
23 from verification import reviewer_lgtm
24 from verification import tree_status
25 from verification import try_server
26 from verification import try_job_on_rietveld
27
28 ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
29 sys.path.append(os.path.join(ROOT_DIR, '..', 'commit-queue-internal'))
30
31 # These come from commit-queue in the internal repo.
32 try:
33   import chromium_committers  # pylint: disable=F0401
34   import gyp_committers  # pylint: disable=F0401
35   import nacl_committers  # pylint: disable=F0401
36 except ImportError, e:
37   print >> sys.stderr, (
38       'Failed to find commit-queue-internal, will fail to start: %s' % e)
39   chromium_committers = None
40   gyp_committers = None
41   nacl_committers = None
42
43
44 # It's tricky here because 'chrome' is remapped to 'svn' on src.chromium.org but
45 # the other repositories keep their repository name. So don't list it here.
46 SVN_HOST_ALIASES = [
47     'svn://svn.chromium.org',
48     'svn://chrome-svn',
49     'svn://chrome-svn.corp',
50     'svn://chrome-svn.corp.google.com'
51 ]
52
53 CHROME_SVN_BASES = [item + '/chrome' for item in SVN_HOST_ALIASES] + [
54     'http://src.chromium.org/svn',
55     'https://src.chromium.org/svn',
56     'http://src.chromium.org/chrome',
57     'https://src.chromium.org/chrome',
58 ]
59
60 # Steps that are never considered to determine the try job success.
61 IGNORED_STEPS = (
62   'svnkill', 'update_scripts', 'taskkill', 'cleanup_temp', 'process_dumps')
63
64 # To be used in a regexp to match the branch part of an git url.
65 BRANCH_MATCH = r'\@[a-zA-Z0-9\-_]+'
66
67
68 def _read_lines(filepath, what):
69   try:
70     return open(filepath).readlines()
71   except IOError:
72     raise errors.ConfigurationError('Put the %s in %s' % (what, filepath))
73
74
75 def _get_chromium_committers():
76   """Gets the list of all allowed committers."""
77   if not chromium_committers:
78     # Fake values.
79     entries = ['georges']
80   else:
81     entries = chromium_committers.get_list()
82   logging.info('Found %d committers' % len(entries))
83   return ['^%s$' % re.escape(i) for i in entries]
84
85
86 def _get_nacl_committers():
87   """Gets the list of all allowed committers."""
88   if not nacl_committers:
89     # Fake values.
90     entries = ['georges']
91   else:
92     entries = nacl_committers.get_list()
93   logging.info('Found %d committers' % len(entries))
94   return ['^%s$' % re.escape(i) for i in entries]
95
96
97 def _get_gyp_committers():
98   """Gets the list of all allowed committers."""
99   if not gyp_committers:
100     # Fake values.
101     entries = ['georges']
102   else:
103     entries = gyp_committers.get_list()
104   logging.info('Found %d committers' % len(entries))
105   return ['^%s$' % re.escape(i) for i in entries]
106
107
108 def _chromium_lkgr():
109   try:
110     return int(
111         urllib2.urlopen('https://chromium-status.appspot.com/lkgr').read())
112   except (ValueError, IOError):
113     return None
114
115
116 def _nacl_lkgr():
117   try:
118     return int(
119         urllib2.urlopen('https://nativeclient-status.appspot.com/lkgr').read())
120   except (ValueError, IOError):
121     return None
122
123
124 def _chromium_status_pwd(root_dir):
125   filepath = os.path.join(root_dir, '.chromium_status_pwd')
126   return _read_lines(filepath, 'chromium-status password')[0].strip()
127
128
129 def _gen_chromium(user, root_dir, rietveld_obj, no_try):
130   """Generates a PendingManager commit queue for chrome/trunk/src."""
131   svn_creds = creds.Credentials(os.path.join(root_dir, '.svn_pwd'))
132   local_checkout = checkout.SvnCheckout(
133       root_dir,
134       'chromium',
135       user,
136       svn_creds.get(user),
137       'svn://svn.chromium.org/chrome/trunk/src',
138       [])
139   context_obj = context.Context(
140       rietveld_obj,
141       local_checkout,
142       async_push.AsyncPush(
143         'https://chromium-status.appspot.com/cq',
144         _chromium_status_pwd(root_dir)))
145
146   project_bases = [
147       '^%s/trunk/src(|/.*)$' % re.escape(base) for base in CHROME_SVN_BASES]
148
149   aliases = (
150     # Old path.
151     'http://git.chromium.org/git/chromium.git',
152     'https://git.chromium.org/git/chromium.git',
153     # New path.
154     'http://git.chromium.org/chromium/src.git',
155     'https://git.chromium.org/chromium/src.git',
156     'http://git.chromium.org/git/chromium/src',
157     'https://git.chromium.org/git/chromium/src',
158     'http://git.chromium.org/git/chromium/src.git',
159     'https://git.chromium.org/git/chromium/src.git',
160     'https://chromium.googlesource.com/chromium/src',
161     'https://chromium.googlesource.com/chromium/src.git',
162   )
163   project_bases.extend(
164       r'^%s%s$' % (re.escape(i), BRANCH_MATCH) for i in aliases)
165   verifiers_no_patch = [
166       project_base.ProjectBaseUrlVerifier(project_bases),
167       reviewer_lgtm.ReviewerLgtmVerifier(
168           _get_chromium_committers(),
169           [re.escape(user)]),
170   ]
171   verifiers = [
172       presubmit_check.PresubmitCheckVerifier(context_obj),
173   ]
174   if not no_try:
175     # To add tests to this list, they MUST be in
176     # /chrome/trunk/tools/build/masters/master.chromium/master_gatekeeper_cfg.py
177     # or somehow close the tree whenever they break.
178     standard_tests = [
179         'base_unittests',
180         'browser_tests',
181         'check_deps',
182         'cacheinvalidation_unittests',
183         'content_browsertests',
184         'content_unittests',
185         'crypto_unittests',
186         #'gfx_unittests',
187         # Broken in release.
188         #'googleurl_unittests',
189         'gpu_unittests',
190         'ipc_tests',
191         'interactive_ui_tests',
192         'jingle_unittests',
193         'media_unittests',
194         'net_unittests',
195         'printing_unittests',
196         # Too flaky.
197         #'pyauto_functional_tests',
198         'sql_unittests',
199         'sync_unit_tests',
200         #'ui_tests',
201         # Tends to be broken by webkit roll and not fixed fast enough.
202         #'test_shell_tests',
203         'unit_tests',
204         #'webkit_unit_tests',
205     ]
206     builders_and_tests = {
207       # TODO(maruel): Figure out a way to run 'sizes' where people can
208       # effectively update the perf expectation correctly.  This requires a
209       # clobber=True build running 'sizes'. 'sizes' is not accurate with
210       # incremental build. Reference:
211       # http://chromium.org/developers/tree-sheriffs/perf-sheriffs.
212       # TODO(maruel): An option would be to run 'sizes' but not count a failure
213       # of this step as a try job failure.
214       'linux_rel': standard_tests + [
215         'nacl_integration',
216         'remoting_unittests',
217         'sandbox_linux_unittests',
218         'sync_integration_tests',
219       ],
220       'mac': ['compile'],
221       'mac_rel': standard_tests + [
222         'nacl_integration',
223         'remoting_unittests',
224         'sync_integration_tests',
225       ],
226       'win_rel': standard_tests + [
227         'chrome_frame_net_tests',
228         'chrome_frame_unittests',
229         'installer_util_unittests',
230         'mini_installer_test',
231         'nacl_integration',
232         'remoting_unittests',
233         'sync_integration_tests',
234       ],
235       'win': ['compile'],
236       'linux_clang': ['compile'],
237       'linux_chromeos': standard_tests + [
238         'sandbox_linux_unittests',
239       ],
240       'android_dbg': ['build'],
241       'ios_rel_device': ['compile'],
242       'ios_dbg_simulator': [
243         'compile',
244         'base_unittests',
245         'crypto_unittests',
246         'googleurl_unittests',
247         'sql_unittests',
248       ],
249     }
250     triggered_builders_and_tests = [
251       ('android_dbg_triggered_tests', 'android_dbg', ['build']),
252     ]
253
254     verifiers.append(try_job_on_rietveld.TryRunnerRietveld(
255         context_obj,
256         'http://build.chromium.org/p/tryserver.chromium/',
257         user,
258         builders_and_tests,
259         triggered_builders_and_tests,
260         IGNORED_STEPS,
261         'src'))
262
263   verifiers.append(tree_status.TreeStatusVerifier(
264       'http://chromium-status.appspot.com'))
265   return pending_manager.PendingManager(
266       context_obj,
267       verifiers_no_patch,
268       verifiers)
269
270
271 def _gen_nacl(user, root_dir, rietveld_obj, no_try):
272   """Generates a PendingManager commit queue for Native Client."""
273   svn_creds = creds.Credentials(os.path.join(root_dir, '.svn_pwd'))
274   offset = 'trunk/src/native_client'
275   local_checkout = checkout.SvnCheckout(
276       root_dir,
277       'nacl',
278       user,
279       svn_creds.get(user),
280       'svn://svn.chromium.org/native_client/' + offset)
281   context_obj = context.Context(
282       rietveld_obj,
283       local_checkout,
284       async_push.AsyncPush(
285         'https://nativeclient-status.appspot.com/cq',
286         _chromium_status_pwd(root_dir)))
287
288   host_aliases = SVN_HOST_ALIASES + [
289       'http://src.chromium.org', 'https://src.chromium.org']
290   svn_bases = [i + '/native_client' for i in host_aliases]
291   project_bases = [
292       '^%s/%s(|/.*)$' % (re.escape(base), offset) for base in svn_bases
293   ]
294   git_url = 'http://git.chromium.org/native_client/src/native_client.git'
295   project_bases.append('^%s%s$' % (re.escape(git_url), BRANCH_MATCH))
296   verifiers_no_patch = [
297       project_base.ProjectBaseUrlVerifier(project_bases),
298       reviewer_lgtm.ReviewerLgtmVerifier(
299           _get_nacl_committers(),
300           [re.escape(user)]),
301   ]
302   verifiers = [
303       presubmit_check.PresubmitCheckVerifier(context_obj),
304   ]
305   if not no_try:
306     # Grab the list of all the builders here. The commit queue needs to know
307     # which builders were triggered. TODO: makes this more automatic.
308     url = 'http://build.chromium.org/p/tryserver.nacl/json/builders'
309     builders_and_tests = dict(
310       (key, []) for key in json.load(urllib2.urlopen(url))
311       if (key.startswith('nacl-') and
312           'toolchain' not in key and
313           'valgrind' not in key and
314           'perf_panda' not in key and
315           'arm_hw' not in key and
316           'shared' not in key and
317           'coverage' not in key)
318     )
319     verifiers.append(try_server.TryRunnerSvn(
320         context_obj,
321         'http://build.chromium.org/p/tryserver.nacl/',
322         user,
323         builders_and_tests,
324         IGNORED_STEPS,
325         'native_client',
326         ['--root', 'native_client'],
327         _nacl_lkgr))
328
329   verifiers.append(tree_status.TreeStatusVerifier(
330       'http://nativeclient-status.appspot.com'))
331   return pending_manager.PendingManager(
332       context_obj,
333       verifiers_no_patch,
334       verifiers)
335
336
337 def _gen_gyp(user, root_dir, rietveld_obj, no_try):
338   """Generates a PendingManager commit queue for GYP."""
339   svn_creds = creds.Credentials(os.path.join(root_dir, '.svn_pwd'))
340   naked_url = '://gyp.googlecode.com/svn/trunk'
341   local_checkout = checkout.SvnCheckout(
342       root_dir,
343       'gyp',
344       user,
345       svn_creds.get(user),
346       'https' + naked_url)
347   context_obj = context.Context(
348       rietveld_obj,
349       local_checkout,
350       async_push.AsyncPush(
351         'https://chromium-status.appspot.com/cq/receiver',
352         _chromium_status_pwd(root_dir)))
353
354   project_bases = [
355       '^%s(|/.*)$' % re.escape(base + naked_url) for base in ('http', 'https')
356   ]
357   verifiers_no_patch = [
358       project_base.ProjectBaseUrlVerifier(project_bases),
359       reviewer_lgtm.ReviewerLgtmVerifier(
360           _get_gyp_committers(),
361           [re.escape(user)]),
362   ]
363   verifiers = []
364   if not no_try:
365     # Grab the list of all the builders here. The commit queue needs to know
366     # which builders were triggered. TODO: makes this more automatic.
367     # GYP is using the Nacl try server.
368     url = 'http://build.chromium.org/p/tryserver.nacl/json/builders'
369     builders_and_tests = dict(
370       (key, []) for key in json.load(urllib2.urlopen(url))
371       if key.startswith('gyp-')
372     )
373     verifiers.append(try_server.TryRunnerSvn(
374         context_obj,
375         'http://build.chromium.org/p/tryserver.nacl/',
376         user,
377         builders_and_tests,
378         IGNORED_STEPS,
379         'gyp',
380         ['--root', 'gyp'],
381         lambda: None))
382
383   verifiers.append(tree_status.TreeStatusVerifier(
384       'http://gyp-status.appspot.com/status'))
385   return pending_manager.PendingManager(
386       context_obj,
387       verifiers_no_patch,
388       verifiers)
389
390
391 def _gen_tools(user, root_dir, rietveld_obj, _no_try):
392   """Generates a PendingManager commit queue for everything under
393   chrome/trunk/tools.
394
395   These don't have a try server but have presubmit checks.
396   """
397   # Ignore no_try.
398   path = 'tools'
399   project_bases = [
400       '^%s/trunk/%s(|/.*)$' % (re.escape(base), path)
401       for base in CHROME_SVN_BASES
402   ]
403   regexp = r'([a-z0-9\-_]+)'
404   githost = '://git.chromium.org/'
405   googlesource = '://chromium.googlesource.com/'
406   aliases = (
407     re.escape( 'http' + githost + 'chromium/tools/') + regexp + r'\.git',
408     re.escape('https' + githost + 'chromium/tools/') + regexp + r'\.git',
409     re.escape( 'http' + githost + 'git/chromium/tools/') + regexp,
410     re.escape('https' + githost + 'git/chromium/tools/') + regexp,
411     re.escape( 'http' + githost + 'git/chromium/tools/') + regexp + r'\.git',
412     re.escape('https' + githost + 'git/chromium/tools/') + regexp + r'\.git',
413     re.escape('https' + googlesource + 'chromium/tools/') + regexp,
414     re.escape('https' + googlesource + 'chromium/tools/') + regexp + r'\.git',
415   )
416   project_bases.extend('^%s%s$' % (i, BRANCH_MATCH) for i in aliases)
417   return _internal_simple(path, project_bases, user, root_dir, rietveld_obj)
418
419
420 def _gen_chromium_deps(user, root_dir, rietveld_obj, _no_try):
421   """Generates a PendingManager commit queue for
422   chrome/trunk/deps/.
423   """
424   # Ignore no_try.
425   path = 'deps'
426   project_bases = [
427       '^%s/trunk/%s(|/.*)$' % (re.escape(base), path)
428       for base in CHROME_SVN_BASES
429   ]
430   return _internal_simple(path, project_bases, user, root_dir, rietveld_obj)
431
432
433 def _internal_simple(path, project_bases, user, root_dir, rietveld_obj):
434   """Generates a PendingManager commit queue for chrome/trunk/tools/build."""
435   svn_creds = creds.Credentials(os.path.join(root_dir, '.svn_pwd'))
436   local_checkout = checkout.SvnCheckout(
437       root_dir,
438       os.path.basename(path),
439       user,
440       svn_creds.get(user),
441       'svn://svn.chromium.org/chrome/trunk/' + path,
442       [])
443   context_obj = context.Context(
444       rietveld_obj,
445       local_checkout,
446       async_push.AsyncPush(
447         'https://chromium-status.appspot.com/cq',
448         _chromium_status_pwd(root_dir)))
449
450   verifiers_no_patch = [
451       project_base.ProjectBaseUrlVerifier(project_bases),
452       reviewer_lgtm.ReviewerLgtmVerifier(
453           _get_chromium_committers(),
454           [re.escape(user)]),
455   ]
456   verifiers = [
457       presubmit_check.PresubmitCheckVerifier(context_obj, timeout=900),
458   ]
459
460   return pending_manager.PendingManager(
461       context_obj,
462       verifiers_no_patch,
463       verifiers)
464
465
466 def supported_projects():
467   """List the projects that can be managed by the commit queue."""
468   return sorted(
469       x[5:] for x in dir(sys.modules[__name__]) if x.startswith('_gen_'))
470
471
472 def load_project(project, user, root_dir, rietveld_obj, no_try):
473   """Loads the specified project."""
474   assert os.path.isabs(root_dir)
475   return getattr(sys.modules[__name__], '_gen_' + project)(
476       user, root_dir, rietveld_obj, no_try)