Index: git_cl.py |
diff --git a/git_cl.py b/git_cl.py |
index d838b9dd9eed764e28598cb01652a30ddc541356..58944cb879bbb97bfbbbf1a5478d7a91f21cd61f 100755 |
--- a/git_cl.py |
+++ b/git_cl.py |
@@ -10,6 +10,7 @@ |
from distutils.version import LooseVersion |
import base64 |
import glob |
+import httplib |
import json |
import logging |
import optparse |
@@ -21,6 +22,7 @@ import sys |
import tempfile |
import textwrap |
import threading |
+import time |
import urllib2 |
import urlparse |
import webbrowser |
@@ -33,12 +35,15 @@ except ImportError: |
from third_party import colorama |
+from third_party import httplib2 |
from third_party import upload |
+from third_party.google_api_python_client import apiclient |
import breakpad # pylint: disable=W0611 |
import clang_format |
import dart_format |
import fix_encoding |
import gclient_utils |
+import git_cl_oauth2 |
import git_common |
import owners |
import owners_finder |
@@ -61,6 +66,13 @@ REFS_THAT_ALIAS_TO_OTHER_REFS = { |
'refs/remotes/origin/lkcr': 'refs/remotes/origin/master', |
} |
+# Buildbucket-related constants |
+DISCOVERY_URL = ( |
+ 'https://cr-buildbucket.appspot.com/_ah/api/discovery/v1/apis/' |
+ '{api}/{apiVersion}/rest') |
+DEFAULT_SCOPES = 'email' |
+BUILDSET_STR = 'patch/rietveld/{hostname}/{issue}/{patch}' |
+ |
# Valid extensions for files we want to lint. |
DEFAULT_LINT_REGEX = r"(.*\.cpp|.*\.cc|.*\.h)" |
DEFAULT_LINT_IGNORE_REGEX = r"$^" |
@@ -215,6 +227,95 @@ def is_dirty_git_tree(cmd): |
return False |
+def _prefix_master(master): |
+ prefix = 'master.' |
+ if master.startswith(prefix): |
+ return master |
+ else: |
+ return '%s%s' % (prefix, master) |
+ |
+ |
+def _get_buildbucket(credentials): |
+ http = httplib2.Http() |
+ http = credentials.authorize(http) |
+ return apiclient.discovery.build( |
+ 'buildbucket', 'v1', |
+ http=http, |
+ discoveryServiceUrl=DISCOVERY_URL, |
+ ) |
+ |
+ |
+def trigger_distributed_try_jobs( |
+ credentials, changelist, options, masters, category): |
+ buildbucket = _get_buildbucket(credentials) |
+ creds_props = json.loads(credentials.to_json()) |
+ requester = creds_props['id_token']['email'] |
nodir
2015/03/10 22:39:40
I think you can get requester like this: credentia
sheyang
2015/03/13 20:58:27
No it doesn't work.
|
+ issue_props = changelist.GetIssueProperties() |
+ rietveld_host = urlparse.urlparse(changelist.GetRietveldServer()).hostname |
+ issue = changelist.GetIssue() |
+ patchset = changelist.GetMostRecentPatchset() |
+ buildset = BUILDSET_STR.format( |
+ hostname=rietveld_host, |
+ issue=str(issue), |
+ patch=str(patchset)) |
+ print 'Tried jobs on:' |
+ for (master, builders_and_tests) in masters.iteritems(): |
+ print 'Master: %s' % master |
+ bucket = _prefix_master(master) |
+ for builder, tests in builders_and_tests.iteritems(): |
+ req = buildbucket.put(body={ |
+ 'bucket': bucket, |
+ 'parameters_json': json.dumps({ |
+ 'builder_name': builder, |
+ 'changes':[ |
+ {'author': {'email': issue_props['owner_email']}}, |
+ ], |
+ 'properties': { |
+ 'category': category, |
+ 'clobber': options.clobber, |
+ 'issue': issue, |
+ 'master': master, |
+ 'patch_project': issue_props['project'], |
+ 'patch_storage': 'rietveld', |
+ 'patchset': patchset, |
+ 'reason': options.name, |
+ 'requester': requester, |
+ 'revision': options.revision, |
+ 'rietveld': changelist.GetRietveldServer(), |
+ 'testfilter': tests, |
+ }, |
+ }), |
+ 'tags': ['buildset:%s' % buildset, |
+ 'master:%s' % master, |
+ 'builder:%s' % builder, |
+ 'requester:%s' % requester] |
+ }) |
+ wait = 1 |
+ try_count = 3 |
+ while try_count > 0: |
+ try: |
+ response = req.execute() |
nodir
2015/03/10 22:39:40
do try_count -=1 after this
sheyang
2015/03/13 20:58:27
You mean before this right? Otherwise we may never
nodir
2015/03/18 23:49:15
Right
|
+ if response.get('error'): |
+ msg = 'Error in response. Reason: %s. Message: %s.' % ( |
+ response['error'].get('reason', ''), |
+ response['error'].get('message', '')) |
+ raise BuildbucketResponseException(msg) |
+ try_count = 0 |
nodir
2015/03/10 22:39:40
If this intends to break the loop, please do `brea
sheyang
2015/03/13 20:58:27
Done.
|
+ except apiclient.errors.HttpError as ex: |
+ status = ex.resp.status if ex.resp else None |
+ if status >= 500: |
+ logging.debug('Transient errors when triggering tryjobs. ' |
+ 'Will retry in %d seconds.', wait) |
+ time.sleep(wait) |
+ wait *= 2 |
+ try_count -= 1 |
nodir
2015/03/10 22:39:40
not needed if try_count -=1 right after trying
sheyang
2015/03/13 20:58:27
Done.
|
+ if try_count <= 0: |
+ raise |
+ else: |
+ raise |
+ print ' %s: %s' % (builder, tests) |
+ |
+ |
def MatchSvnGlob(url, base_url, glob_spec, allow_wildcards): |
"""Return the corresponding git ref if |base_url| together with |glob_spec| |
matches the full |url|. |
@@ -282,6 +383,10 @@ def print_stats(similarity, find_copies, args): |
stdout=stdout, env=env) |
+class BuildbucketResponseException(Exception): |
+ pass |
+ |
+ |
class Settings(object): |
def __init__(self): |
self.default_server = None |
@@ -2703,6 +2808,7 @@ def CMDtry(parser, args): |
group.add_option( |
"-n", "--name", help="Try job name; default to current branch name") |
parser.add_option_group(group) |
+ git_cl_oauth2.add_oauth2_options(parser) |
options, args = parser.parse_args(args) |
if args: |
@@ -2798,22 +2904,23 @@ def CMDtry(parser, args): |
'upload fail?\ngit-cl try always uses latest patchset from rietveld. ' |
'Continuing using\npatchset %s.\n' % patchset) |
try: |
- cl.RpcServer().trigger_distributed_try_jobs( |
- cl.GetIssue(), patchset, options.name, options.clobber, |
- options.revision, masters) |
- except urllib2.HTTPError, e: |
- if e.code == 404: |
- print('404 from rietveld; ' |
- 'did you mean to use "git try" instead of "git cl try"?') |
- return 1 |
- print('Tried jobs on:') |
- |
- for (master, builders) in masters.iteritems(): |
- if master: |
- print 'Master: %s' % master |
- length = max(len(builder) for builder in builders) |
- for builder in sorted(builders): |
- print ' %*s: %s' % (length, builder, ','.join(builders[builder])) |
+ creds = git_cl_oauth2.get_oauth2_creds( |
+ options, |
+ urlparse.urlparse(cl.GetRietveldServer()).hostname) |
+ trigger_distributed_try_jobs(creds, cl, options, masters, 'git cl try') |
+ except apiclient.errors.HttpError as ex: |
+ status = ex.resp.status if ex.resp else None |
+ if status == httplib.FORBIDDEN: |
+ print 'ERROR: Access denied. Please verify you have tryjob access.' |
+ else: |
+ print 'ERROR: Tryjob request failed: %s.' % ex |
+ return 1 |
+ except BuildbucketResponseException as ex: |
+ print ex |
+ return 1 |
+ except Exception as e: |
+ print 'Unexcpected error when trying to trigger tryjobs: %s.' % e |
+ return 1 |
return 0 |