Chromium Code Reviews| Index: trychange.py |
| diff --git a/trychange.py b/trychange.py |
| index d181e141baff4c312c8fd1c8343fc98c8918991c..b9d43e1802d1f79aca75b3f7b423293132937f96 100755 |
| --- a/trychange.py |
| +++ b/trychange.py |
| @@ -24,12 +24,14 @@ import sys |
| import tempfile |
| import urllib |
| import urllib2 |
| +import urlparse |
| import breakpad # pylint: disable=W0611 |
| -import gcl |
| import fix_encoding |
| +import gcl |
| import gclient_utils |
| +import gerrit_util |
| import scm |
| import subprocess2 |
| @@ -95,17 +97,21 @@ def RunGit(args, **kwargs): |
| """Returns stdout.""" |
| return RunCommand(['git'] + args, **kwargs) |
| +class Error(Exception): |
| + """An error during a try job submission. |
| + |
| + For this error, trychange.py does not display stack trace, only message |
| + """ |
| -class InvalidScript(Exception): |
| +class InvalidScript(Error): |
| def __str__(self): |
| return self.args[0] + '\n' + HELP_STRING |
| -class NoTryServerAccess(Exception): |
| +class NoTryServerAccess(Error): |
| def __str__(self): |
| return self.args[0] + '\n' + HELP_STRING |
| - |
| def Escape(name): |
| """Escapes characters that could interfere with the file system or try job |
| parsing. |
| @@ -168,6 +174,7 @@ class SCM(object): |
| 'port': self.GetCodeReviewSetting('TRYSERVER_HTTP_PORT'), |
| 'host': self.GetCodeReviewSetting('TRYSERVER_HTTP_HOST'), |
| 'svn_repo': self.GetCodeReviewSetting('TRYSERVER_SVN_URL'), |
| + 'gerrit_url': self.GetCodeReviewSetting('TRYSERVER_GERRIT_URL'), |
| 'git_repo': self.GetCodeReviewSetting('TRYSERVER_GIT_URL'), |
| 'project': self.GetCodeReviewSetting('TRYSERVER_PROJECT'), |
| # Primarily for revision=auto |
| @@ -706,6 +713,73 @@ def _SendChangeGit(bot_spec, options): |
| patch_git('reset', '--hard', 'origin/master') |
| raise |
| +def _SendChangeGerrit(bot_spec, options): |
| + """Posts a try job to a Gerrit change. |
| + |
| + Reads Change-Id from the HEAD commit, resolves the current revision, checks |
| + that local revision matches the uploaded one, posts a try job in form of a |
| + message, sets Tryjob label to 1. |
| + |
| + Gerrit message format: starts with !tryjob, optionally followed by a tryjob |
| + definition in JSON format: |
| + buildNames: list of strings specifying build names. |
| + """ |
| + |
| + logging.info('Sending by Gerrit') |
| + if not options.gerrit_url: |
| + raise NoTryServerAccess('Please use --gerrit_url option to specify the ' |
| + 'Gerrit instance url to connect to') |
| + gerrit_host = urlparse.urlparse(options.gerrit_url).hostname |
| + logging.debug('Gerrit host: %s' % gerrit_host) |
| + |
| + def get_change_id(): |
|
Vadim Sh.
2014/04/30 00:40:48
looks like this file is using GetChangeId naming s
|
| + """Finds Change-ID of the HEAD commit.""" |
| + CHANGE_ID_RGX = '^Change-Id: (I[a-f0-9]{10,})' |
| + comment = scm.GIT.Capture(['log', '-1', '--format=%b'], cwd=os.getcwd()) |
| + change_id_match = re.search(CHANGE_ID_RGX, comment, re.I | re.M) |
| + if not change_id_match: |
| + raise Error('Change-Id was not found in the HEAD commit.') |
|
Vadim Sh.
2014/04/30 00:40:48
It would be helpful to explain what to do in that
|
| + change_id = change_id_match.group(1) |
| + assert change_id and change_id.startswith('I') |
|
Vadim Sh.
2014/04/30 00:40:48
I think this assert is redundant since your regexp
|
| + return change_id |
| + |
| + def format_message(): |
| + # Build job definition. |
| + job_def = {} |
| + builderNames = [builder for builder, _ in bot_spec] |
| + if builderNames: |
| + job_def['builderNames'] = builderNames |
| + |
| + # Format message. |
| + msg = '!tryjob' |
| + if job_def: |
| + msg = '%s %s' % (msg, json.dumps(job_def)) |
|
Vadim Sh.
2014/04/30 00:40:48
json.dumps(job_def, sort_keys=True)
|
| + return msg |
|
Vadim Sh.
2014/04/30 00:40:48
Does Gerrit append '\n' for you here? I think it's
nodir
2014/04/30 18:57:27
The regexp expects EOL or EOF after job definitio
|
| + |
| + head_sha = scm.GIT.Capture(['log', '-1', '--format=%H'], cwd=os.getcwd()) |
| + |
| + change_id = get_change_id() |
|
Vadim Sh.
2014/04/30 00:40:48
I think it would be cleaner to pass |head_sha| to
nodir
2014/04/30 18:57:27
Done.
|
| + assert change_id |
|
Vadim Sh.
2014/04/30 00:40:48
I think this is redundant too..
|
| + |
| + # Check that the uploaded revision matches the local one. |
| + changes = gerrit_util.GetChangeCurrentRevision(gerrit_host, change_id) |
| + assert len(changes) in (0, 1), 'Multiple changes with id %s' % change_id |
|
Vadim Sh.
2014/04/30 00:40:48
hm.. len(changes) <= 1?
nodir
2014/04/30 18:57:27
Wanted to be more explicit, it's probably looks we
|
| + if not changes: |
| + raise Error('A change %s was not found on the server. Was it uploaded?' % |
| + change_id) |
| + logging.debug('Found Gerrit change: %s' % changes[0]) |
| + if changes[0]['current_revision'] != head_sha: |
| + raise Error('Some changes were made since last upload to Gerrit, ' |
|
Vadim Sh.
2014/04/30 00:40:48
I'd rephrase it somehow. Maybe "Please reupload yo
nodir
2014/04/30 18:57:27
Modified the string a bit.
|
| + 'so stopping.') |
| + |
| + # Post a try job. |
| + message = format_message() |
| + logging.info('Posting gerrit message: %s' % message) |
| + if not options.dry_run: |
| + # Post a message and set TryJob=1 label |
|
Vadim Sh.
2014/04/30 00:40:48
nit: append '.' at the end of a sentence :)
|
| + gerrit_util.SetReview(gerrit_host, change_id, msg=message, |
| + labels={'Tryjob': 1}) |
|
Vadim Sh.
2014/04/30 00:40:48
What happens here if project doesn't have Tryjob l
nodir
2014/04/30 18:57:27
It will report:
Bad Request: label "Tryjb" is not
|
| + |
| def PrintSuccess(bot_spec, options): |
| if not options.dry_run: |
| @@ -920,6 +994,19 @@ def gen_parser(prog): |
| help="GIT url to use to write the changes in; --use_git is " |
| "implied when using --git_repo") |
| parser.add_option_group(group) |
| + |
| + group = optparse.OptionGroup(parser, "Access the try server with Gerrit") |
| + group.add_option("--use_gerrit", |
| + action="store_const", |
| + const=_SendChangeGerrit, |
| + dest="send_patch", |
| + help="Use Gerrit to talk to the try server") |
| + group.add_option("--gerrit_url", |
| + metavar="GERRIT_URL", |
| + help="Gerrit url to post a tryjob to; --use_gerrit is " |
| + "implied when using --gerrit_url") |
| + parser.add_option_group(group) |
| + |
| return parser |
| @@ -1033,9 +1120,11 @@ def TryChange(argv, |
| can_http = options.port and options.host |
| can_svn = options.svn_repo |
| can_git = options.git_repo |
| + can_gerrit = options.gerrit_url |
| + can_anything = can_http or can_svn or can_git or can_gerrit |
|
Vadim Sh.
2014/04/30 00:40:48
I'm far from english expert, but shouldn't it be "
nodir
2014/04/30 18:57:27
Done
|
| # If there was no transport selected yet, now we must have enough data to |
| # select one. |
| - if not options.send_patch and not (can_http or can_svn or can_git): |
| + if not options.send_patch and not can_anything: |
| parser.error('Please specify an access method.') |
| # Convert options.diff into the content of the diff. |
| @@ -1122,7 +1211,8 @@ def TryChange(argv, |
| all_senders = [ |
| (_SendChangeHTTP, can_http), |
| (_SendChangeSVN, can_svn), |
| - (_SendChangeGit, can_git) |
| + (_SendChangeGerrit, can_gerrit), |
| + (_SendChangeGit, can_git), |
| ] |
| senders = [sender for sender, can in all_senders if can] |
| @@ -1137,7 +1227,7 @@ def TryChange(argv, |
| if is_last: |
| raise |
| assert False, "Unreachable code" |
| - except (InvalidScript, NoTryServerAccess), e: |
| + except Error, e: |
| if swallow_exception: |
| return 1 |
| print >> sys.stderr, e |