| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 # Copyright (C) 2008 Evan Martin <martine@danga.com> | 6 # Copyright (C) 2008 Evan Martin <martine@danga.com> |
| 7 | 7 |
| 8 """A git-command for integrating reviews on Rietveld.""" | 8 """A git-command for integrating reviews on Rietveld.""" |
| 9 | 9 |
| 10 from distutils.version import LooseVersion | 10 from distutils.version import LooseVersion |
| (...skipping 16 matching lines...) Expand all Loading... |
| 27 import zlib | 27 import zlib |
| 28 | 28 |
| 29 try: | 29 try: |
| 30 import readline # pylint: disable=F0401,W0611 | 30 import readline # pylint: disable=F0401,W0611 |
| 31 except ImportError: | 31 except ImportError: |
| 32 pass | 32 pass |
| 33 | 33 |
| 34 | 34 |
| 35 from third_party import colorama | 35 from third_party import colorama |
| 36 from third_party import upload | 36 from third_party import upload |
| 37 import auth |
| 37 import breakpad # pylint: disable=W0611 | 38 import breakpad # pylint: disable=W0611 |
| 38 import clang_format | 39 import clang_format |
| 39 import dart_format | 40 import dart_format |
| 40 import fix_encoding | 41 import fix_encoding |
| 41 import gclient_utils | 42 import gclient_utils |
| 42 import git_common | 43 import git_common |
| 43 import owners | 44 import owners |
| 44 import owners_finder | 45 import owners_finder |
| 45 import presubmit_support | 46 import presubmit_support |
| 46 import rietveld | 47 import rietveld |
| (...skipping 444 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 491 self.LazyUpdateIfNeeded() | 492 self.LazyUpdateIfNeeded() |
| 492 return RunGit(['config', param], **kwargs).strip() | 493 return RunGit(['config', param], **kwargs).strip() |
| 493 | 494 |
| 494 | 495 |
| 495 def ShortBranchName(branch): | 496 def ShortBranchName(branch): |
| 496 """Convert a name like 'refs/heads/foo' to just 'foo'.""" | 497 """Convert a name like 'refs/heads/foo' to just 'foo'.""" |
| 497 return branch.replace('refs/heads/', '') | 498 return branch.replace('refs/heads/', '') |
| 498 | 499 |
| 499 | 500 |
| 500 class Changelist(object): | 501 class Changelist(object): |
| 501 def __init__(self, branchref=None, issue=None): | 502 def __init__(self, branchref=None, issue=None, auth_config=None): |
| 502 # Poke settings so we get the "configure your server" message if necessary. | 503 # Poke settings so we get the "configure your server" message if necessary. |
| 503 global settings | 504 global settings |
| 504 if not settings: | 505 if not settings: |
| 505 # Happens when git_cl.py is used as a utility library. | 506 # Happens when git_cl.py is used as a utility library. |
| 506 settings = Settings() | 507 settings = Settings() |
| 507 settings.GetDefaultServerUrl() | 508 settings.GetDefaultServerUrl() |
| 508 self.branchref = branchref | 509 self.branchref = branchref |
| 509 if self.branchref: | 510 if self.branchref: |
| 510 self.branch = ShortBranchName(self.branchref) | 511 self.branch = ShortBranchName(self.branchref) |
| 511 else: | 512 else: |
| 512 self.branch = None | 513 self.branch = None |
| 513 self.rietveld_server = None | 514 self.rietveld_server = None |
| 514 self.upstream_branch = None | 515 self.upstream_branch = None |
| 515 self.lookedup_issue = False | 516 self.lookedup_issue = False |
| 516 self.issue = issue or None | 517 self.issue = issue or None |
| 517 self.has_description = False | 518 self.has_description = False |
| 518 self.description = None | 519 self.description = None |
| 519 self.lookedup_patchset = False | 520 self.lookedup_patchset = False |
| 520 self.patchset = None | 521 self.patchset = None |
| 521 self._rpc_server = None | |
| 522 self.cc = None | 522 self.cc = None |
| 523 self.watchers = () | 523 self.watchers = () |
| 524 self._auth_config = auth_config |
| 525 self._props = None |
| 524 self._remote = None | 526 self._remote = None |
| 525 self._props = None | 527 self._rpc_server = None |
| 528 |
| 529 @property |
| 530 def auth_config(self): |
| 531 return self._auth_config |
| 526 | 532 |
| 527 def GetCCList(self): | 533 def GetCCList(self): |
| 528 """Return the users cc'd on this CL. | 534 """Return the users cc'd on this CL. |
| 529 | 535 |
| 530 Return is a string suitable for passing to gcl with the --cc flag. | 536 Return is a string suitable for passing to gcl with the --cc flag. |
| 531 """ | 537 """ |
| 532 if self.cc is None: | 538 if self.cc is None: |
| 533 base_cc = settings.GetDefaultCCList() | 539 base_cc = settings.GetDefaultCCList() |
| 534 more_cc = ','.join(self.watchers) | 540 more_cc = ','.join(self.watchers) |
| 535 self.cc = ','.join(filter(None, (base_cc, more_cc))) or '' | 541 self.cc = ','.join(filter(None, (base_cc, more_cc))) or '' |
| (...skipping 442 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 978 DieWithError( | 984 DieWithError( |
| 979 ('Access denied to issue %s. Maybe the patchset %s doesn\'t ' | 985 ('Access denied to issue %s. Maybe the patchset %s doesn\'t ' |
| 980 'match?') % (self.GetIssue(), self.GetPatchset())) | 986 'match?') % (self.GetIssue(), self.GetPatchset())) |
| 981 raise | 987 raise |
| 982 | 988 |
| 983 def RpcServer(self): | 989 def RpcServer(self): |
| 984 """Returns an upload.RpcServer() to access this review's rietveld instance. | 990 """Returns an upload.RpcServer() to access this review's rietveld instance. |
| 985 """ | 991 """ |
| 986 if not self._rpc_server: | 992 if not self._rpc_server: |
| 987 self._rpc_server = rietveld.CachingRietveld( | 993 self._rpc_server = rietveld.CachingRietveld( |
| 988 self.GetRietveldServer(), None, None) | 994 self.GetRietveldServer(), |
| 995 self._auth_config or auth.make_auth_config()) |
| 989 return self._rpc_server | 996 return self._rpc_server |
| 990 | 997 |
| 991 def _IssueSetting(self): | 998 def _IssueSetting(self): |
| 992 """Return the git setting that stores this change's issue.""" | 999 """Return the git setting that stores this change's issue.""" |
| 993 return 'branch.%s.rietveldissue' % self.GetBranch() | 1000 return 'branch.%s.rietveldissue' % self.GetBranch() |
| 994 | 1001 |
| 995 def _PatchsetSetting(self): | 1002 def _PatchsetSetting(self): |
| 996 """Return the git setting that stores this change's most recent patchset.""" | 1003 """Return the git setting that stores this change's most recent patchset.""" |
| 997 return 'branch.%s.rietveldpatchset' % self.GetBranch() | 1004 return 'branch.%s.rietveldpatchset' % self.GetBranch() |
| 998 | 1005 |
| (...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1335 return { | 1342 return { |
| 1336 'unsent': Fore.RED, | 1343 'unsent': Fore.RED, |
| 1337 'waiting': Fore.BLUE, | 1344 'waiting': Fore.BLUE, |
| 1338 'reply': Fore.YELLOW, | 1345 'reply': Fore.YELLOW, |
| 1339 'lgtm': Fore.GREEN, | 1346 'lgtm': Fore.GREEN, |
| 1340 'commit': Fore.MAGENTA, | 1347 'commit': Fore.MAGENTA, |
| 1341 'closed': Fore.CYAN, | 1348 'closed': Fore.CYAN, |
| 1342 'error': Fore.WHITE, | 1349 'error': Fore.WHITE, |
| 1343 }.get(status, Fore.WHITE) | 1350 }.get(status, Fore.WHITE) |
| 1344 | 1351 |
| 1345 def fetch_cl_status(b): | 1352 def fetch_cl_status(b, auth_config=None): |
| 1346 """Fetches information for an issue and returns (branch, issue, color).""" | 1353 """Fetches information for an issue and returns (branch, issue, color).""" |
| 1347 c = Changelist(branchref=b) | 1354 c = Changelist(branchref=b, auth_config=auth_config) |
| 1348 i = c.GetIssueURL() | 1355 i = c.GetIssueURL() |
| 1349 status = c.GetStatus() | 1356 status = c.GetStatus() |
| 1350 color = color_for_status(status) | 1357 color = color_for_status(status) |
| 1351 | 1358 |
| 1352 if i and (not status or status == 'error'): | 1359 if i and (not status or status == 'error'): |
| 1353 # The issue probably doesn't exist anymore. | 1360 # The issue probably doesn't exist anymore. |
| 1354 i += ' (broken)' | 1361 i += ' (broken)' |
| 1355 | 1362 |
| 1356 return (b, i, color) | 1363 return (b, i, color) |
| 1357 | 1364 |
| 1358 def get_cl_statuses(branches, fine_grained, max_processes=None): | 1365 def get_cl_statuses( |
| 1366 branches, fine_grained, max_processes=None, auth_config=None): |
| 1359 """Returns a blocking iterable of (branch, issue, color) for given branches. | 1367 """Returns a blocking iterable of (branch, issue, color) for given branches. |
| 1360 | 1368 |
| 1361 If fine_grained is true, this will fetch CL statuses from the server. | 1369 If fine_grained is true, this will fetch CL statuses from the server. |
| 1362 Otherwise, simply indicate if there's a matching url for the given branches. | 1370 Otherwise, simply indicate if there's a matching url for the given branches. |
| 1363 | 1371 |
| 1364 If max_processes is specified, it is used as the maximum number of processes | 1372 If max_processes is specified, it is used as the maximum number of processes |
| 1365 to spawn to fetch CL status from the server. Otherwise 1 process per branch is | 1373 to spawn to fetch CL status from the server. Otherwise 1 process per branch is |
| 1366 spawned. | 1374 spawned. |
| 1367 """ | 1375 """ |
| 1368 # Silence upload.py otherwise it becomes unwieldly. | 1376 # Silence upload.py otherwise it becomes unwieldly. |
| 1369 upload.verbosity = 0 | 1377 upload.verbosity = 0 |
| 1370 | 1378 |
| 1371 if fine_grained: | 1379 if fine_grained: |
| 1372 # Process one branch synchronously to work through authentication, then | 1380 # Process one branch synchronously to work through authentication, then |
| 1373 # spawn processes to process all the other branches in parallel. | 1381 # spawn processes to process all the other branches in parallel. |
| 1374 if branches: | 1382 if branches: |
| 1375 yield fetch_cl_status(branches[0]) | 1383 fetch = lambda branch: fetch_cl_status(branch, auth_config=auth_config) |
| 1384 yield fetch(branches[0]) |
| 1376 | 1385 |
| 1377 branches_to_fetch = branches[1:] | 1386 branches_to_fetch = branches[1:] |
| 1378 pool = ThreadPool( | 1387 pool = ThreadPool( |
| 1379 min(max_processes, len(branches_to_fetch)) | 1388 min(max_processes, len(branches_to_fetch)) |
| 1380 if max_processes is not None | 1389 if max_processes is not None |
| 1381 else len(branches_to_fetch)) | 1390 else len(branches_to_fetch)) |
| 1382 for x in pool.imap_unordered(fetch_cl_status, branches_to_fetch): | 1391 for x in pool.imap_unordered(fetch, branches_to_fetch): |
| 1383 yield x | 1392 yield x |
| 1384 else: | 1393 else: |
| 1385 # Do not use GetApprovingReviewers(), since it requires an HTTP request. | 1394 # Do not use GetApprovingReviewers(), since it requires an HTTP request. |
| 1386 for b in branches: | 1395 for b in branches: |
| 1387 c = Changelist(branchref=b) | 1396 c = Changelist(branchref=b, auth_config=auth_config) |
| 1388 url = c.GetIssueURL() | 1397 url = c.GetIssueURL() |
| 1389 yield (b, url, Fore.BLUE if url else Fore.WHITE) | 1398 yield (b, url, Fore.BLUE if url else Fore.WHITE) |
| 1390 | 1399 |
| 1391 def CMDstatus(parser, args): | 1400 def CMDstatus(parser, args): |
| 1392 """Show status of changelists. | 1401 """Show status of changelists. |
| 1393 | 1402 |
| 1394 Colors are used to tell the state of the CL unless --fast is used: | 1403 Colors are used to tell the state of the CL unless --fast is used: |
| 1395 - Red not sent for review or broken | 1404 - Red not sent for review or broken |
| 1396 - Blue waiting for review | 1405 - Blue waiting for review |
| 1397 - Yellow waiting for you to reply to review | 1406 - Yellow waiting for you to reply to review |
| 1398 - Green LGTM'ed | 1407 - Green LGTM'ed |
| 1399 - Magenta in the commit queue | 1408 - Magenta in the commit queue |
| 1400 - Cyan was committed, branch can be deleted | 1409 - Cyan was committed, branch can be deleted |
| 1401 | 1410 |
| 1402 Also see 'git cl comments'. | 1411 Also see 'git cl comments'. |
| 1403 """ | 1412 """ |
| 1404 parser.add_option('--field', | 1413 parser.add_option('--field', |
| 1405 help='print only specific field (desc|id|patch|url)') | 1414 help='print only specific field (desc|id|patch|url)') |
| 1406 parser.add_option('-f', '--fast', action='store_true', | 1415 parser.add_option('-f', '--fast', action='store_true', |
| 1407 help='Do not retrieve review status') | 1416 help='Do not retrieve review status') |
| 1408 parser.add_option( | 1417 parser.add_option( |
| 1409 '-j', '--maxjobs', action='store', type=int, | 1418 '-j', '--maxjobs', action='store', type=int, |
| 1410 help='The maximum number of jobs to use when retrieving review status') | 1419 help='The maximum number of jobs to use when retrieving review status') |
| 1411 (options, args) = parser.parse_args(args) | 1420 |
| 1421 auth.add_auth_options(parser) |
| 1422 options, args = parser.parse_args(args) |
| 1412 if args: | 1423 if args: |
| 1413 parser.error('Unsupported args: %s' % args) | 1424 parser.error('Unsupported args: %s' % args) |
| 1425 auth_config = auth.extract_auth_config_from_options(options) |
| 1414 | 1426 |
| 1415 if options.field: | 1427 if options.field: |
| 1416 cl = Changelist() | 1428 cl = Changelist(auth_config=auth_config) |
| 1417 if options.field.startswith('desc'): | 1429 if options.field.startswith('desc'): |
| 1418 print cl.GetDescription() | 1430 print cl.GetDescription() |
| 1419 elif options.field == 'id': | 1431 elif options.field == 'id': |
| 1420 issueid = cl.GetIssue() | 1432 issueid = cl.GetIssue() |
| 1421 if issueid: | 1433 if issueid: |
| 1422 print issueid | 1434 print issueid |
| 1423 elif options.field == 'patch': | 1435 elif options.field == 'patch': |
| 1424 patchset = cl.GetPatchset() | 1436 patchset = cl.GetPatchset() |
| 1425 if patchset: | 1437 if patchset: |
| 1426 print patchset | 1438 print patchset |
| 1427 elif options.field == 'url': | 1439 elif options.field == 'url': |
| 1428 url = cl.GetIssueURL() | 1440 url = cl.GetIssueURL() |
| 1429 if url: | 1441 if url: |
| 1430 print url | 1442 print url |
| 1431 return 0 | 1443 return 0 |
| 1432 | 1444 |
| 1433 branches = RunGit(['for-each-ref', '--format=%(refname)', 'refs/heads']) | 1445 branches = RunGit(['for-each-ref', '--format=%(refname)', 'refs/heads']) |
| 1434 if not branches: | 1446 if not branches: |
| 1435 print('No local branch found.') | 1447 print('No local branch found.') |
| 1436 return 0 | 1448 return 0 |
| 1437 | 1449 |
| 1438 changes = (Changelist(branchref=b) for b in branches.splitlines()) | 1450 changes = ( |
| 1451 Changelist(branchref=b, auth_config=auth_config) |
| 1452 for b in branches.splitlines()) |
| 1439 branches = [c.GetBranch() for c in changes] | 1453 branches = [c.GetBranch() for c in changes] |
| 1440 alignment = max(5, max(len(b) for b in branches)) | 1454 alignment = max(5, max(len(b) for b in branches)) |
| 1441 print 'Branches associated with reviews:' | 1455 print 'Branches associated with reviews:' |
| 1442 output = get_cl_statuses(branches, | 1456 output = get_cl_statuses(branches, |
| 1443 fine_grained=not options.fast, | 1457 fine_grained=not options.fast, |
| 1444 max_processes=options.maxjobs) | 1458 max_processes=options.maxjobs, |
| 1459 auth_config=auth_config) |
| 1445 | 1460 |
| 1446 branch_statuses = {} | 1461 branch_statuses = {} |
| 1447 alignment = max(5, max(len(ShortBranchName(b)) for b in branches)) | 1462 alignment = max(5, max(len(ShortBranchName(b)) for b in branches)) |
| 1448 for branch in sorted(branches): | 1463 for branch in sorted(branches): |
| 1449 while branch not in branch_statuses: | 1464 while branch not in branch_statuses: |
| 1450 b, i, color = output.next() | 1465 b, i, color = output.next() |
| 1451 branch_statuses[b] = (i, color) | 1466 branch_statuses[b] = (i, color) |
| 1452 issue, color = branch_statuses.pop(branch) | 1467 issue, color = branch_statuses.pop(branch) |
| 1453 reset = Fore.RESET | 1468 reset = Fore.RESET |
| 1454 if not sys.stdout.isatty(): | 1469 if not sys.stdout.isatty(): |
| 1455 color = '' | 1470 color = '' |
| 1456 reset = '' | 1471 reset = '' |
| 1457 print ' %*s : %s%s%s' % ( | 1472 print ' %*s : %s%s%s' % ( |
| 1458 alignment, ShortBranchName(branch), color, issue, reset) | 1473 alignment, ShortBranchName(branch), color, issue, reset) |
| 1459 | 1474 |
| 1460 cl = Changelist() | 1475 cl = Changelist(auth_config=auth_config) |
| 1461 print | 1476 print |
| 1462 print 'Current branch:', | 1477 print 'Current branch:', |
| 1463 if not cl.GetIssue(): | 1478 if not cl.GetIssue(): |
| 1464 print 'no issue assigned.' | 1479 print 'no issue assigned.' |
| 1465 return 0 | 1480 return 0 |
| 1466 print cl.GetBranch() | 1481 print cl.GetBranch() |
| 1467 print 'Issue number: %s (%s)' % (cl.GetIssue(), cl.GetIssueURL()) | 1482 print 'Issue number: %s (%s)' % (cl.GetIssue(), cl.GetIssueURL()) |
| 1468 if not options.fast: | 1483 if not options.fast: |
| 1469 print 'Issue description:' | 1484 print 'Issue description:' |
| 1470 print cl.GetDescription(pretty=True) | 1485 print cl.GetDescription(pretty=True) |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1527 print 'Issue number: %s (%s)' % (cl.GetIssue(), cl.GetIssueURL()) | 1542 print 'Issue number: %s (%s)' % (cl.GetIssue(), cl.GetIssueURL()) |
| 1528 return 0 | 1543 return 0 |
| 1529 | 1544 |
| 1530 | 1545 |
| 1531 def CMDcomments(parser, args): | 1546 def CMDcomments(parser, args): |
| 1532 """Shows or posts review comments for any changelist.""" | 1547 """Shows or posts review comments for any changelist.""" |
| 1533 parser.add_option('-a', '--add-comment', dest='comment', | 1548 parser.add_option('-a', '--add-comment', dest='comment', |
| 1534 help='comment to add to an issue') | 1549 help='comment to add to an issue') |
| 1535 parser.add_option('-i', dest='issue', | 1550 parser.add_option('-i', dest='issue', |
| 1536 help="review issue id (defaults to current issue)") | 1551 help="review issue id (defaults to current issue)") |
| 1552 auth.add_auth_options(parser) |
| 1537 options, args = parser.parse_args(args) | 1553 options, args = parser.parse_args(args) |
| 1554 auth_config = auth.extract_auth_config_from_options(options) |
| 1538 | 1555 |
| 1539 issue = None | 1556 issue = None |
| 1540 if options.issue: | 1557 if options.issue: |
| 1541 try: | 1558 try: |
| 1542 issue = int(options.issue) | 1559 issue = int(options.issue) |
| 1543 except ValueError: | 1560 except ValueError: |
| 1544 DieWithError('A review issue id is expected to be a number') | 1561 DieWithError('A review issue id is expected to be a number') |
| 1545 | 1562 |
| 1546 cl = Changelist(issue=issue) | 1563 cl = Changelist(issue=issue, auth_config=auth_config) |
| 1547 | 1564 |
| 1548 if options.comment: | 1565 if options.comment: |
| 1549 cl.AddComment(options.comment) | 1566 cl.AddComment(options.comment) |
| 1550 return 0 | 1567 return 0 |
| 1551 | 1568 |
| 1552 data = cl.GetIssueProperties() | 1569 data = cl.GetIssueProperties() |
| 1553 for message in sorted(data.get('messages', []), key=lambda x: x['date']): | 1570 for message in sorted(data.get('messages', []), key=lambda x: x['date']): |
| 1554 if message['disapproval']: | 1571 if message['disapproval']: |
| 1555 color = Fore.RED | 1572 color = Fore.RED |
| 1556 elif message['approval']: | 1573 elif message['approval']: |
| 1557 color = Fore.GREEN | 1574 color = Fore.GREEN |
| 1558 elif message['sender'] == data['owner_email']: | 1575 elif message['sender'] == data['owner_email']: |
| 1559 color = Fore.MAGENTA | 1576 color = Fore.MAGENTA |
| 1560 else: | 1577 else: |
| 1561 color = Fore.BLUE | 1578 color = Fore.BLUE |
| 1562 print '\n%s%s %s%s' % ( | 1579 print '\n%s%s %s%s' % ( |
| 1563 color, message['date'].split('.', 1)[0], message['sender'], | 1580 color, message['date'].split('.', 1)[0], message['sender'], |
| 1564 Fore.RESET) | 1581 Fore.RESET) |
| 1565 if message['text'].strip(): | 1582 if message['text'].strip(): |
| 1566 print '\n'.join(' ' + l for l in message['text'].splitlines()) | 1583 print '\n'.join(' ' + l for l in message['text'].splitlines()) |
| 1567 return 0 | 1584 return 0 |
| 1568 | 1585 |
| 1569 | 1586 |
| 1570 def CMDdescription(parser, args): | 1587 def CMDdescription(parser, args): |
| 1571 """Brings up the editor for the current CL's description.""" | 1588 """Brings up the editor for the current CL's description.""" |
| 1572 parser.parse_args(args) | 1589 auth.add_auth_options(parser) |
| 1573 cl = Changelist() | 1590 options, _ = parser.parse_args(args) |
| 1591 auth_config = auth.extract_auth_config_from_options(options) |
| 1592 cl = Changelist(auth_config=auth_config) |
| 1574 if not cl.GetIssue(): | 1593 if not cl.GetIssue(): |
| 1575 DieWithError('This branch has no associated changelist.') | 1594 DieWithError('This branch has no associated changelist.') |
| 1576 description = ChangeDescription(cl.GetDescription()) | 1595 description = ChangeDescription(cl.GetDescription()) |
| 1577 description.prompt() | 1596 description.prompt() |
| 1578 if cl.GetDescription() != description.description: | 1597 if cl.GetDescription() != description.description: |
| 1579 cl.UpdateDescription(description.description) | 1598 cl.UpdateDescription(description.description) |
| 1580 return 0 | 1599 return 0 |
| 1581 | 1600 |
| 1582 | 1601 |
| 1583 def CreateDescriptionFromLog(args): | 1602 def CreateDescriptionFromLog(args): |
| 1584 """Pulls out the commit log to use as a base for the CL description.""" | 1603 """Pulls out the commit log to use as a base for the CL description.""" |
| 1585 log_args = [] | 1604 log_args = [] |
| 1586 if len(args) == 1 and not args[0].endswith('.'): | 1605 if len(args) == 1 and not args[0].endswith('.'): |
| 1587 log_args = [args[0] + '..'] | 1606 log_args = [args[0] + '..'] |
| 1588 elif len(args) == 1 and args[0].endswith('...'): | 1607 elif len(args) == 1 and args[0].endswith('...'): |
| 1589 log_args = [args[0][:-1]] | 1608 log_args = [args[0][:-1]] |
| 1590 elif len(args) == 2: | 1609 elif len(args) == 2: |
| 1591 log_args = [args[0] + '..' + args[1]] | 1610 log_args = [args[0] + '..' + args[1]] |
| 1592 else: | 1611 else: |
| 1593 log_args = args[:] # Hope for the best! | 1612 log_args = args[:] # Hope for the best! |
| 1594 return RunGit(['log', '--pretty=format:%s\n\n%b'] + log_args) | 1613 return RunGit(['log', '--pretty=format:%s\n\n%b'] + log_args) |
| 1595 | 1614 |
| 1596 | 1615 |
| 1597 def CMDlint(parser, args): | 1616 def CMDlint(parser, args): |
| 1598 """Runs cpplint on the current changelist.""" | 1617 """Runs cpplint on the current changelist.""" |
| 1599 parser.add_option('--filter', action='append', metavar='-x,+y', | 1618 parser.add_option('--filter', action='append', metavar='-x,+y', |
| 1600 help='Comma-separated list of cpplint\'s category-filters') | 1619 help='Comma-separated list of cpplint\'s category-filters') |
| 1601 (options, args) = parser.parse_args(args) | 1620 auth.add_auth_options(parser) |
| 1621 options, args = parser.parse_args(args) |
| 1622 auth_config = auth.extract_auth_config_from_options(options) |
| 1602 | 1623 |
| 1603 # Access to a protected member _XX of a client class | 1624 # Access to a protected member _XX of a client class |
| 1604 # pylint: disable=W0212 | 1625 # pylint: disable=W0212 |
| 1605 try: | 1626 try: |
| 1606 import cpplint | 1627 import cpplint |
| 1607 import cpplint_chromium | 1628 import cpplint_chromium |
| 1608 except ImportError: | 1629 except ImportError: |
| 1609 print "Your depot_tools is missing cpplint.py and/or cpplint_chromium.py." | 1630 print "Your depot_tools is missing cpplint.py and/or cpplint_chromium.py." |
| 1610 return 1 | 1631 return 1 |
| 1611 | 1632 |
| 1612 # Change the current working directory before calling lint so that it | 1633 # Change the current working directory before calling lint so that it |
| 1613 # shows the correct base. | 1634 # shows the correct base. |
| 1614 previous_cwd = os.getcwd() | 1635 previous_cwd = os.getcwd() |
| 1615 os.chdir(settings.GetRoot()) | 1636 os.chdir(settings.GetRoot()) |
| 1616 try: | 1637 try: |
| 1617 cl = Changelist() | 1638 cl = Changelist(auth_config=auth_config) |
| 1618 change = cl.GetChange(cl.GetCommonAncestorWithUpstream(), None) | 1639 change = cl.GetChange(cl.GetCommonAncestorWithUpstream(), None) |
| 1619 files = [f.LocalPath() for f in change.AffectedFiles()] | 1640 files = [f.LocalPath() for f in change.AffectedFiles()] |
| 1620 if not files: | 1641 if not files: |
| 1621 print "Cannot lint an empty CL" | 1642 print "Cannot lint an empty CL" |
| 1622 return 1 | 1643 return 1 |
| 1623 | 1644 |
| 1624 # Process cpplints arguments if any. | 1645 # Process cpplints arguments if any. |
| 1625 command = args + files | 1646 command = args + files |
| 1626 if options.filter: | 1647 if options.filter: |
| 1627 command = ['--filter=' + ','.join(options.filter)] + command | 1648 command = ['--filter=' + ','.join(options.filter)] + command |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1646 return 1 | 1667 return 1 |
| 1647 return 0 | 1668 return 0 |
| 1648 | 1669 |
| 1649 | 1670 |
| 1650 def CMDpresubmit(parser, args): | 1671 def CMDpresubmit(parser, args): |
| 1651 """Runs presubmit tests on the current changelist.""" | 1672 """Runs presubmit tests on the current changelist.""" |
| 1652 parser.add_option('-u', '--upload', action='store_true', | 1673 parser.add_option('-u', '--upload', action='store_true', |
| 1653 help='Run upload hook instead of the push/dcommit hook') | 1674 help='Run upload hook instead of the push/dcommit hook') |
| 1654 parser.add_option('-f', '--force', action='store_true', | 1675 parser.add_option('-f', '--force', action='store_true', |
| 1655 help='Run checks even if tree is dirty') | 1676 help='Run checks even if tree is dirty') |
| 1656 (options, args) = parser.parse_args(args) | 1677 auth.add_auth_options(parser) |
| 1678 options, args = parser.parse_args(args) |
| 1679 auth_config = auth.extract_auth_config_from_options(options) |
| 1657 | 1680 |
| 1658 if not options.force and is_dirty_git_tree('presubmit'): | 1681 if not options.force and is_dirty_git_tree('presubmit'): |
| 1659 print 'use --force to check even if tree is dirty.' | 1682 print 'use --force to check even if tree is dirty.' |
| 1660 return 1 | 1683 return 1 |
| 1661 | 1684 |
| 1662 cl = Changelist() | 1685 cl = Changelist(auth_config=auth_config) |
| 1663 if args: | 1686 if args: |
| 1664 base_branch = args[0] | 1687 base_branch = args[0] |
| 1665 else: | 1688 else: |
| 1666 # Default to diffing against the common ancestor of the upstream branch. | 1689 # Default to diffing against the common ancestor of the upstream branch. |
| 1667 base_branch = cl.GetCommonAncestorWithUpstream() | 1690 base_branch = cl.GetCommonAncestorWithUpstream() |
| 1668 | 1691 |
| 1669 cl.RunHook( | 1692 cl.RunHook( |
| 1670 committing=not options.upload, | 1693 committing=not options.upload, |
| 1671 may_prompt=False, | 1694 may_prompt=False, |
| 1672 verbose=options.verbose, | 1695 verbose=options.verbose, |
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1852 # If a pending prefix exists then replace refs/ with it. | 1875 # If a pending prefix exists then replace refs/ with it. |
| 1853 if pending_prefix: | 1876 if pending_prefix: |
| 1854 remote_branch = remote_branch.replace('refs/', pending_prefix) | 1877 remote_branch = remote_branch.replace('refs/', pending_prefix) |
| 1855 return remote_branch | 1878 return remote_branch |
| 1856 | 1879 |
| 1857 | 1880 |
| 1858 def RietveldUpload(options, args, cl, change): | 1881 def RietveldUpload(options, args, cl, change): |
| 1859 """upload the patch to rietveld.""" | 1882 """upload the patch to rietveld.""" |
| 1860 upload_args = ['--assume_yes'] # Don't ask about untracked files. | 1883 upload_args = ['--assume_yes'] # Don't ask about untracked files. |
| 1861 upload_args.extend(['--server', cl.GetRietveldServer()]) | 1884 upload_args.extend(['--server', cl.GetRietveldServer()]) |
| 1885 upload_args.extend(auth.auth_config_to_command_options(cl.auth_config)) |
| 1862 if options.emulate_svn_auto_props: | 1886 if options.emulate_svn_auto_props: |
| 1863 upload_args.append('--emulate_svn_auto_props') | 1887 upload_args.append('--emulate_svn_auto_props') |
| 1864 | 1888 |
| 1865 change_desc = None | 1889 change_desc = None |
| 1866 | 1890 |
| 1867 if options.email is not None: | 1891 if options.email is not None: |
| 1868 upload_args.extend(['--email', options.email]) | 1892 upload_args.extend(['--email', options.email]) |
| 1869 | 1893 |
| 1870 if cl.GetIssue(): | 1894 if cl.GetIssue(): |
| 1871 if options.title: | 1895 if options.title: |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2023 help='Squash multiple commits into one (Gerrit only)') | 2047 help='Squash multiple commits into one (Gerrit only)') |
| 2024 parser.add_option('--email', default=None, | 2048 parser.add_option('--email', default=None, |
| 2025 help='email address to use to connect to Rietveld') | 2049 help='email address to use to connect to Rietveld') |
| 2026 parser.add_option('--tbr-owners', dest='tbr_owners', action='store_true', | 2050 parser.add_option('--tbr-owners', dest='tbr_owners', action='store_true', |
| 2027 help='add a set of OWNERS to TBR') | 2051 help='add a set of OWNERS to TBR') |
| 2028 parser.add_option('--cq-dry-run', dest='cq_dry_run', action='store_true', | 2052 parser.add_option('--cq-dry-run', dest='cq_dry_run', action='store_true', |
| 2029 help='Send the patchset to do a CQ dry run right after ' | 2053 help='Send the patchset to do a CQ dry run right after ' |
| 2030 'upload.') | 2054 'upload.') |
| 2031 | 2055 |
| 2032 add_git_similarity(parser) | 2056 add_git_similarity(parser) |
| 2057 auth.add_auth_options(parser) |
| 2033 (options, args) = parser.parse_args(args) | 2058 (options, args) = parser.parse_args(args) |
| 2059 auth_config = auth.extract_auth_config_from_options(options) |
| 2034 | 2060 |
| 2035 if is_dirty_git_tree('upload'): | 2061 if is_dirty_git_tree('upload'): |
| 2036 return 1 | 2062 return 1 |
| 2037 | 2063 |
| 2038 options.reviewers = cleanup_list(options.reviewers) | 2064 options.reviewers = cleanup_list(options.reviewers) |
| 2039 options.cc = cleanup_list(options.cc) | 2065 options.cc = cleanup_list(options.cc) |
| 2040 | 2066 |
| 2041 cl = Changelist() | 2067 cl = Changelist(auth_config=auth_config) |
| 2042 if args: | 2068 if args: |
| 2043 # TODO(ukai): is it ok for gerrit case? | 2069 # TODO(ukai): is it ok for gerrit case? |
| 2044 base_branch = args[0] | 2070 base_branch = args[0] |
| 2045 else: | 2071 else: |
| 2046 if cl.GetBranch() is None: | 2072 if cl.GetBranch() is None: |
| 2047 DieWithError('Can\'t upload from detached HEAD state. Get on a branch!') | 2073 DieWithError('Can\'t upload from detached HEAD state. Get on a branch!') |
| 2048 | 2074 |
| 2049 # Default to diffing against common ancestor of upstream branch | 2075 # Default to diffing against common ancestor of upstream branch |
| 2050 base_branch = cl.GetCommonAncestorWithUpstream() | 2076 base_branch = cl.GetCommonAncestorWithUpstream() |
| 2051 args = [base_branch, 'HEAD'] | 2077 args = [base_branch, 'HEAD'] |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2125 help='bypass upload presubmit hook') | 2151 help='bypass upload presubmit hook') |
| 2126 parser.add_option('-m', dest='message', | 2152 parser.add_option('-m', dest='message', |
| 2127 help="override review description") | 2153 help="override review description") |
| 2128 parser.add_option('-f', action='store_true', dest='force', | 2154 parser.add_option('-f', action='store_true', dest='force', |
| 2129 help="force yes to questions (don't prompt)") | 2155 help="force yes to questions (don't prompt)") |
| 2130 parser.add_option('-c', dest='contributor', | 2156 parser.add_option('-c', dest='contributor', |
| 2131 help="external contributor for patch (appended to " + | 2157 help="external contributor for patch (appended to " + |
| 2132 "description and used as author for git). Should be " + | 2158 "description and used as author for git). Should be " + |
| 2133 "formatted as 'First Last <email@example.com>'") | 2159 "formatted as 'First Last <email@example.com>'") |
| 2134 add_git_similarity(parser) | 2160 add_git_similarity(parser) |
| 2161 auth.add_auth_options(parser) |
| 2135 (options, args) = parser.parse_args(args) | 2162 (options, args) = parser.parse_args(args) |
| 2136 cl = Changelist() | 2163 auth_config = auth.extract_auth_config_from_options(options) |
| 2164 |
| 2165 cl = Changelist(auth_config=auth_config) |
| 2137 | 2166 |
| 2138 current = cl.GetBranch() | 2167 current = cl.GetBranch() |
| 2139 remote, upstream_branch = cl.FetchUpstreamTuple(cl.GetBranch()) | 2168 remote, upstream_branch = cl.FetchUpstreamTuple(cl.GetBranch()) |
| 2140 if not settings.GetIsGitSvn() and remote == '.': | 2169 if not settings.GetIsGitSvn() and remote == '.': |
| 2141 print | 2170 print |
| 2142 print 'Attempting to push branch %r into another local branch!' % current | 2171 print 'Attempting to push branch %r into another local branch!' % current |
| 2143 print | 2172 print |
| 2144 print 'Either reparent this branch on top of origin/master:' | 2173 print 'Either reparent this branch on top of origin/master:' |
| 2145 print ' git reparent-branch --root' | 2174 print ' git reparent-branch --root' |
| 2146 print | 2175 print |
| (...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2524 parser.add_option('-f', '--force', action='store_true', | 2553 parser.add_option('-f', '--force', action='store_true', |
| 2525 help='with -b, clobber any existing branch') | 2554 help='with -b, clobber any existing branch') |
| 2526 parser.add_option('-d', '--directory', action='store', metavar='DIR', | 2555 parser.add_option('-d', '--directory', action='store', metavar='DIR', |
| 2527 help='Change to the directory DIR immediately, ' | 2556 help='Change to the directory DIR immediately, ' |
| 2528 'before doing anything else.') | 2557 'before doing anything else.') |
| 2529 parser.add_option('--reject', action='store_true', | 2558 parser.add_option('--reject', action='store_true', |
| 2530 help='failed patches spew .rej files rather than ' | 2559 help='failed patches spew .rej files rather than ' |
| 2531 'attempting a 3-way merge') | 2560 'attempting a 3-way merge') |
| 2532 parser.add_option('-n', '--no-commit', action='store_true', dest='nocommit', | 2561 parser.add_option('-n', '--no-commit', action='store_true', dest='nocommit', |
| 2533 help="don't commit after patch applies") | 2562 help="don't commit after patch applies") |
| 2563 auth.add_auth_options(parser) |
| 2534 (options, args) = parser.parse_args(args) | 2564 (options, args) = parser.parse_args(args) |
| 2565 auth_config = auth.extract_auth_config_from_options(options) |
| 2566 |
| 2535 if len(args) != 1: | 2567 if len(args) != 1: |
| 2536 parser.print_help() | 2568 parser.print_help() |
| 2537 return 1 | 2569 return 1 |
| 2538 issue_arg = args[0] | 2570 issue_arg = args[0] |
| 2539 | 2571 |
| 2540 # We don't want uncommitted changes mixed up with the patch. | 2572 # We don't want uncommitted changes mixed up with the patch. |
| 2541 if is_dirty_git_tree('patch'): | 2573 if is_dirty_git_tree('patch'): |
| 2542 return 1 | 2574 return 1 |
| 2543 | 2575 |
| 2544 # TODO(maruel): Use apply_issue.py | 2576 # TODO(maruel): Use apply_issue.py |
| 2545 # TODO(ukai): use gerrit-cherry-pick for gerrit repository? | 2577 # TODO(ukai): use gerrit-cherry-pick for gerrit repository? |
| 2546 | 2578 |
| 2547 if options.newbranch: | 2579 if options.newbranch: |
| 2548 if options.force: | 2580 if options.force: |
| 2549 RunGit(['branch', '-D', options.newbranch], | 2581 RunGit(['branch', '-D', options.newbranch], |
| 2550 stderr=subprocess2.PIPE, error_ok=True) | 2582 stderr=subprocess2.PIPE, error_ok=True) |
| 2551 RunGit(['checkout', '-b', options.newbranch, | 2583 RunGit(['checkout', '-b', options.newbranch, |
| 2552 Changelist().GetUpstreamBranch()]) | 2584 Changelist().GetUpstreamBranch()]) |
| 2553 | 2585 |
| 2554 return PatchIssue(issue_arg, options.reject, options.nocommit, | 2586 return PatchIssue(issue_arg, options.reject, options.nocommit, |
| 2555 options.directory) | 2587 options.directory, auth_config) |
| 2556 | 2588 |
| 2557 | 2589 |
| 2558 def PatchIssue(issue_arg, reject, nocommit, directory): | 2590 def PatchIssue(issue_arg, reject, nocommit, directory, auth_config): |
| 2559 # There's a "reset --hard" when failing to apply the patch. In order | 2591 # There's a "reset --hard" when failing to apply the patch. In order |
| 2560 # not to destroy users' data, make sure the tree is not dirty here. | 2592 # not to destroy users' data, make sure the tree is not dirty here. |
| 2561 assert(not is_dirty_git_tree('apply')) | 2593 assert(not is_dirty_git_tree('apply')) |
| 2562 | 2594 |
| 2563 if type(issue_arg) is int or issue_arg.isdigit(): | 2595 if type(issue_arg) is int or issue_arg.isdigit(): |
| 2564 # Input is an issue id. Figure out the URL. | 2596 # Input is an issue id. Figure out the URL. |
| 2565 issue = int(issue_arg) | 2597 issue = int(issue_arg) |
| 2566 cl = Changelist(issue=issue) | 2598 cl = Changelist(issue=issue, auth_config=auth_config) |
| 2567 patchset = cl.GetMostRecentPatchset() | 2599 patchset = cl.GetMostRecentPatchset() |
| 2568 patch_data = cl.GetPatchSetDiff(issue, patchset) | 2600 patch_data = cl.GetPatchSetDiff(issue, patchset) |
| 2569 else: | 2601 else: |
| 2570 # Assume it's a URL to the patch. Default to https. | 2602 # Assume it's a URL to the patch. Default to https. |
| 2571 issue_url = gclient_utils.UpgradeToHttps(issue_arg) | 2603 issue_url = gclient_utils.UpgradeToHttps(issue_arg) |
| 2572 match = re.match(r'.*?/issue(\d+)_(\d+).diff', issue_url) | 2604 match = re.match(r'.*?/issue(\d+)_(\d+).diff', issue_url) |
| 2573 if not match: | 2605 if not match: |
| 2574 DieWithError('Must pass an issue ID or full URL for ' | 2606 DieWithError('Must pass an issue ID or full URL for ' |
| 2575 '\'Download raw patch set\'') | 2607 '\'Download raw patch set\'') |
| 2576 issue = int(match.group(1)) | 2608 issue = int(match.group(1)) |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2609 stdin=patch_data, stdout=subprocess2.VOID) | 2641 stdin=patch_data, stdout=subprocess2.VOID) |
| 2610 except subprocess2.CalledProcessError: | 2642 except subprocess2.CalledProcessError: |
| 2611 RunGit(['reset', '--hard']) | 2643 RunGit(['reset', '--hard']) |
| 2612 DieWithError('Failed to apply the patch') | 2644 DieWithError('Failed to apply the patch') |
| 2613 | 2645 |
| 2614 # If we had an issue, commit the current state and register the issue. | 2646 # If we had an issue, commit the current state and register the issue. |
| 2615 if not nocommit: | 2647 if not nocommit: |
| 2616 RunGit(['commit', '-m', ('patch from issue %(i)s at patchset ' | 2648 RunGit(['commit', '-m', ('patch from issue %(i)s at patchset ' |
| 2617 '%(p)s (http://crrev.com/%(i)s#ps%(p)s)' | 2649 '%(p)s (http://crrev.com/%(i)s#ps%(p)s)' |
| 2618 % {'i': issue, 'p': patchset})]) | 2650 % {'i': issue, 'p': patchset})]) |
| 2619 cl = Changelist() | 2651 cl = Changelist(auth_config=auth_config) |
| 2620 cl.SetIssue(issue) | 2652 cl.SetIssue(issue) |
| 2621 cl.SetPatchset(patchset) | 2653 cl.SetPatchset(patchset) |
| 2622 print "Committed patch locally." | 2654 print "Committed patch locally." |
| 2623 else: | 2655 else: |
| 2624 print "Patch applied to index." | 2656 print "Patch applied to index." |
| 2625 return 0 | 2657 return 0 |
| 2626 | 2658 |
| 2627 | 2659 |
| 2628 def CMDrebase(parser, args): | 2660 def CMDrebase(parser, args): |
| 2629 """Rebases current branch on top of svn repo.""" | 2661 """Rebases current branch on top of svn repo.""" |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2729 "-c", "--clobber", action="store_true", default=False, | 2761 "-c", "--clobber", action="store_true", default=False, |
| 2730 help="Force a clobber before building; e.g. don't do an " | 2762 help="Force a clobber before building; e.g. don't do an " |
| 2731 "incremental build") | 2763 "incremental build") |
| 2732 group.add_option( | 2764 group.add_option( |
| 2733 "--project", | 2765 "--project", |
| 2734 help="Override which project to use. Projects are defined " | 2766 help="Override which project to use. Projects are defined " |
| 2735 "server-side to define what default bot set to use") | 2767 "server-side to define what default bot set to use") |
| 2736 group.add_option( | 2768 group.add_option( |
| 2737 "-n", "--name", help="Try job name; default to current branch name") | 2769 "-n", "--name", help="Try job name; default to current branch name") |
| 2738 parser.add_option_group(group) | 2770 parser.add_option_group(group) |
| 2771 auth.add_auth_options(parser) |
| 2739 options, args = parser.parse_args(args) | 2772 options, args = parser.parse_args(args) |
| 2773 auth_config = auth.extract_auth_config_from_options(options) |
| 2740 | 2774 |
| 2741 if args: | 2775 if args: |
| 2742 parser.error('Unknown arguments: %s' % args) | 2776 parser.error('Unknown arguments: %s' % args) |
| 2743 | 2777 |
| 2744 cl = Changelist() | 2778 cl = Changelist(auth_config=auth_config) |
| 2745 if not cl.GetIssue(): | 2779 if not cl.GetIssue(): |
| 2746 parser.error('Need to upload first') | 2780 parser.error('Need to upload first') |
| 2747 | 2781 |
| 2748 props = cl.GetIssueProperties() | 2782 props = cl.GetIssueProperties() |
| 2749 if props.get('closed'): | 2783 if props.get('closed'): |
| 2750 parser.error('Cannot send tryjobs for a closed CL') | 2784 parser.error('Cannot send tryjobs for a closed CL') |
| 2751 | 2785 |
| 2752 if props.get('private'): | 2786 if props.get('private'): |
| 2753 parser.error('Cannot use trybots with private issue') | 2787 parser.error('Cannot use trybots with private issue') |
| 2754 | 2788 |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2882 if not issue_url: | 2916 if not issue_url: |
| 2883 print >> sys.stderr, 'ERROR No issue to open' | 2917 print >> sys.stderr, 'ERROR No issue to open' |
| 2884 return 1 | 2918 return 1 |
| 2885 | 2919 |
| 2886 webbrowser.open(issue_url) | 2920 webbrowser.open(issue_url) |
| 2887 return 0 | 2921 return 0 |
| 2888 | 2922 |
| 2889 | 2923 |
| 2890 def CMDset_commit(parser, args): | 2924 def CMDset_commit(parser, args): |
| 2891 """Sets the commit bit to trigger the Commit Queue.""" | 2925 """Sets the commit bit to trigger the Commit Queue.""" |
| 2892 _, args = parser.parse_args(args) | 2926 auth.add_auth_options(parser) |
| 2927 options, args = parser.parse_args(args) |
| 2928 auth_config = auth.extract_auth_config_from_options(options) |
| 2893 if args: | 2929 if args: |
| 2894 parser.error('Unrecognized args: %s' % ' '.join(args)) | 2930 parser.error('Unrecognized args: %s' % ' '.join(args)) |
| 2895 cl = Changelist() | 2931 cl = Changelist(auth_config=auth_config) |
| 2896 props = cl.GetIssueProperties() | 2932 props = cl.GetIssueProperties() |
| 2897 if props.get('private'): | 2933 if props.get('private'): |
| 2898 parser.error('Cannot set commit on private issue') | 2934 parser.error('Cannot set commit on private issue') |
| 2899 cl.SetFlag('commit', '1') | 2935 cl.SetFlag('commit', '1') |
| 2900 return 0 | 2936 return 0 |
| 2901 | 2937 |
| 2902 | 2938 |
| 2903 def CMDset_close(parser, args): | 2939 def CMDset_close(parser, args): |
| 2904 """Closes the issue.""" | 2940 """Closes the issue.""" |
| 2905 _, args = parser.parse_args(args) | 2941 auth.add_auth_options(parser) |
| 2942 options, args = parser.parse_args(args) |
| 2943 auth_config = auth.extract_auth_config_from_options(options) |
| 2906 if args: | 2944 if args: |
| 2907 parser.error('Unrecognized args: %s' % ' '.join(args)) | 2945 parser.error('Unrecognized args: %s' % ' '.join(args)) |
| 2908 cl = Changelist() | 2946 cl = Changelist(auth_config=auth_config) |
| 2909 # Ensure there actually is an issue to close. | 2947 # Ensure there actually is an issue to close. |
| 2910 cl.GetDescription() | 2948 cl.GetDescription() |
| 2911 cl.CloseIssue() | 2949 cl.CloseIssue() |
| 2912 return 0 | 2950 return 0 |
| 2913 | 2951 |
| 2914 | 2952 |
| 2915 def CMDdiff(parser, args): | 2953 def CMDdiff(parser, args): |
| 2916 """Shows differences between local tree and last upload.""" | 2954 """Shows differences between local tree and last upload.""" |
| 2917 parser.parse_args(args) | 2955 auth.add_auth_options(parser) |
| 2956 options, args = parser.parse_args(args) |
| 2957 auth_config = auth.extract_auth_config_from_options(options) |
| 2958 if args: |
| 2959 parser.error('Unrecognized args: %s' % ' '.join(args)) |
| 2918 | 2960 |
| 2919 # Uncommitted (staged and unstaged) changes will be destroyed by | 2961 # Uncommitted (staged and unstaged) changes will be destroyed by |
| 2920 # "git reset --hard" if there are merging conflicts in PatchIssue(). | 2962 # "git reset --hard" if there are merging conflicts in PatchIssue(). |
| 2921 # Staged changes would be committed along with the patch from last | 2963 # Staged changes would be committed along with the patch from last |
| 2922 # upload, hence counted toward the "last upload" side in the final | 2964 # upload, hence counted toward the "last upload" side in the final |
| 2923 # diff output, and this is not what we want. | 2965 # diff output, and this is not what we want. |
| 2924 if is_dirty_git_tree('diff'): | 2966 if is_dirty_git_tree('diff'): |
| 2925 return 1 | 2967 return 1 |
| 2926 | 2968 |
| 2927 cl = Changelist() | 2969 cl = Changelist(auth_config=auth_config) |
| 2928 issue = cl.GetIssue() | 2970 issue = cl.GetIssue() |
| 2929 branch = cl.GetBranch() | 2971 branch = cl.GetBranch() |
| 2930 if not issue: | 2972 if not issue: |
| 2931 DieWithError('No issue found for current branch (%s)' % branch) | 2973 DieWithError('No issue found for current branch (%s)' % branch) |
| 2932 TMP_BRANCH = 'git-cl-diff' | 2974 TMP_BRANCH = 'git-cl-diff' |
| 2933 base_branch = cl.GetCommonAncestorWithUpstream() | 2975 base_branch = cl.GetCommonAncestorWithUpstream() |
| 2934 | 2976 |
| 2935 # Create a new branch based on the merge-base | 2977 # Create a new branch based on the merge-base |
| 2936 RunGit(['checkout', '-q', '-b', TMP_BRANCH, base_branch]) | 2978 RunGit(['checkout', '-q', '-b', TMP_BRANCH, base_branch]) |
| 2937 try: | 2979 try: |
| 2938 # Patch in the latest changes from rietveld. | 2980 # Patch in the latest changes from rietveld. |
| 2939 rtn = PatchIssue(issue, False, False, None) | 2981 rtn = PatchIssue(issue, False, False, None, auth_config) |
| 2940 if rtn != 0: | 2982 if rtn != 0: |
| 2941 return rtn | 2983 return rtn |
| 2942 | 2984 |
| 2943 # Switch back to starting branch and diff against the temporary | 2985 # Switch back to starting branch and diff against the temporary |
| 2944 # branch containing the latest rietveld patch. | 2986 # branch containing the latest rietveld patch. |
| 2945 subprocess2.check_call(['git', 'diff', TMP_BRANCH, branch, '--']) | 2987 subprocess2.check_call(['git', 'diff', TMP_BRANCH, branch, '--']) |
| 2946 finally: | 2988 finally: |
| 2947 RunGit(['checkout', '-q', branch]) | 2989 RunGit(['checkout', '-q', branch]) |
| 2948 RunGit(['branch', '-D', TMP_BRANCH]) | 2990 RunGit(['branch', '-D', TMP_BRANCH]) |
| 2949 | 2991 |
| 2950 return 0 | 2992 return 0 |
| 2951 | 2993 |
| 2952 | 2994 |
| 2953 def CMDowners(parser, args): | 2995 def CMDowners(parser, args): |
| 2954 """Interactively find the owners for reviewing.""" | 2996 """Interactively find the owners for reviewing.""" |
| 2955 parser.add_option( | 2997 parser.add_option( |
| 2956 '--no-color', | 2998 '--no-color', |
| 2957 action='store_true', | 2999 action='store_true', |
| 2958 help='Use this option to disable color output') | 3000 help='Use this option to disable color output') |
| 3001 auth.add_auth_options(parser) |
| 2959 options, args = parser.parse_args(args) | 3002 options, args = parser.parse_args(args) |
| 3003 auth_config = auth.extract_auth_config_from_options(options) |
| 2960 | 3004 |
| 2961 author = RunGit(['config', 'user.email']).strip() or None | 3005 author = RunGit(['config', 'user.email']).strip() or None |
| 2962 | 3006 |
| 2963 cl = Changelist() | 3007 cl = Changelist(auth_config=auth_config) |
| 2964 | 3008 |
| 2965 if args: | 3009 if args: |
| 2966 if len(args) > 1: | 3010 if len(args) > 1: |
| 2967 parser.error('Unknown args') | 3011 parser.error('Unknown args') |
| 2968 base_branch = args[0] | 3012 base_branch = args[0] |
| 2969 else: | 3013 else: |
| 2970 # Default to diffing against the common ancestor of the upstream branch. | 3014 # Default to diffing against the common ancestor of the upstream branch. |
| 2971 base_branch = cl.GetCommonAncestorWithUpstream() | 3015 base_branch = cl.GetCommonAncestorWithUpstream() |
| 2972 | 3016 |
| 2973 change = cl.GetChange(base_branch, None) | 3017 change = cl.GetChange(base_branch, None) |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3161 if __name__ == '__main__': | 3205 if __name__ == '__main__': |
| 3162 # These affect sys.stdout so do it outside of main() to simplify mocks in | 3206 # These affect sys.stdout so do it outside of main() to simplify mocks in |
| 3163 # unit testing. | 3207 # unit testing. |
| 3164 fix_encoding.fix_encoding() | 3208 fix_encoding.fix_encoding() |
| 3165 colorama.init() | 3209 colorama.init() |
| 3166 try: | 3210 try: |
| 3167 sys.exit(main(sys.argv[1:])) | 3211 sys.exit(main(sys.argv[1:])) |
| 3168 except KeyboardInterrupt: | 3212 except KeyboardInterrupt: |
| 3169 sys.stderr.write('interrupted\n') | 3213 sys.stderr.write('interrupted\n') |
| 3170 sys.exit(1) | 3214 sys.exit(1) |
| OLD | NEW |