blob: 9002d98873d3416c308038da9b39b33cd9911787 [file] [log] [blame]
borenet@google.com6b5388e2013-01-23 20:54:29 +00001#!/usr/bin/python
2
3# Copyright (c) 2013 The Chromium Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7
8"""
9submit_try: Submit a try request.
10
11This is a thin wrapper around the try request utilities in depot_tools which
12adds some validation and supports both git and svn.
13"""
14
15
borenet@google.com6b5388e2013-01-23 20:54:29 +000016import httplib
17import json
18import os
19import subprocess
20import sys
21
22
23# Alias which can be used to run a try on every builder.
24ALL_BUILDERS = 'all'
25
26# Contact information for the build master.
27# TODO(borenet): Share this information from a single location. Filed bug:
28# http://code.google.com/p/skia/issues/detail?id=1081
borenet@google.com69b50e32013-02-05 20:26:31 +000029SKIA_BUILD_MASTER_HOST = '70.32.156.53'
borenet@google.com6b5388e2013-01-23 20:54:29 +000030SKIA_BUILD_MASTER_PORT = '10117'
31
32# All try builders have this suffix.
33TRYBOT_SUFFIX = '_Trybot'
34
35# Location of the codereview.settings file in the Skia repo.
36SKIA_URL = 'skia.googlecode.com'
37CODEREVIEW_SETTINGS = '/svn/codereview.settings'
38
39# String for matching the svn url of the try server inside codereview.settings.
40TRYSERVER_SVN_URL = 'TRYSERVER_SVN_URL: '
41
42# Strings used for matching svn config properties.
43URL_STR = 'URL: '
44REPO_ROOT_STR = 'Repository Root: '
45
46
47def FindDepotTools():
48 """ Find depot_tools on the local machine and return its location. """
49 which_cmd = 'where' if os.name == 'nt' else 'which'
50 cmd = [which_cmd, 'gcl']
51 proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
52 if proc.wait() != 0:
53 raise Exception('Couldn\'t find depot_tools in PATH!')
borenet@google.com6c55b512013-01-24 21:38:51 +000054 gcl = proc.communicate()[0].split('\n')[0].rstrip()
borenet@google.com6b5388e2013-01-23 20:54:29 +000055 depot_tools_dir = os.path.dirname(gcl)
56 return depot_tools_dir
57
58
59def GetCheckoutRoot(is_svn=True):
60 """ Determine where the local checkout is rooted.
61
62 is_svn: boolean; whether we're in an SVN checkout. If False, assume we're in
63 a git checkout.
64 """
65 if is_svn:
borenet@google.com6c55b512013-01-24 21:38:51 +000066 svn_cmd = 'svn.bat' if os.name == 'nt' else 'svn'
67 cmd = [svn_cmd, 'info']
borenet@google.com6b5388e2013-01-23 20:54:29 +000068 proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
69 stderr=subprocess.STDOUT)
70 if proc.wait() != 0:
71 raise Exception('Couldn\'t find checkout root!')
72 output = proc.communicate()[0].split('\n')
73 url = None
74 repo_root = None
75 for line in output:
76 if line.startswith(REPO_ROOT_STR):
77 repo_root = line[len(REPO_ROOT_STR):].rstrip()
78 elif line.startswith(URL_STR):
79 url = line[len(URL_STR):].rstrip()
80 if not url or not repo_root:
81 raise Exception('Couldn\'t find checkout root!')
82 if url == repo_root:
83 return 'svn'
84 return url[len(repo_root)+1:]
85 else:
86 cmd = ['git', 'rev-parse', '--show-toplevel']
87 proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
88 stderr=subprocess.STDOUT)
89 if proc.wait() != 0:
90 raise Exception('Couldn\'t find checkout root!')
91 return os.path.basename(proc.communicate()[0])
92
93
94def GetTryRepo():
95 """ Determine the TRYSERVER_SVN_URL from the codereview.settings file in the
96 Skia repo. """
97 connection = httplib.HTTPConnection(SKIA_URL)
98 connection.request('GET', CODEREVIEW_SETTINGS)
99 content = connection.getresponse().read()
100 for line in content.split('\n'):
101 if line.startswith(TRYSERVER_SVN_URL):
102 return line[len(TRYSERVER_SVN_URL):].rstrip()
103 raise Exception('Couldn\'t determine the TRYSERVER_SVN_URL. Make sure it is '
104 'defined in the %s file.' % CODEREVIEW_SETTINGS)
105
106
107def RetrieveTrybotList():
108 """ Retrieve the list of known trybots from the build master, stripping
109 TRYBOT_SUFFIX from the name. """
110 trybots = []
111 connection = httplib.HTTPConnection(SKIA_BUILD_MASTER_HOST,
112 SKIA_BUILD_MASTER_PORT)
113 connection.request('GET', '/json/builders')
114 response = connection.getresponse()
115 builders = json.load(response)
116
117 for builder in builders:
118 if builder.endswith(TRYBOT_SUFFIX):
119 trybots.append(builder[:-len(TRYBOT_SUFFIX)])
120 return trybots
121
122
borenet@google.coma5d621f2013-01-25 20:55:35 +0000123def ValidateArgs(argv, trybots, is_svn=True):
borenet@google.com6b5388e2013-01-23 20:54:29 +0000124 """ Parse and validate command-line arguments. If the arguments are valid,
125 returns a tuple of (<changelist name>, <list of trybots>).
126
127 trybots: A list of the known try builders.
128 """
borenet@google.com6b5388e2013-01-23 20:54:29 +0000129
borenet@google.coma5d621f2013-01-25 20:55:35 +0000130 class CollectedArgs(object):
131 def __init__(self, bots, changelist, revision):
132 self._bots = bots
133 self._changelist = changelist
134 self._revision = revision
135
136 @property
137 def bots(self):
138 for bot in self._bots:
139 yield bot
140
141 @property
142 def changelist(self):
143 return self._changelist
144
145 @property
146 def revision(self):
147 return self._revision
148
149 usage = (
150"""submit_try: Submit a try request.
151submit_try %s--bot <buildername> [<buildername> ...]
152
153--bot Builder on which to run the try. Required.
154-h, --help Show this message.
155-r <revision#> Revision from which to run the try.
156-l, --list_bots List the available try builders and exit.
157""" % ('<changelist> ' if is_svn else ''))
158
159 def Error(msg=None):
160 if msg:
161 print msg
162 print usage
163 sys.exit(1)
164
165 using_bots = None
166 changelist = None
167 revision = None
168
169 while argv:
170 arg = argv.pop(0)
171 if arg == '-h' or arg == '--help':
172 Error()
173 elif arg == '-l' or arg == '--list_bots':
174 print 'submit_try: Available builders:\n %s' % '\n '.join(trybots)
175 sys.exit(0)
176 elif arg == '--bot':
177 if using_bots:
178 Error('--bot specified multiple times.')
179 if len(argv) < 1:
180 Error('You must specify a builder with "--bot".')
181 using_bots = []
182 while argv and not argv[0].startswith('-'):
183 bot = argv.pop(0)
184 if bot == ALL_BUILDERS:
185 if using_bots:
186 Error('Cannot specify "all" with additional builder names.')
187 using_bots = trybots
188 break
189 else:
190 if not bot in trybots:
191 Error('Unrecognized builder: %s' % bot)
192 using_bots.append(bot)
193 elif arg == '-r':
194 if len(argv) < 1:
195 Error('You must specify a revision with "-r".')
196 revision = argv.pop(0)
197 else:
198 if changelist or not is_svn:
199 Error('Unknown argument: %s' % arg)
200 changelist = arg
201 if is_svn and not changelist:
202 Error('You must specify a changelist name.')
203 if not using_bots:
204 Error('You must specify one or more builders using --bot.')
205 return CollectedArgs(bots=using_bots, changelist=changelist,
206 revision=revision)
borenet@google.com6b5388e2013-01-23 20:54:29 +0000207
208
209def SubmitTryRequest(args, is_svn=True):
210 """ Submits a try request for the given changelist on the given list of
211 trybots.
212
213 args: Object whose properties are derived from command-line arguments. If
214 is_svn is True, it should contain:
215 - changelist: string; the name of the changelist to try.
216 - bot: list of strings; the names of the try builders to run.
217 - revision: optional, int; the revision number from which to run the try.
218 If is_svn is False, it should contain:
219 - bot: list of strings; the names of the try builders to run.
220 - revision: optional, int; the revision number from which to run the try.
221 is_svn: boolean; are we in an SVN repo?
222 """
borenet@google.coma5d621f2013-01-25 20:55:35 +0000223 botlist = ','.join(['%s%s' % (bot, TRYBOT_SUFFIX) for bot in args.bots])
borenet@google.com6b5388e2013-01-23 20:54:29 +0000224 if is_svn:
borenet@google.com6c55b512013-01-24 21:38:51 +0000225 gcl_cmd = 'gcl.bat' if os.name == 'nt' else 'gcl'
226 try_args = [gcl_cmd, 'try', args.changelist,
227 '--root', GetCheckoutRoot(is_svn),
borenet@google.com6b5388e2013-01-23 20:54:29 +0000228 '--bot', botlist]
229 if args.revision:
230 try_args.extend(['-r', args.revision])
borenet@google.com6c55b512013-01-24 21:38:51 +0000231 print ' '.join(try_args)
232 proc = subprocess.Popen(try_args, stdout=subprocess.PIPE,
233 stderr=subprocess.STDOUT)
234 if proc.wait() != 0:
235 raise Exception('Failed to submit try request: %s' % (
236 proc.communicate()[0]))
237 print proc.communicate()[0]
borenet@google.com6b5388e2013-01-23 20:54:29 +0000238 else:
borenet@google.com6c55b512013-01-24 21:38:51 +0000239 # First, find depot_tools. This is needed to import trychange.
240 sys.path.append(FindDepotTools())
borenet@google.com6b5388e2013-01-23 20:54:29 +0000241 import trychange
242 try_args = ['--use_svn',
243 '--svn_repo', GetTryRepo(),
244 '--root', GetCheckoutRoot(is_svn),
245 '--bot', botlist]
246 if args.revision:
247 try_args.extend(['-r', args.revision])
248 trychange.TryChange(try_args, None, False)
249
250
251def main():
252 # Retrieve the list of active try builders from the build master.
253 trybots = RetrieveTrybotList()
254
255 # Determine if we're in an SVN checkout.
256 is_svn = os.path.isdir('.svn')
257
258 # Parse and validate the command-line arguments.
borenet@google.coma5d621f2013-01-25 20:55:35 +0000259 args = ValidateArgs(sys.argv[1:], trybots=trybots, is_svn=is_svn)
borenet@google.com6b5388e2013-01-23 20:54:29 +0000260
261 # Submit the try request.
262 SubmitTryRequest(args, is_svn=is_svn)
263
264
265if __name__ == '__main__':
266 sys.exit(main())