blob: a3fa57780fc364509206d762dd7a4590d0eccced [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
borenet@google.coma74302d2013-03-18 18:18:26 +000020import svn
borenet@google.com6b5388e2013-01-23 20:54:29 +000021import sys
borenet@google.comfe7533e2013-03-11 20:09:40 +000022
23
borenet@google.coma74302d2013-03-18 18:18:26 +000024GLOBAL_VARIABLES = json.loads(svn.Svn.Cat('http://skia.googlecode.com/svn/'
25 'buildbot/site_config/'
26 'global_variables.json'))
borenet@google.comfe7533e2013-03-11 20:09:40 +000027
28
29def GetGlobalVariable(var_name):
30 return GLOBAL_VARIABLES[var_name]['value']
borenet@google.com6b5388e2013-01-23 20:54:29 +000031
32
33# Alias which can be used to run a try on every builder.
34ALL_BUILDERS = 'all'
35
36# Contact information for the build master.
borenet@google.comfe7533e2013-03-11 20:09:40 +000037SKIA_BUILD_MASTER_HOST = str(GetGlobalVariable('master_host'))
38SKIA_BUILD_MASTER_PORT = str(GetGlobalVariable('external_port'))
borenet@google.com6b5388e2013-01-23 20:54:29 +000039
40# All try builders have this suffix.
41TRYBOT_SUFFIX = '_Trybot'
42
43# Location of the codereview.settings file in the Skia repo.
44SKIA_URL = 'skia.googlecode.com'
45CODEREVIEW_SETTINGS = '/svn/codereview.settings'
46
47# String for matching the svn url of the try server inside codereview.settings.
48TRYSERVER_SVN_URL = 'TRYSERVER_SVN_URL: '
49
50# Strings used for matching svn config properties.
borenet@google.coma74302d2013-03-18 18:18:26 +000051URL_STR = 'URL'
52REPO_ROOT_STR = 'Repository Root'
borenet@google.com6b5388e2013-01-23 20:54:29 +000053
54
55def FindDepotTools():
56 """ Find depot_tools on the local machine and return its location. """
57 which_cmd = 'where' if os.name == 'nt' else 'which'
58 cmd = [which_cmd, 'gcl']
59 proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
60 if proc.wait() != 0:
61 raise Exception('Couldn\'t find depot_tools in PATH!')
borenet@google.com6c55b512013-01-24 21:38:51 +000062 gcl = proc.communicate()[0].split('\n')[0].rstrip()
borenet@google.com6b5388e2013-01-23 20:54:29 +000063 depot_tools_dir = os.path.dirname(gcl)
64 return depot_tools_dir
65
66
67def GetCheckoutRoot(is_svn=True):
68 """ Determine where the local checkout is rooted.
69
70 is_svn: boolean; whether we're in an SVN checkout. If False, assume we're in
71 a git checkout.
72 """
73 if is_svn:
borenet@google.coma74302d2013-03-18 18:18:26 +000074 repo = svn.Svn(os.curdir)
75 svn_info = repo.GetInfo()
76 url = svn_info.get(URL_STR, None)
77 repo_root = svn_info.get(REPO_ROOT_STR, None)
borenet@google.com6b5388e2013-01-23 20:54:29 +000078 if not url or not repo_root:
79 raise Exception('Couldn\'t find checkout root!')
80 if url == repo_root:
81 return 'svn'
82 return url[len(repo_root)+1:]
83 else:
84 cmd = ['git', 'rev-parse', '--show-toplevel']
85 proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
86 stderr=subprocess.STDOUT)
87 if proc.wait() != 0:
88 raise Exception('Couldn\'t find checkout root!')
89 return os.path.basename(proc.communicate()[0])
90
91
92def GetTryRepo():
93 """ Determine the TRYSERVER_SVN_URL from the codereview.settings file in the
94 Skia repo. """
95 connection = httplib.HTTPConnection(SKIA_URL)
96 connection.request('GET', CODEREVIEW_SETTINGS)
97 content = connection.getresponse().read()
98 for line in content.split('\n'):
99 if line.startswith(TRYSERVER_SVN_URL):
100 return line[len(TRYSERVER_SVN_URL):].rstrip()
101 raise Exception('Couldn\'t determine the TRYSERVER_SVN_URL. Make sure it is '
102 'defined in the %s file.' % CODEREVIEW_SETTINGS)
103
104
105def RetrieveTrybotList():
106 """ Retrieve the list of known trybots from the build master, stripping
107 TRYBOT_SUFFIX from the name. """
108 trybots = []
109 connection = httplib.HTTPConnection(SKIA_BUILD_MASTER_HOST,
110 SKIA_BUILD_MASTER_PORT)
111 connection.request('GET', '/json/builders')
112 response = connection.getresponse()
113 builders = json.load(response)
114
115 for builder in builders:
116 if builder.endswith(TRYBOT_SUFFIX):
117 trybots.append(builder[:-len(TRYBOT_SUFFIX)])
118 return trybots
119
120
borenet@google.coma5d621f2013-01-25 20:55:35 +0000121def ValidateArgs(argv, trybots, is_svn=True):
borenet@google.com6b5388e2013-01-23 20:54:29 +0000122 """ Parse and validate command-line arguments. If the arguments are valid,
123 returns a tuple of (<changelist name>, <list of trybots>).
124
125 trybots: A list of the known try builders.
126 """
borenet@google.com6b5388e2013-01-23 20:54:29 +0000127
borenet@google.coma5d621f2013-01-25 20:55:35 +0000128 class CollectedArgs(object):
129 def __init__(self, bots, changelist, revision):
130 self._bots = bots
131 self._changelist = changelist
132 self._revision = revision
133
134 @property
135 def bots(self):
136 for bot in self._bots:
137 yield bot
138
139 @property
140 def changelist(self):
141 return self._changelist
142
143 @property
144 def revision(self):
145 return self._revision
146
147 usage = (
148"""submit_try: Submit a try request.
149submit_try %s--bot <buildername> [<buildername> ...]
150
151--bot Builder on which to run the try. Required.
152-h, --help Show this message.
153-r <revision#> Revision from which to run the try.
154-l, --list_bots List the available try builders and exit.
155""" % ('<changelist> ' if is_svn else ''))
156
157 def Error(msg=None):
158 if msg:
159 print msg
160 print usage
161 sys.exit(1)
162
163 using_bots = None
164 changelist = None
165 revision = None
166
167 while argv:
168 arg = argv.pop(0)
169 if arg == '-h' or arg == '--help':
170 Error()
171 elif arg == '-l' or arg == '--list_bots':
172 print 'submit_try: Available builders:\n %s' % '\n '.join(trybots)
173 sys.exit(0)
174 elif arg == '--bot':
175 if using_bots:
176 Error('--bot specified multiple times.')
177 if len(argv) < 1:
178 Error('You must specify a builder with "--bot".')
179 using_bots = []
180 while argv and not argv[0].startswith('-'):
181 bot = argv.pop(0)
182 if bot == ALL_BUILDERS:
183 if using_bots:
184 Error('Cannot specify "all" with additional builder names.')
185 using_bots = trybots
186 break
187 else:
188 if not bot in trybots:
189 Error('Unrecognized builder: %s' % bot)
190 using_bots.append(bot)
191 elif arg == '-r':
192 if len(argv) < 1:
193 Error('You must specify a revision with "-r".')
194 revision = argv.pop(0)
195 else:
196 if changelist or not is_svn:
197 Error('Unknown argument: %s' % arg)
198 changelist = arg
199 if is_svn and not changelist:
200 Error('You must specify a changelist name.')
201 if not using_bots:
202 Error('You must specify one or more builders using --bot.')
203 return CollectedArgs(bots=using_bots, changelist=changelist,
204 revision=revision)
borenet@google.com6b5388e2013-01-23 20:54:29 +0000205
206
207def SubmitTryRequest(args, is_svn=True):
208 """ Submits a try request for the given changelist on the given list of
209 trybots.
210
211 args: Object whose properties are derived from command-line arguments. If
212 is_svn is True, it should contain:
213 - changelist: string; the name of the changelist to try.
214 - bot: list of strings; the names of the try builders to run.
215 - revision: optional, int; the revision number from which to run the try.
216 If is_svn is False, it should contain:
217 - bot: list of strings; the names of the try builders to run.
218 - revision: optional, int; the revision number from which to run the try.
219 is_svn: boolean; are we in an SVN repo?
220 """
borenet@google.coma5d621f2013-01-25 20:55:35 +0000221 botlist = ','.join(['%s%s' % (bot, TRYBOT_SUFFIX) for bot in args.bots])
borenet@google.com6b5388e2013-01-23 20:54:29 +0000222 if is_svn:
borenet@google.com6c55b512013-01-24 21:38:51 +0000223 gcl_cmd = 'gcl.bat' if os.name == 'nt' else 'gcl'
224 try_args = [gcl_cmd, 'try', args.changelist,
225 '--root', GetCheckoutRoot(is_svn),
borenet@google.com6b5388e2013-01-23 20:54:29 +0000226 '--bot', botlist]
227 if args.revision:
228 try_args.extend(['-r', args.revision])
borenet@google.com6c55b512013-01-24 21:38:51 +0000229 print ' '.join(try_args)
230 proc = subprocess.Popen(try_args, stdout=subprocess.PIPE,
231 stderr=subprocess.STDOUT)
232 if proc.wait() != 0:
233 raise Exception('Failed to submit try request: %s' % (
234 proc.communicate()[0]))
235 print proc.communicate()[0]
borenet@google.com6b5388e2013-01-23 20:54:29 +0000236 else:
borenet@google.com6c55b512013-01-24 21:38:51 +0000237 # First, find depot_tools. This is needed to import trychange.
238 sys.path.append(FindDepotTools())
borenet@google.com6b5388e2013-01-23 20:54:29 +0000239 import trychange
240 try_args = ['--use_svn',
241 '--svn_repo', GetTryRepo(),
242 '--root', GetCheckoutRoot(is_svn),
243 '--bot', botlist]
244 if args.revision:
245 try_args.extend(['-r', args.revision])
246 trychange.TryChange(try_args, None, False)
247
248
249def main():
250 # Retrieve the list of active try builders from the build master.
251 trybots = RetrieveTrybotList()
252
253 # Determine if we're in an SVN checkout.
254 is_svn = os.path.isdir('.svn')
255
256 # Parse and validate the command-line arguments.
borenet@google.coma5d621f2013-01-25 20:55:35 +0000257 args = ValidateArgs(sys.argv[1:], trybots=trybots, is_svn=is_svn)
borenet@google.com6b5388e2013-01-23 20:54:29 +0000258
259 # Submit the try request.
260 SubmitTryRequest(args, is_svn=is_svn)
261
262
263if __name__ == '__main__':
264 sys.exit(main())