Index: git_cl.py |
diff --git a/git_cl.py b/git_cl.py |
index d50b7a37dfe8c596f3b2b6c5c534b086daa7a15a..49deade9b4fb3f6d97acc93bff7de8e44f2ee6d0 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 |
@@ -1505,6 +1506,102 @@ def get_cl_statuses( |
url = c.GetIssueURL() |
yield (b, url, Fore.BLUE if url else Fore.WHITE) |
+ |
+def CMDupload_branch_deps(parser, 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 this command 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 command 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. |
+ """ |
+ auth.add_auth_options(parser) |
+ (options, args) = parser.parse_args(args) |
+ auth_config = auth.extract_auth_config_from_options(options) |
+ |
+ if git_common.is_dirty_git_tree('upload-branch-deps'): |
+ return 1 |
+ |
+ cl = Changelist(auth_config=auth_config) |
+ 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 |
agable
2015/06/17 18:13:34
Seems like you should be able to reuse code from g
rmistry
2015/06/18 17:52:40
My comment for this is similar to my earlier comme
|
+ # 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 '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 ('This command will checkout all dependent branches and run ' |
+ '"git cl upload".') |
+ ask_for_data('[Press enter to continue or ctrl-C to quit]') |
+ |
+ if not dependents: |
agable
2015/06/17 18:13:34
Do this before requiring user input above.
rmistry
2015/06/18 17:52:39
Done.
|
+ print 'There are no dependent local branches for %s' % root_branch |
+ return 0 |
+ |
+ # Add a default patchset title to all upload calls. |
+ args.extend(['-t', 'Updated patchset dependency with upload-branch-deps']) |
+ # Go through all dependents, checkout the branch and upload. |
+ try: |
+ for dependent_branch in dependents: |
+ print '--------------------------------------' |
+ print 'Running "git cl upload" from %s:' % dependent_branch |
+ RunGit(['checkout', '-q', dependent_branch]) |
+ if CMDupload(OptionParser(), args) != 0: |
+ print 'Upload failed for %s!' % dependent_branch |
+ return 1 |
+ finally: |
+ # Swap back to the original root branch. |
+ RunGit(['checkout', '-q', root_branch]) |
+ |
+ print 'All dependent branches %s have been updated!' % dependents |
+ |
+ return 0 |
+ |
+ |
def CMDstatus(parser, args): |
"""Show status of changelists. |