|
|
|
@ -1033,7 +1033,7 @@ def DownloadHooks(force):
|
|
|
|
|
|
|
|
|
|
@usage('[repo root containing codereview.settings]')
|
|
|
|
|
def CMDconfig(parser, args):
|
|
|
|
|
"""Edits configuration for this tree."""
|
|
|
|
|
"""edit configuration for this tree"""
|
|
|
|
|
|
|
|
|
|
_, args = parser.parse_args(args)
|
|
|
|
|
if len(args) == 0:
|
|
|
|
@ -1052,7 +1052,7 @@ def CMDconfig(parser, args):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def CMDbaseurl(parser, args):
|
|
|
|
|
"""Gets or sets base-url for this branch."""
|
|
|
|
|
"""get or set base-url for this branch"""
|
|
|
|
|
branchref = RunGit(['symbolic-ref', 'HEAD']).strip()
|
|
|
|
|
branch = ShortBranchName(branchref)
|
|
|
|
|
_, args = parser.parse_args(args)
|
|
|
|
@ -1067,17 +1067,7 @@ def CMDbaseurl(parser, args):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def CMDstatus(parser, args):
|
|
|
|
|
"""Show status of changelists.
|
|
|
|
|
|
|
|
|
|
Colors are used to tell the state of the CL unless --fast is used:
|
|
|
|
|
- Green LGTM'ed
|
|
|
|
|
- Blue waiting for review
|
|
|
|
|
- Yellow waiting for you to reply to review
|
|
|
|
|
- Red not sent for review or broken
|
|
|
|
|
- Cyan was committed, branch can be deleted
|
|
|
|
|
|
|
|
|
|
Also see 'git cl comments'.
|
|
|
|
|
"""
|
|
|
|
|
"""show status of changelists"""
|
|
|
|
|
parser.add_option('--field',
|
|
|
|
|
help='print only specific field (desc|id|patch|url)')
|
|
|
|
|
parser.add_option('-f', '--fast', action='store_true',
|
|
|
|
@ -1119,37 +1109,18 @@ def CMDstatus(parser, args):
|
|
|
|
|
|
|
|
|
|
if not options.fast:
|
|
|
|
|
def fetch(b):
|
|
|
|
|
"""Fetches information for an issue and returns (branch, issue, color)."""
|
|
|
|
|
c = Changelist(branchref=b)
|
|
|
|
|
i = c.GetIssueURL()
|
|
|
|
|
props = {}
|
|
|
|
|
r = None
|
|
|
|
|
if i:
|
|
|
|
|
try:
|
|
|
|
|
props = c.GetIssueProperties()
|
|
|
|
|
r = c.GetApprovingReviewers() if i else None
|
|
|
|
|
except urllib2.HTTPError:
|
|
|
|
|
# The issue probably doesn't exist anymore.
|
|
|
|
|
i += ' (broken)'
|
|
|
|
|
|
|
|
|
|
msgs = props.get('messages') or []
|
|
|
|
|
|
|
|
|
|
if not i:
|
|
|
|
|
color = Fore.WHITE
|
|
|
|
|
elif props.get('closed'):
|
|
|
|
|
# Issue is closed.
|
|
|
|
|
color = Fore.CYAN
|
|
|
|
|
elif r:
|
|
|
|
|
# Was LGTM'ed.
|
|
|
|
|
color = Fore.GREEN
|
|
|
|
|
elif not msgs:
|
|
|
|
|
# No message was sent.
|
|
|
|
|
color = Fore.RED
|
|
|
|
|
elif msgs[-1]['sender'] != props.get('owner_email'):
|
|
|
|
|
color = Fore.YELLOW
|
|
|
|
|
else:
|
|
|
|
|
color = Fore.BLUE
|
|
|
|
|
output.put((b, i, color))
|
|
|
|
|
try:
|
|
|
|
|
props = c.GetIssueProperties()
|
|
|
|
|
r = c.GetApprovingReviewers() if i else None
|
|
|
|
|
if not props.get('messages'):
|
|
|
|
|
r = None
|
|
|
|
|
except urllib2.HTTPError:
|
|
|
|
|
# The issue probably doesn't exist anymore.
|
|
|
|
|
i += ' (broken)'
|
|
|
|
|
r = None
|
|
|
|
|
output.put((b, i, r))
|
|
|
|
|
|
|
|
|
|
threads = [threading.Thread(target=fetch, args=(b,)) for b in branches]
|
|
|
|
|
for t in threads:
|
|
|
|
@ -1159,16 +1130,25 @@ def CMDstatus(parser, args):
|
|
|
|
|
# Do not use GetApprovingReviewers(), since it requires an HTTP request.
|
|
|
|
|
for b in branches:
|
|
|
|
|
c = Changelist(branchref=b)
|
|
|
|
|
url = c.GetIssueURL()
|
|
|
|
|
output.put((b, url, Fore.BLUE if url else Fore.WHITE))
|
|
|
|
|
output.put((b, c.GetIssue(), None))
|
|
|
|
|
|
|
|
|
|
tmp = {}
|
|
|
|
|
alignment = max(5, max(len(ShortBranchName(b)) for b in branches))
|
|
|
|
|
for branch in sorted(branches):
|
|
|
|
|
while branch not in tmp:
|
|
|
|
|
b, i, color = output.get()
|
|
|
|
|
tmp[b] = (i, color)
|
|
|
|
|
issue, color = tmp.pop(branch)
|
|
|
|
|
b, i, r = output.get()
|
|
|
|
|
tmp[b] = (i, r)
|
|
|
|
|
issue, reviewers = tmp.pop(branch)
|
|
|
|
|
if not issue:
|
|
|
|
|
color = Fore.WHITE
|
|
|
|
|
elif reviewers:
|
|
|
|
|
# Was approved.
|
|
|
|
|
color = Fore.GREEN
|
|
|
|
|
elif reviewers is None:
|
|
|
|
|
# No message was sent.
|
|
|
|
|
color = Fore.RED
|
|
|
|
|
else:
|
|
|
|
|
color = Fore.BLUE
|
|
|
|
|
print ' %*s: %s%s%s' % (
|
|
|
|
|
alignment, ShortBranchName(branch), color, issue, Fore.RESET)
|
|
|
|
|
|
|
|
|
@ -1187,10 +1167,10 @@ def CMDstatus(parser, args):
|
|
|
|
|
|
|
|
|
|
@usage('[issue_number]')
|
|
|
|
|
def CMDissue(parser, args):
|
|
|
|
|
"""Sets or displays the current code review issue number.
|
|
|
|
|
"""Set or display the current code review issue number.
|
|
|
|
|
|
|
|
|
|
Pass issue number 0 to clear the current issue.
|
|
|
|
|
"""
|
|
|
|
|
"""
|
|
|
|
|
_, args = parser.parse_args(args)
|
|
|
|
|
|
|
|
|
|
cl = Changelist()
|
|
|
|
@ -1206,7 +1186,7 @@ def CMDissue(parser, args):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def CMDcomments(parser, args):
|
|
|
|
|
"""Shows review comments of the current changelist."""
|
|
|
|
|
"""show review comments of the current changelist"""
|
|
|
|
|
(_, args) = parser.parse_args(args)
|
|
|
|
|
if args:
|
|
|
|
|
parser.error('Unsupported argument: %s' % args)
|
|
|
|
@ -1232,7 +1212,7 @@ def CMDcomments(parser, args):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def CMDdescription(parser, args):
|
|
|
|
|
"""Brings up the editor for the current CL's description."""
|
|
|
|
|
"""brings up the editor for the current CL's description."""
|
|
|
|
|
cl = Changelist()
|
|
|
|
|
if not cl.GetIssue():
|
|
|
|
|
DieWithError('This branch has no associated changelist.')
|
|
|
|
@ -1257,7 +1237,7 @@ def CreateDescriptionFromLog(args):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def CMDpresubmit(parser, args):
|
|
|
|
|
"""Runs presubmit tests on the current changelist."""
|
|
|
|
|
"""run presubmit tests on the current changelist"""
|
|
|
|
|
parser.add_option('-u', '--upload', action='store_true',
|
|
|
|
|
help='Run upload hook instead of the push/dcommit hook')
|
|
|
|
|
parser.add_option('-f', '--force', action='store_true',
|
|
|
|
@ -1444,7 +1424,7 @@ def cleanup_list(l):
|
|
|
|
|
|
|
|
|
|
@usage('[args to "git diff"]')
|
|
|
|
|
def CMDupload(parser, args):
|
|
|
|
|
"""Uploads the current changelist to codereview."""
|
|
|
|
|
"""upload the current changelist to codereview"""
|
|
|
|
|
parser.add_option('--bypass-hooks', action='store_true', dest='bypass_hooks',
|
|
|
|
|
help='bypass upload presubmit hook')
|
|
|
|
|
parser.add_option('--bypass-watchlists', action='store_true',
|
|
|
|
@ -1767,7 +1747,7 @@ def SendUpstream(parser, args, cmd):
|
|
|
|
|
|
|
|
|
|
@usage('[upstream branch to apply against]')
|
|
|
|
|
def CMDdcommit(parser, args):
|
|
|
|
|
"""Commits the current changelist via git-svn."""
|
|
|
|
|
"""commit the current changelist via git-svn"""
|
|
|
|
|
if not settings.GetIsGitSvn():
|
|
|
|
|
message = """This doesn't appear to be an SVN repository.
|
|
|
|
|
If your project has a git mirror with an upstream SVN master, you probably need
|
|
|
|
@ -1783,7 +1763,7 @@ will instead be silently ignored."""
|
|
|
|
|
|
|
|
|
|
@usage('[upstream branch to apply against]')
|
|
|
|
|
def CMDpush(parser, args):
|
|
|
|
|
"""Commits the current changelist via git."""
|
|
|
|
|
"""commit the current changelist via git"""
|
|
|
|
|
if settings.GetIsGitSvn():
|
|
|
|
|
print('This appears to be an SVN repository.')
|
|
|
|
|
print('Are you sure you didn\'t mean \'git cl dcommit\'?')
|
|
|
|
@ -1793,7 +1773,7 @@ def CMDpush(parser, args):
|
|
|
|
|
|
|
|
|
|
@usage('<patch url or issue id>')
|
|
|
|
|
def CMDpatch(parser, args):
|
|
|
|
|
"""Patchs in a code review."""
|
|
|
|
|
"""patch in a code review"""
|
|
|
|
|
parser.add_option('-b', dest='newbranch',
|
|
|
|
|
help='create a new branch off trunk for the patch')
|
|
|
|
|
parser.add_option('-f', action='store_true', dest='force',
|
|
|
|
@ -1883,7 +1863,7 @@ def CMDpatch(parser, args):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def CMDrebase(parser, args):
|
|
|
|
|
"""Rebases current branch on top of svn repo."""
|
|
|
|
|
"""rebase current branch on top of svn repo"""
|
|
|
|
|
# Provide a wrapper for git svn rebase to help avoid accidental
|
|
|
|
|
# git svn dcommit.
|
|
|
|
|
# It's the only command that doesn't use parser at all since we just defer
|
|
|
|
@ -1921,7 +1901,7 @@ def GetTreeStatusReason():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def CMDtree(parser, args):
|
|
|
|
|
"""Shows the status of the tree."""
|
|
|
|
|
"""show the status of the tree"""
|
|
|
|
|
_, args = parser.parse_args(args)
|
|
|
|
|
status = GetTreeStatus()
|
|
|
|
|
if 'unset' == status:
|
|
|
|
@ -2037,7 +2017,7 @@ def CMDtry(parser, args):
|
|
|
|
|
|
|
|
|
|
@usage('[new upstream branch]')
|
|
|
|
|
def CMDupstream(parser, args):
|
|
|
|
|
"""Prints or sets the name of the upstream branch, if any."""
|
|
|
|
|
"""prints or sets the name of the upstream branch, if any"""
|
|
|
|
|
_, args = parser.parse_args(args)
|
|
|
|
|
if len(args) > 1:
|
|
|
|
|
parser.error('Unrecognized args: %s' % ' '.join(args))
|
|
|
|
@ -2055,7 +2035,7 @@ def CMDupstream(parser, args):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def CMDset_commit(parser, args):
|
|
|
|
|
"""Sets the commit bit to trigger the Commit Queue."""
|
|
|
|
|
"""set the commit bit"""
|
|
|
|
|
_, args = parser.parse_args(args)
|
|
|
|
|
if args:
|
|
|
|
|
parser.error('Unrecognized args: %s' % ' '.join(args))
|
|
|
|
@ -2065,7 +2045,7 @@ def CMDset_commit(parser, args):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def CMDset_close(parser, args):
|
|
|
|
|
"""Closes the issue."""
|
|
|
|
|
"""close the issue"""
|
|
|
|
|
_, args = parser.parse_args(args)
|
|
|
|
|
if args:
|
|
|
|
|
parser.error('Unrecognized args: %s' % ' '.join(args))
|
|
|
|
@ -2077,7 +2057,7 @@ def CMDset_close(parser, args):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def CMDformat(parser, args):
|
|
|
|
|
"""Runs clang-format on the diff."""
|
|
|
|
|
"""run clang-format on the diff"""
|
|
|
|
|
CLANG_EXTS = ['.cc', '.cpp', '.h']
|
|
|
|
|
parser.add_option('--full', action='store_true', default=False)
|
|
|
|
|
opts, args = parser.parse_args(args)
|
|
|
|
@ -2174,7 +2154,7 @@ def Command(name):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def CMDhelp(parser, args):
|
|
|
|
|
"""Prints list of commands or help for a specific command."""
|
|
|
|
|
"""print list of commands or help for a specific command"""
|
|
|
|
|
_, args = parser.parse_args(args)
|
|
|
|
|
if len(args) == 1:
|
|
|
|
|
return main(args + ['--help'])
|
|
|
|
@ -2192,32 +2172,11 @@ def GenUsage(parser, command):
|
|
|
|
|
if command == 'help':
|
|
|
|
|
command = '<command>'
|
|
|
|
|
else:
|
|
|
|
|
parser.description = obj.__doc__
|
|
|
|
|
# OptParser.description prefer nicely non-formatted strings.
|
|
|
|
|
parser.description = re.sub('[\r\n ]{2,}', ' ', obj.__doc__)
|
|
|
|
|
parser.set_usage('usage: %%prog %s [options] %s' % (command, more))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class OptionParser(optparse.OptionParser):
|
|
|
|
|
"""Creates the option parse and add --verbose support."""
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
|
optparse.OptionParser.__init__(self, *args, **kwargs)
|
|
|
|
|
self.add_option(
|
|
|
|
|
'-v', '--verbose', action='count', default=0,
|
|
|
|
|
help='Use 2 times for more debugging info')
|
|
|
|
|
|
|
|
|
|
def parse_args(self, args=None, values=None):
|
|
|
|
|
options, args = optparse.OptionParser.parse_args(self, args, values)
|
|
|
|
|
levels = [logging.WARNING, logging.INFO, logging.DEBUG]
|
|
|
|
|
logging.basicConfig(level=levels[min(options.verbose, len(levels) - 1)])
|
|
|
|
|
return options, args
|
|
|
|
|
|
|
|
|
|
def format_description(self, _):
|
|
|
|
|
"""Disables automatic reformatting."""
|
|
|
|
|
lines = self.description.rstrip().splitlines()
|
|
|
|
|
lines_fixed = [lines[0]] + [l[2:] if len(l) >= 2 else l for l in lines[1:]]
|
|
|
|
|
description = ''.join(l + '\n' for l in lines_fixed)
|
|
|
|
|
return description[0].upper() + description[1:]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main(argv):
|
|
|
|
|
"""Doesn't parse the arguments here, just find the right subcommand to
|
|
|
|
|
execute."""
|
|
|
|
@ -2234,19 +2193,29 @@ def main(argv):
|
|
|
|
|
# Do it late so all commands are listed.
|
|
|
|
|
commands = Commands()
|
|
|
|
|
length = max(len(c) for c in commands)
|
|
|
|
|
|
|
|
|
|
def gen_summary(x):
|
|
|
|
|
"""Creates a oneline summary from the docstring."""
|
|
|
|
|
line = x.split('\n', 1)[0].rstrip('.')
|
|
|
|
|
return line[0].lower() + line[1:]
|
|
|
|
|
|
|
|
|
|
docs = sorted(
|
|
|
|
|
(name, gen_summary(handler.__doc__).strip())
|
|
|
|
|
(name, handler.__doc__.split('\n')[0].strip())
|
|
|
|
|
for name, handler in commands.iteritems())
|
|
|
|
|
CMDhelp.usage_more = ('\n\nCommands are:\n' + '\n'.join(
|
|
|
|
|
' %-*s %s' % (length, name, doc) for name, doc in docs))
|
|
|
|
|
|
|
|
|
|
parser = OptionParser()
|
|
|
|
|
# Create the option parse and add --verbose support.
|
|
|
|
|
parser = optparse.OptionParser()
|
|
|
|
|
parser.add_option(
|
|
|
|
|
'-v', '--verbose', action='count', default=0,
|
|
|
|
|
help='Use 2 times for more debugging info')
|
|
|
|
|
old_parser_args = parser.parse_args
|
|
|
|
|
def Parse(args):
|
|
|
|
|
options, args = old_parser_args(args)
|
|
|
|
|
if options.verbose >= 2:
|
|
|
|
|
logging.basicConfig(level=logging.DEBUG)
|
|
|
|
|
elif options.verbose:
|
|
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
|
|
|
else:
|
|
|
|
|
logging.basicConfig(level=logging.WARNING)
|
|
|
|
|
return options, args
|
|
|
|
|
parser.parse_args = Parse
|
|
|
|
|
|
|
|
|
|
if argv:
|
|
|
|
|
command = Command(argv[0])
|
|
|
|
|
if command:
|
|
|
|
|