Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(160)

Side by Side Diff: git_cl.py

Issue 1191473002: [depot_tools] New "git cl upload" flag to traverse dependent branches and re-upload them (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@master
Patch Set: Fix lint Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | tests/git_cl_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
11 from multiprocessing.pool import ThreadPool 11 from multiprocessing.pool import ThreadPool
12 import base64 12 import base64
13 import collections
13 import glob 14 import glob
14 import httplib 15 import httplib
15 import json 16 import json
16 import logging 17 import logging
17 import optparse 18 import optparse
18 import os 19 import os
19 import Queue 20 import Queue
20 import re 21 import re
21 import stat 22 import stat
22 import sys 23 import sys
(...skipping 1486 matching lines...) Expand 10 before | Expand all | Expand 10 after
1509 else len(branches_to_fetch)) 1510 else len(branches_to_fetch))
1510 for x in pool.imap_unordered(fetch, branches_to_fetch): 1511 for x in pool.imap_unordered(fetch, branches_to_fetch):
1511 yield x 1512 yield x
1512 else: 1513 else:
1513 # Do not use GetApprovingReviewers(), since it requires an HTTP request. 1514 # Do not use GetApprovingReviewers(), since it requires an HTTP request.
1514 for b in branches: 1515 for b in branches:
1515 cl = Changelist(branchref=b, auth_config=auth_config) 1516 cl = Changelist(branchref=b, auth_config=auth_config)
1516 url = cl.GetIssueURL() 1517 url = cl.GetIssueURL()
1517 yield (b, url, 'waiting' if url else 'error') 1518 yield (b, url, 'waiting' if url else 'error')
1518 1519
1520
1521 def upload_branch_deps(cl, args):
1522 """Uploads CLs of local branches that are dependents of the current branch.
1523
1524 If the local branch dependency tree looks like:
1525 test1 -> test2.1 -> test3.1
1526 -> test3.2
1527 -> test2.2 -> test3.3
1528
1529 and you run "git cl upload --dependencies" from test1 then "git cl upload" is
1530 run on the dependent branches in this order:
1531 test2.1, test3.1, test3.2, test2.2, test3.3
1532
1533 Note: This function does not rebase your local dependent branches. Use it when
1534 you make a change to the parent branch that will not conflict with its
1535 dependent branches, and you would like their dependencies updated in
1536 Rietveld.
1537 """
1538 if git_common.is_dirty_git_tree('upload-branch-deps'):
1539 return 1
1540
1541 root_branch = cl.GetBranch()
1542 if root_branch is None:
1543 DieWithError('Can\'t find dependent branches from detached HEAD state. '
1544 'Get on a branch!')
1545 if not cl.GetIssue() or not cl.GetPatchset():
1546 DieWithError('Current branch does not have an uploaded CL. We cannot set '
1547 'patchset dependencies without an uploaded CL.')
1548
1549 branches = RunGit(['for-each-ref',
1550 '--format=%(refname:short) %(upstream:short)',
1551 'refs/heads'])
1552 if not branches:
1553 print('No local branches found.')
1554 return 0
1555
1556 # Create a dictionary of all local branches to the branches that are dependent
1557 # on it.
1558 tracked_to_dependents = collections.defaultdict(list)
1559 for b in branches.splitlines():
1560 tokens = b.split()
1561 if len(tokens) == 2:
1562 branch_name, tracked = tokens
1563 tracked_to_dependents[tracked].append(branch_name)
1564
1565 print
1566 print 'The dependent local branches of %s are:' % root_branch
1567 dependents = []
1568 def traverse_dependents_preorder(branch, padding=''):
1569 dependents_to_process = tracked_to_dependents.get(branch, [])
1570 padding += ' '
1571 for dependent in dependents_to_process:
1572 print '%s%s' % (padding, dependent)
1573 dependents.append(dependent)
1574 traverse_dependents_preorder(dependent, padding)
1575 traverse_dependents_preorder(root_branch)
1576 print
1577
1578 if not dependents:
1579 print 'There are no dependent local branches for %s' % root_branch
1580 return 0
1581
1582 print ('This command will checkout all dependent branches and run '
1583 '"git cl upload".')
1584 ask_for_data('[Press enter to continue or ctrl-C to quit]')
1585
1586 # Add a default patchset title to all upload calls.
1587 args.extend(['-t', 'Updated patchset dependency'])
1588 # Record all dependents that failed to upload.
1589 failures = {}
1590 # Go through all dependents, checkout the branch and upload.
1591 try:
1592 for dependent_branch in dependents:
1593 print
1594 print '--------------------------------------'
1595 print 'Running "git cl upload" from %s:' % dependent_branch
1596 RunGit(['checkout', '-q', dependent_branch])
1597 print
1598 try:
1599 if CMDupload(OptionParser(), args) != 0:
1600 print 'Upload failed for %s!' % dependent_branch
1601 failures[dependent_branch] = 1
1602 except: # pylint: disable=W0702
1603 failures[dependent_branch] = 1
1604 print
1605 finally:
1606 # Swap back to the original root branch.
1607 RunGit(['checkout', '-q', root_branch])
1608
1609 print
1610 print 'Upload complete for dependent branches!'
1611 for dependent_branch in dependents:
1612 upload_status = 'failed' if failures.get(dependent_branch) else 'succeeded'
1613 print ' %s : %s' % (dependent_branch, upload_status)
1614 print
1615
1616 return 0
1617
1618
1519 def CMDstatus(parser, args): 1619 def CMDstatus(parser, args):
1520 """Show status of changelists. 1620 """Show status of changelists.
1521 1621
1522 Colors are used to tell the state of the CL unless --fast is used: 1622 Colors are used to tell the state of the CL unless --fast is used:
1523 - Red not sent for review or broken 1623 - Red not sent for review or broken
1524 - Blue waiting for review 1624 - Blue waiting for review
1525 - Yellow waiting for you to reply to review 1625 - Yellow waiting for you to reply to review
1526 - Green LGTM'ed 1626 - Green LGTM'ed
1527 - Magenta in the commit queue 1627 - Magenta in the commit queue
1528 - Cyan was committed, branch can be deleted 1628 - Cyan was committed, branch can be deleted
(...skipping 661 matching lines...) Expand 10 before | Expand all | Expand 10 after
2190 'Default: remote branch head, or master') 2290 'Default: remote branch head, or master')
2191 parser.add_option('--squash', action='store_true', 2291 parser.add_option('--squash', action='store_true',
2192 help='Squash multiple commits into one (Gerrit only)') 2292 help='Squash multiple commits into one (Gerrit only)')
2193 parser.add_option('--email', default=None, 2293 parser.add_option('--email', default=None,
2194 help='email address to use to connect to Rietveld') 2294 help='email address to use to connect to Rietveld')
2195 parser.add_option('--tbr-owners', dest='tbr_owners', action='store_true', 2295 parser.add_option('--tbr-owners', dest='tbr_owners', action='store_true',
2196 help='add a set of OWNERS to TBR') 2296 help='add a set of OWNERS to TBR')
2197 parser.add_option('--cq-dry-run', dest='cq_dry_run', action='store_true', 2297 parser.add_option('--cq-dry-run', dest='cq_dry_run', action='store_true',
2198 help='Send the patchset to do a CQ dry run right after ' 2298 help='Send the patchset to do a CQ dry run right after '
2199 'upload.') 2299 'upload.')
2300 parser.add_option('--dependencies', action='store_true',
2301 help='Uploads CLs of all the local branches that depend on '
2302 'the current branch')
2200 2303
2304 orig_args = args
2201 add_git_similarity(parser) 2305 add_git_similarity(parser)
2202 auth.add_auth_options(parser) 2306 auth.add_auth_options(parser)
2203 (options, args) = parser.parse_args(args) 2307 (options, args) = parser.parse_args(args)
2204 auth_config = auth.extract_auth_config_from_options(options) 2308 auth_config = auth.extract_auth_config_from_options(options)
2205 2309
2206 if git_common.is_dirty_git_tree('upload'): 2310 if git_common.is_dirty_git_tree('upload'):
2207 return 1 2311 return 1
2208 2312
2209 options.reviewers = cleanup_list(options.reviewers) 2313 options.reviewers = cleanup_list(options.reviewers)
2210 options.cc = cleanup_list(options.cc) 2314 options.cc = cleanup_list(options.cc)
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
2275 RunGit(['rev-parse', 'HEAD']).strip()) 2379 RunGit(['rev-parse', 'HEAD']).strip())
2276 # Run post upload hooks, if specified. 2380 # Run post upload hooks, if specified.
2277 if settings.GetRunPostUploadHook(): 2381 if settings.GetRunPostUploadHook():
2278 presubmit_support.DoPostUploadExecuter( 2382 presubmit_support.DoPostUploadExecuter(
2279 change, 2383 change,
2280 cl, 2384 cl,
2281 settings.GetRoot(), 2385 settings.GetRoot(),
2282 options.verbose, 2386 options.verbose,
2283 sys.stdout) 2387 sys.stdout)
2284 2388
2389 # Upload all dependencies if specified.
2390 if options.dependencies:
2391 print
2392 print '--dependencies has been specified.'
2393 print 'All dependent local branches will be re-uploaded.'
2394 print
2395 # Remove the dependencies flag from args so that we do not end up in a
2396 # loop.
2397 orig_args.remove('--dependencies')
2398 upload_branch_deps(cl, orig_args)
2285 return ret 2399 return ret
2286 2400
2287 2401
2288 def IsSubmoduleMergeCommit(ref): 2402 def IsSubmoduleMergeCommit(ref):
2289 # When submodules are added to the repo, we expect there to be a single 2403 # When submodules are added to the repo, we expect there to be a single
2290 # non-git-svn merge commit at remote HEAD with a signature comment. 2404 # non-git-svn merge commit at remote HEAD with a signature comment.
2291 pattern = '^SVN changes up to revision [0-9]*$' 2405 pattern = '^SVN changes up to revision [0-9]*$'
2292 cmd = ['rev-list', '--merges', '--grep=%s' % pattern, '%s^!' % ref] 2406 cmd = ['rev-list', '--merges', '--grep=%s' % pattern, '%s^!' % ref]
2293 return RunGit(cmd) != '' 2407 return RunGit(cmd) != ''
2294 2408
(...skipping 1121 matching lines...) Expand 10 before | Expand all | Expand 10 after
3416 if __name__ == '__main__': 3530 if __name__ == '__main__':
3417 # These affect sys.stdout so do it outside of main() to simplify mocks in 3531 # These affect sys.stdout so do it outside of main() to simplify mocks in
3418 # unit testing. 3532 # unit testing.
3419 fix_encoding.fix_encoding() 3533 fix_encoding.fix_encoding()
3420 colorama.init() 3534 colorama.init()
3421 try: 3535 try:
3422 sys.exit(main(sys.argv[1:])) 3536 sys.exit(main(sys.argv[1:]))
3423 except KeyboardInterrupt: 3537 except KeyboardInterrupt:
3424 sys.stderr.write('interrupted\n') 3538 sys.stderr.write('interrupted\n')
3425 sys.exit(1) 3539 sys.exit(1)
OLDNEW
« no previous file with comments | « no previous file | tests/git_cl_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698