| Index: git_cl.py
|
| diff --git a/git_cl.py b/git_cl.py
|
| index 50ba3432eb230dc484f2036e8a00bb641820e6f2..288e281b1170aa16220eb5fe6527f638dc1d6b5d 100755
|
| --- a/git_cl.py
|
| +++ b/git_cl.py
|
| @@ -10,6 +10,7 @@
|
| from distutils.version import LooseVersion
|
| from multiprocessing.pool import ThreadPool
|
| import base64
|
| +import collections
|
| import glob
|
| import httplib
|
| import json
|
| @@ -1516,6 +1517,105 @@ def get_cl_statuses(
|
| url = cl.GetIssueURL()
|
| yield (b, url, 'waiting' if url else 'error')
|
|
|
| +
|
| +def upload_branch_deps(cl, args):
|
| + """Uploads CLs of local branches that are dependents of the current branch.
|
| +
|
| + If the local branch dependency tree looks like:
|
| + test1 -> test2.1 -> test3.1
|
| + -> test3.2
|
| + -> test2.2 -> test3.3
|
| +
|
| + and you run "git cl upload --dependencies" from test1 then "git cl upload" is
|
| + run on the dependent branches in this order:
|
| + test2.1, test3.1, test3.2, test2.2, test3.3
|
| +
|
| + Note: This function does not rebase your local dependent branches. Use it when
|
| + you make a change to the parent branch that will not conflict with its
|
| + dependent branches, and you would like their dependencies updated in
|
| + Rietveld.
|
| + """
|
| + if git_common.is_dirty_git_tree('upload-branch-deps'):
|
| + return 1
|
| +
|
| + root_branch = cl.GetBranch()
|
| + if root_branch is None:
|
| + DieWithError('Can\'t find dependent branches from detached HEAD state. '
|
| + 'Get on a branch!')
|
| + if not cl.GetIssue() or not cl.GetPatchset():
|
| + DieWithError('Current branch does not have an uploaded CL. We cannot set '
|
| + 'patchset dependencies without an uploaded CL.')
|
| +
|
| + branches = RunGit(['for-each-ref',
|
| + '--format=%(refname:short) %(upstream:short)',
|
| + 'refs/heads'])
|
| + if not branches:
|
| + print('No local branches found.')
|
| + return 0
|
| +
|
| + # Create a dictionary of all local branches to the branches that are dependent
|
| + # on it.
|
| + tracked_to_dependents = collections.defaultdict(list)
|
| + for b in branches.splitlines():
|
| + tokens = b.split()
|
| + if len(tokens) == 2:
|
| + branch_name, tracked = tokens
|
| + tracked_to_dependents[tracked].append(branch_name)
|
| +
|
| + print
|
| + print 'The dependent local branches of %s are:' % root_branch
|
| + dependents = []
|
| + def traverse_dependents_preorder(branch, padding=''):
|
| + dependents_to_process = tracked_to_dependents.get(branch, [])
|
| + padding += ' '
|
| + for dependent in dependents_to_process:
|
| + print '%s%s' % (padding, dependent)
|
| + dependents.append(dependent)
|
| + traverse_dependents_preorder(dependent, padding)
|
| + traverse_dependents_preorder(root_branch)
|
| + print
|
| +
|
| + if not dependents:
|
| + print 'There are no dependent local branches for %s' % root_branch
|
| + return 0
|
| +
|
| + print ('This command will checkout all dependent branches and run '
|
| + '"git cl upload".')
|
| + ask_for_data('[Press enter to continue or ctrl-C to quit]')
|
| +
|
| + # Add a default patchset title to all upload calls.
|
| + args.extend(['-t', 'Updated patchset dependency'])
|
| + # Record all dependents that failed to upload.
|
| + failures = {}
|
| + # Go through all dependents, checkout the branch and upload.
|
| + try:
|
| + for dependent_branch in dependents:
|
| + print
|
| + print '--------------------------------------'
|
| + print 'Running "git cl upload" from %s:' % dependent_branch
|
| + RunGit(['checkout', '-q', dependent_branch])
|
| + print
|
| + try:
|
| + if CMDupload(OptionParser(), args) != 0:
|
| + print 'Upload failed for %s!' % dependent_branch
|
| + failures[dependent_branch] = 1
|
| + except: # pylint: disable=W0702
|
| + failures[dependent_branch] = 1
|
| + print
|
| + finally:
|
| + # Swap back to the original root branch.
|
| + RunGit(['checkout', '-q', root_branch])
|
| +
|
| + print
|
| + print 'Upload complete for dependent branches!'
|
| + for dependent_branch in dependents:
|
| + upload_status = 'failed' if failures.get(dependent_branch) else 'succeeded'
|
| + print ' %s : %s' % (dependent_branch, upload_status)
|
| + print
|
| +
|
| + return 0
|
| +
|
| +
|
| def CMDstatus(parser, args):
|
| """Show status of changelists.
|
|
|
| @@ -2197,7 +2297,11 @@ def CMDupload(parser, args):
|
| parser.add_option('--cq-dry-run', dest='cq_dry_run', action='store_true',
|
| help='Send the patchset to do a CQ dry run right after '
|
| 'upload.')
|
| + parser.add_option('--dependencies', action='store_true',
|
| + help='Uploads CLs of all the local branches that depend on '
|
| + 'the current branch')
|
|
|
| + orig_args = args
|
| add_git_similarity(parser)
|
| auth.add_auth_options(parser)
|
| (options, args) = parser.parse_args(args)
|
| @@ -2282,6 +2386,16 @@ def CMDupload(parser, args):
|
| options.verbose,
|
| sys.stdout)
|
|
|
| + # Upload all dependencies if specified.
|
| + if options.dependencies:
|
| + print
|
| + print '--dependencies has been specified.'
|
| + print 'All dependent local branches will be re-uploaded.'
|
| + print
|
| + # Remove the dependencies flag from args so that we do not end up in a
|
| + # loop.
|
| + orig_args.remove('--dependencies')
|
| + upload_branch_deps(cl, orig_args)
|
| return ret
|
|
|
|
|
|
|