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

Side by Side Diff: git_cl.py

Issue 543463002: Add a --tbr-owners option to git cl upload (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: Created 6 years, 3 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | 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
(...skipping 18 matching lines...) Expand all
29 pass 29 pass
30 30
31 31
32 from third_party import colorama 32 from third_party import colorama
33 from third_party import upload 33 from third_party import upload
34 import breakpad # pylint: disable=W0611 34 import breakpad # pylint: disable=W0611
35 import clang_format 35 import clang_format
36 import fix_encoding 36 import fix_encoding
37 import gclient_utils 37 import gclient_utils
38 import git_common 38 import git_common
39 import owners
39 import owners_finder 40 import owners_finder
40 import presubmit_support 41 import presubmit_support
41 import rietveld 42 import rietveld
42 import scm 43 import scm
43 import subcommand 44 import subcommand
44 import subprocess2 45 import subprocess2
45 import watchlists 46 import watchlists
46 47
47 __version__ = '1.0' 48 __version__ = '1.0'
48 49
(...skipping 903 matching lines...) Expand 10 before | Expand all | Expand 10 after
952 if isinstance(desc, basestring): 953 if isinstance(desc, basestring):
953 lines = desc.splitlines() 954 lines = desc.splitlines()
954 else: 955 else:
955 lines = [line.rstrip() for line in desc] 956 lines = [line.rstrip() for line in desc]
956 while lines and not lines[0]: 957 while lines and not lines[0]:
957 lines.pop(0) 958 lines.pop(0)
958 while lines and not lines[-1]: 959 while lines and not lines[-1]:
959 lines.pop(-1) 960 lines.pop(-1)
960 self._description_lines = lines 961 self._description_lines = lines
961 962
962 def update_reviewers(self, reviewers): 963 def update_reviewers(self, reviewers, add_owners_tbr=False, change=None):
963 """Rewrites the R=/TBR= line(s) as a single line each.""" 964 """Rewrites the R=/TBR= line(s) as a single line each."""
964 assert isinstance(reviewers, list), reviewers 965 assert isinstance(reviewers, list), reviewers
965 if not reviewers: 966 if not reviewers and not add_owners_tbr:
966 return 967 return
967 reviewers = reviewers[:] 968 reviewers = reviewers[:]
968 969
969 # Get the set of R= and TBR= lines and remove them from the desciption. 970 # Get the set of R= and TBR= lines and remove them from the desciption.
970 regexp = re.compile(self.R_LINE) 971 regexp = re.compile(self.R_LINE)
971 matches = [regexp.match(line) for line in self._description_lines] 972 matches = [regexp.match(line) for line in self._description_lines]
972 new_desc = [l for i, l in enumerate(self._description_lines) 973 new_desc = [l for i, l in enumerate(self._description_lines)
973 if not matches[i]] 974 if not matches[i]]
974 self.set_description(new_desc) 975 self.set_description(new_desc)
975 976
976 # Construct new unified R= and TBR= lines. 977 # Construct new unified R= and TBR= lines.
977 r_names = [] 978 r_names = []
978 tbr_names = [] 979 tbr_names = []
979 for match in matches: 980 for match in matches:
980 if not match: 981 if not match:
981 continue 982 continue
982 people = cleanup_list([match.group(2).strip()]) 983 people = cleanup_list([match.group(2).strip()])
983 if match.group(1) == 'TBR': 984 if match.group(1) == 'TBR':
984 tbr_names.extend(people) 985 tbr_names.extend(people)
985 else: 986 else:
986 r_names.extend(people) 987 r_names.extend(people)
987 for name in r_names: 988 for name in r_names:
988 if name not in reviewers: 989 if name not in reviewers:
989 reviewers.append(name) 990 reviewers.append(name)
991 if add_owners_tbr:
992 owners_db = owners.Database(change.RepositoryRoot(),
993 fopen=file, os_path=os.path, glob=glob.glob)
994 all_reviewers = set(tbr_names + reviewers)
995 missing_files = owners_db.files_not_covered_by(change.LocalPaths(),
996 all_reviewers)
997 tbr_names.extend(owners_db.reviewers_for(missing_files,
998 change.author_email))
990 new_r_line = 'R=' + ', '.join(reviewers) if reviewers else None 999 new_r_line = 'R=' + ', '.join(reviewers) if reviewers else None
991 new_tbr_line = 'TBR=' + ', '.join(tbr_names) if tbr_names else None 1000 new_tbr_line = 'TBR=' + ', '.join(tbr_names) if tbr_names else None
992 1001
993 # Put the new lines in the description where the old first R= line was. 1002 # Put the new lines in the description where the old first R= line was.
994 line_loc = next((i for i, match in enumerate(matches) if match), -1) 1003 line_loc = next((i for i, match in enumerate(matches) if match), -1)
995 if 0 <= line_loc < len(self._description_lines): 1004 if 0 <= line_loc < len(self._description_lines):
996 if new_tbr_line: 1005 if new_tbr_line:
997 self._description_lines.insert(line_loc, new_tbr_line) 1006 self._description_lines.insert(line_loc, new_tbr_line)
998 if new_r_line: 1007 if new_r_line:
999 self._description_lines.insert(line_loc, new_r_line) 1008 self._description_lines.insert(line_loc, new_r_line)
(...skipping 518 matching lines...) Expand 10 before | Expand all | Expand 10 after
1518 log_desc = options.message or CreateDescriptionFromLog(args) 1527 log_desc = options.message or CreateDescriptionFromLog(args)
1519 git_command = ['commit', '--amend', '-m', log_desc] 1528 git_command = ['commit', '--amend', '-m', log_desc]
1520 RunGit(git_command) 1529 RunGit(git_command)
1521 new_log_desc = CreateDescriptionFromLog(args) 1530 new_log_desc = CreateDescriptionFromLog(args)
1522 if CHANGE_ID in new_log_desc: 1531 if CHANGE_ID in new_log_desc:
1523 print 'git-cl: Added Change-Id to commit message.' 1532 print 'git-cl: Added Change-Id to commit message.'
1524 else: 1533 else:
1525 print >> sys.stderr, 'ERROR: Gerrit commit-msg hook not available.' 1534 print >> sys.stderr, 'ERROR: Gerrit commit-msg hook not available.'
1526 1535
1527 1536
1528 def GerritUpload(options, args, cl): 1537 def GerritUpload(options, args, cl, change):
1529 """upload the current branch to gerrit.""" 1538 """upload the current branch to gerrit."""
1530 # We assume the remote called "origin" is the one we want. 1539 # We assume the remote called "origin" is the one we want.
1531 # It is probably not worthwhile to support different workflows. 1540 # It is probably not worthwhile to support different workflows.
1532 remote = 'origin' 1541 remote = 'origin'
1533 branch = 'master' 1542 branch = 'master'
1534 if options.target_branch: 1543 if options.target_branch:
1535 branch = options.target_branch 1544 branch = options.target_branch
1536 1545
1537 change_desc = ChangeDescription( 1546 change_desc = ChangeDescription(
1538 options.message or CreateDescriptionFromLog(args)) 1547 options.message or CreateDescriptionFromLog(args))
1539 if not change_desc.description: 1548 if not change_desc.description:
1540 print "Description is empty; aborting." 1549 print "Description is empty; aborting."
1541 return 1 1550 return 1
1542 if CHANGE_ID not in change_desc.description: 1551 if CHANGE_ID not in change_desc.description:
1543 AddChangeIdToCommitMessage(options, args) 1552 AddChangeIdToCommitMessage(options, args)
1544 1553
1545 commits = RunGit(['rev-list', '%s/%s..' % (remote, branch)]).splitlines() 1554 commits = RunGit(['rev-list', '%s/%s..' % (remote, branch)]).splitlines()
1546 if len(commits) > 1: 1555 if len(commits) > 1:
1547 print('WARNING: This will upload %d commits. Run the following command ' 1556 print('WARNING: This will upload %d commits. Run the following command '
1548 'to see which commits will be uploaded: ' % len(commits)) 1557 'to see which commits will be uploaded: ' % len(commits))
1549 print('git log %s/%s..' % (remote, branch)) 1558 print('git log %s/%s..' % (remote, branch))
1550 print('You can also use `git squash-branch` to squash these into a single' 1559 print('You can also use `git squash-branch` to squash these into a single'
1551 'commit.') 1560 'commit.')
1552 ask_for_data('About to upload; enter to confirm.') 1561 ask_for_data('About to upload; enter to confirm.')
1553 1562
1554 if options.reviewers: 1563 if options.reviewers or options.tbr_owners:
1555 change_desc.update_reviewers(options.reviewers) 1564 change_desc.update_reviewers(options.reviewers, options.tbr_owners, change)
1556 1565
1557 receive_options = [] 1566 receive_options = []
1558 cc = cl.GetCCList().split(',') 1567 cc = cl.GetCCList().split(',')
1559 if options.cc: 1568 if options.cc:
1560 cc.extend(options.cc) 1569 cc.extend(options.cc)
1561 cc = filter(None, cc) 1570 cc = filter(None, cc)
1562 if cc: 1571 if cc:
1563 receive_options += ['--cc=' + email for email in cc] 1572 receive_options += ['--cc=' + email for email in cc]
1564 if change_desc.get_reviewers(): 1573 if change_desc.get_reviewers():
1565 receive_options.extend( 1574 receive_options.extend(
1566 '--reviewer=' + email for email in change_desc.get_reviewers()) 1575 '--reviewer=' + email for email in change_desc.get_reviewers())
1567 1576
1568 git_command = ['push'] 1577 git_command = ['push']
1569 if receive_options: 1578 if receive_options:
1570 git_command.append('--receive-pack=git receive-pack %s' % 1579 git_command.append('--receive-pack=git receive-pack %s' %
1571 ' '.join(receive_options)) 1580 ' '.join(receive_options))
1572 git_command += [remote, 'HEAD:refs/for/' + branch] 1581 git_command += [remote, 'HEAD:refs/for/' + branch]
1573 RunGit(git_command) 1582 RunGit(git_command)
1574 # TODO(ukai): parse Change-Id: and set issue number? 1583 # TODO(ukai): parse Change-Id: and set issue number?
1575 return 0 1584 return 0
1576 1585
1577 1586
1578 def RietveldUpload(options, args, cl): 1587 def RietveldUpload(options, args, cl, change):
1579 """upload the patch to rietveld.""" 1588 """upload the patch to rietveld."""
1580 upload_args = ['--assume_yes'] # Don't ask about untracked files. 1589 upload_args = ['--assume_yes'] # Don't ask about untracked files.
1581 upload_args.extend(['--server', cl.GetRietveldServer()]) 1590 upload_args.extend(['--server', cl.GetRietveldServer()])
1582 if options.emulate_svn_auto_props: 1591 if options.emulate_svn_auto_props:
1583 upload_args.append('--emulate_svn_auto_props') 1592 upload_args.append('--emulate_svn_auto_props')
1584 1593
1585 change_desc = None 1594 change_desc = None
1586 1595
1587 if options.email is not None: 1596 if options.email is not None:
1588 upload_args.extend(['--email', options.email]) 1597 upload_args.extend(['--email', options.email])
1589 1598
1590 if cl.GetIssue(): 1599 if cl.GetIssue():
1591 if options.title: 1600 if options.title:
1592 upload_args.extend(['--title', options.title]) 1601 upload_args.extend(['--title', options.title])
1593 if options.message: 1602 if options.message:
1594 upload_args.extend(['--message', options.message]) 1603 upload_args.extend(['--message', options.message])
1595 upload_args.extend(['--issue', str(cl.GetIssue())]) 1604 upload_args.extend(['--issue', str(cl.GetIssue())])
1596 print ("This branch is associated with issue %s. " 1605 print ("This branch is associated with issue %s. "
1597 "Adding patch to that issue." % cl.GetIssue()) 1606 "Adding patch to that issue." % cl.GetIssue())
1598 else: 1607 else:
1599 if options.title: 1608 if options.title:
1600 upload_args.extend(['--title', options.title]) 1609 upload_args.extend(['--title', options.title])
1601 message = options.title or options.message or CreateDescriptionFromLog(args) 1610 message = options.title or options.message or CreateDescriptionFromLog(args)
1602 change_desc = ChangeDescription(message) 1611 change_desc = ChangeDescription(message)
1603 if options.reviewers: 1612 if options.reviewers or options.tbr_owners:
1604 change_desc.update_reviewers(options.reviewers) 1613 change_desc.update_reviewers(options.reviewers,
1614 options.tbr_owners,
1615 change)
1605 if not options.force: 1616 if not options.force:
1606 change_desc.prompt() 1617 change_desc.prompt()
1607 1618
1608 if not change_desc.description: 1619 if not change_desc.description:
1609 print "Description is empty; aborting." 1620 print "Description is empty; aborting."
1610 return 1 1621 return 1
1611 1622
1612 upload_args.extend(['--message', change_desc.description]) 1623 upload_args.extend(['--message', change_desc.description])
1613 if change_desc.get_reviewers(): 1624 if change_desc.get_reviewers():
1614 upload_args.append('--reviewers=' + ','.join(change_desc.get_reviewers())) 1625 upload_args.append('--reviewers=' + ','.join(change_desc.get_reviewers()))
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
1728 parser.add_option('-c', '--use-commit-queue', action='store_true', 1739 parser.add_option('-c', '--use-commit-queue', action='store_true',
1729 help='tell the commit queue to commit this patchset') 1740 help='tell the commit queue to commit this patchset')
1730 parser.add_option('--private', action='store_true', 1741 parser.add_option('--private', action='store_true',
1731 help='set the review private (rietveld only)') 1742 help='set the review private (rietveld only)')
1732 parser.add_option('--target_branch', 1743 parser.add_option('--target_branch',
1733 '--target-branch', 1744 '--target-branch',
1734 help='When uploading to gerrit, remote branch to ' 1745 help='When uploading to gerrit, remote branch to '
1735 'use for CL. Default: master') 1746 'use for CL. Default: master')
1736 parser.add_option('--email', default=None, 1747 parser.add_option('--email', default=None,
1737 help='email address to use to connect to Rietveld') 1748 help='email address to use to connect to Rietveld')
1749 parser.add_option('--tbr-owners', dest='tbr_owners', action='store_true',
1750 help='add a set of OWNERS to TBR')
1738 1751
1739 add_git_similarity(parser) 1752 add_git_similarity(parser)
1740 (options, args) = parser.parse_args(args) 1753 (options, args) = parser.parse_args(args)
1741 1754
1742 if options.target_branch and not settings.GetIsGerrit(): 1755 if options.target_branch and not settings.GetIsGerrit():
1743 parser.error('Use --target_branch for non gerrit repository.') 1756 parser.error('Use --target_branch for non gerrit repository.')
1744 1757
1745 if is_dirty_git_tree('upload'): 1758 if is_dirty_git_tree('upload'):
1746 return 1 1759 return 1
1747 1760
(...skipping 10 matching lines...) Expand all
1758 args = [base_branch, 'HEAD'] 1771 args = [base_branch, 'HEAD']
1759 1772
1760 # Apply watchlists on upload. 1773 # Apply watchlists on upload.
1761 change = cl.GetChange(base_branch, None) 1774 change = cl.GetChange(base_branch, None)
1762 watchlist = watchlists.Watchlists(change.RepositoryRoot()) 1775 watchlist = watchlists.Watchlists(change.RepositoryRoot())
1763 files = [f.LocalPath() for f in change.AffectedFiles()] 1776 files = [f.LocalPath() for f in change.AffectedFiles()]
1764 if not options.bypass_watchlists: 1777 if not options.bypass_watchlists:
1765 cl.SetWatchers(watchlist.GetWatchersForPaths(files)) 1778 cl.SetWatchers(watchlist.GetWatchersForPaths(files))
1766 1779
1767 if not options.bypass_hooks: 1780 if not options.bypass_hooks:
1768 if options.reviewers: 1781 if options.reviewers or options.tbr_owners:
1769 # Set the reviewer list now so that presubmit checks can access it. 1782 # Set the reviewer list now so that presubmit checks can access it.
1770 change_description = ChangeDescription(change.FullDescriptionText()) 1783 change_description = ChangeDescription(change.FullDescriptionText())
1771 change_description.update_reviewers(options.reviewers) 1784 change_description.update_reviewers(options.reviewers,
1785 options.tbr_owners,
1786 change)
1772 change.SetDescriptionText(change_description.description) 1787 change.SetDescriptionText(change_description.description)
1773 hook_results = cl.RunHook(committing=False, 1788 hook_results = cl.RunHook(committing=False,
1774 may_prompt=not options.force, 1789 may_prompt=not options.force,
1775 verbose=options.verbose, 1790 verbose=options.verbose,
1776 change=change) 1791 change=change)
1777 if not hook_results.should_continue(): 1792 if not hook_results.should_continue():
1778 return 1 1793 return 1
1779 if not options.reviewers and hook_results.reviewers: 1794 if not options.reviewers and hook_results.reviewers:
1780 options.reviewers = hook_results.reviewers.split(',') 1795 options.reviewers = hook_results.reviewers.split(',')
1781 1796
1782 if cl.GetIssue(): 1797 if cl.GetIssue():
1783 latest_patchset = cl.GetMostRecentPatchset() 1798 latest_patchset = cl.GetMostRecentPatchset()
1784 local_patchset = cl.GetPatchset() 1799 local_patchset = cl.GetPatchset()
1785 if latest_patchset and local_patchset and local_patchset != latest_patchset: 1800 if latest_patchset and local_patchset and local_patchset != latest_patchset:
1786 print ('The last upload made from this repository was patchset #%d but ' 1801 print ('The last upload made from this repository was patchset #%d but '
1787 'the most recent patchset on the server is #%d.' 1802 'the most recent patchset on the server is #%d.'
1788 % (local_patchset, latest_patchset)) 1803 % (local_patchset, latest_patchset))
1789 print ('Uploading will still work, but if you\'ve uploaded to this issue ' 1804 print ('Uploading will still work, but if you\'ve uploaded to this issue '
1790 'from another machine or branch the patch you\'re uploading now ' 1805 'from another machine or branch the patch you\'re uploading now '
1791 'might not include those changes.') 1806 'might not include those changes.')
1792 ask_for_data('About to upload; enter to confirm.') 1807 ask_for_data('About to upload; enter to confirm.')
1793 1808
1794 print_stats(options.similarity, options.find_copies, args) 1809 print_stats(options.similarity, options.find_copies, args)
1795 if settings.GetIsGerrit(): 1810 if settings.GetIsGerrit():
1796 return GerritUpload(options, args, cl) 1811 return GerritUpload(options, args, cl, change)
1797 ret = RietveldUpload(options, args, cl) 1812 ret = RietveldUpload(options, args, cl, change)
1798 if not ret: 1813 if not ret:
1799 git_set_branch_value('last-upload-hash', 1814 git_set_branch_value('last-upload-hash',
1800 RunGit(['rev-parse', 'HEAD']).strip()) 1815 RunGit(['rev-parse', 'HEAD']).strip())
1801 1816
1802 return ret 1817 return ret
1803 1818
1804 1819
1805 def IsSubmoduleMergeCommit(ref): 1820 def IsSubmoduleMergeCommit(ref):
1806 # When submodules are added to the repo, we expect there to be a single 1821 # When submodules are added to the repo, we expect there to be a single
1807 # non-git-svn merge commit at remote HEAD with a signature comment. 1822 # non-git-svn merge commit at remote HEAD with a signature comment.
(...skipping 989 matching lines...) Expand 10 before | Expand all | Expand 10 after
2797 ('AppEngine is misbehaving and returned HTTP %d, again. Keep faith ' 2812 ('AppEngine is misbehaving and returned HTTP %d, again. Keep faith '
2798 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) 2813 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e)))
2799 2814
2800 2815
2801 if __name__ == '__main__': 2816 if __name__ == '__main__':
2802 # These affect sys.stdout so do it outside of main() to simplify mocks in 2817 # These affect sys.stdout so do it outside of main() to simplify mocks in
2803 # unit testing. 2818 # unit testing.
2804 fix_encoding.fix_encoding() 2819 fix_encoding.fix_encoding()
2805 colorama.init() 2820 colorama.init()
2806 sys.exit(main(sys.argv[1:])) 2821 sys.exit(main(sys.argv[1:]))
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698