| OLD | NEW |
| 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 and Gerrit.""" | 8 """A git-command for integrating reviews on Rietveld and Gerrit.""" |
| 9 | 9 |
| 10 from distutils.version import LooseVersion | 10 from distutils.version import LooseVersion |
| (...skipping 1408 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1419 directory: switch to directory before applying the patch. Rietveld only. | 1419 directory: switch to directory before applying the patch. Rietveld only. |
| 1420 """ | 1420 """ |
| 1421 raise NotImplementedError() | 1421 raise NotImplementedError() |
| 1422 | 1422 |
| 1423 @staticmethod | 1423 @staticmethod |
| 1424 def ParseIssueURL(parsed_url): | 1424 def ParseIssueURL(parsed_url): |
| 1425 """Parses url and returns instance of _ParsedIssueNumberArgument or None if | 1425 """Parses url and returns instance of _ParsedIssueNumberArgument or None if |
| 1426 failed.""" | 1426 failed.""" |
| 1427 raise NotImplementedError() | 1427 raise NotImplementedError() |
| 1428 | 1428 |
| 1429 def CMDUploadChange(self, options, args, change): |
| 1430 """Uploads a change to codereview.""" |
| 1431 raise NotImplementedError() |
| 1432 |
| 1429 | 1433 |
| 1430 class _RietveldChangelistImpl(_ChangelistCodereviewBase): | 1434 class _RietveldChangelistImpl(_ChangelistCodereviewBase): |
| 1431 def __init__(self, changelist, auth_config=None, rietveld_server=None): | 1435 def __init__(self, changelist, auth_config=None, rietveld_server=None): |
| 1432 super(_RietveldChangelistImpl, self).__init__(changelist) | 1436 super(_RietveldChangelistImpl, self).__init__(changelist) |
| 1433 assert settings, 'must be initialized in _ChangelistCodereviewBase' | 1437 assert settings, 'must be initialized in _ChangelistCodereviewBase' |
| 1434 settings.GetDefaultServerUrl() | 1438 settings.GetDefaultServerUrl() |
| 1435 | 1439 |
| 1436 self._rietveld_server = rietveld_server | 1440 self._rietveld_server = rietveld_server |
| 1437 self._auth_config = auth_config | 1441 self._auth_config = auth_config |
| 1438 self._props = None | 1442 self._props = None |
| 1439 self._rpc_server = None | 1443 self._rpc_server = None |
| 1440 | 1444 |
| 1441 def GetAuthConfig(self): | |
| 1442 return self._auth_config | |
| 1443 | |
| 1444 def GetCodereviewServer(self): | 1445 def GetCodereviewServer(self): |
| 1445 if not self._rietveld_server: | 1446 if not self._rietveld_server: |
| 1446 # If we're on a branch then get the server potentially associated | 1447 # If we're on a branch then get the server potentially associated |
| 1447 # with that branch. | 1448 # with that branch. |
| 1448 if self.GetIssue(): | 1449 if self.GetIssue(): |
| 1449 rietveld_server_setting = self.GetCodereviewServerSetting() | 1450 rietveld_server_setting = self.GetCodereviewServerSetting() |
| 1450 if rietveld_server_setting: | 1451 if rietveld_server_setting: |
| 1451 self._rietveld_server = gclient_utils.UpgradeToHttps(RunGit( | 1452 self._rietveld_server = gclient_utils.UpgradeToHttps(RunGit( |
| 1452 ['config', rietveld_server_setting], error_ok=True).strip()) | 1453 ['config', rietveld_server_setting], error_ok=True).strip()) |
| 1453 if not self._rietveld_server: | 1454 if not self._rietveld_server: |
| (...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1680 # Rietveld patch: https://domain/download/issue<number>_<patchset>.diff | 1681 # Rietveld patch: https://domain/download/issue<number>_<patchset>.diff |
| 1681 match = re.match(r'/download/issue(\d+)_(\d+).diff$', parsed_url.path) | 1682 match = re.match(r'/download/issue(\d+)_(\d+).diff$', parsed_url.path) |
| 1682 if match: | 1683 if match: |
| 1683 return _RietveldParsedIssueNumberArgument( | 1684 return _RietveldParsedIssueNumberArgument( |
| 1684 issue=int(match.group(1)), | 1685 issue=int(match.group(1)), |
| 1685 patchset=int(match.group(2)), | 1686 patchset=int(match.group(2)), |
| 1686 hostname=parsed_url.netloc, | 1687 hostname=parsed_url.netloc, |
| 1687 patch_url=gclient_utils.UpgradeToHttps(parsed_url.geturl())) | 1688 patch_url=gclient_utils.UpgradeToHttps(parsed_url.geturl())) |
| 1688 return None | 1689 return None |
| 1689 | 1690 |
| 1691 def CMDUploadChange(self, options, args, change): |
| 1692 """Upload the patch to Rietveld.""" |
| 1693 upload_args = ['--assume_yes'] # Don't ask about untracked files. |
| 1694 upload_args.extend(['--server', self.GetCodereviewServer()]) |
| 1695 # TODO(tandrii): refactor this ugliness into _RietveldChangelistImpl. |
| 1696 upload_args.extend(auth.auth_config_to_command_options(self._auth_config)) |
| 1697 if options.emulate_svn_auto_props: |
| 1698 upload_args.append('--emulate_svn_auto_props') |
| 1699 |
| 1700 change_desc = None |
| 1701 |
| 1702 if options.email is not None: |
| 1703 upload_args.extend(['--email', options.email]) |
| 1704 |
| 1705 if self.GetIssue(): |
| 1706 if options.title: |
| 1707 upload_args.extend(['--title', options.title]) |
| 1708 if options.message: |
| 1709 upload_args.extend(['--message', options.message]) |
| 1710 upload_args.extend(['--issue', str(self.GetIssue())]) |
| 1711 print ('This branch is associated with issue %s. ' |
| 1712 'Adding patch to that issue.' % self.GetIssue()) |
| 1713 else: |
| 1714 if options.title: |
| 1715 upload_args.extend(['--title', options.title]) |
| 1716 message = (options.title or options.message or |
| 1717 CreateDescriptionFromLog(args)) |
| 1718 change_desc = ChangeDescription(message) |
| 1719 if options.reviewers or options.tbr_owners: |
| 1720 change_desc.update_reviewers(options.reviewers, |
| 1721 options.tbr_owners, |
| 1722 change) |
| 1723 if not options.force: |
| 1724 change_desc.prompt() |
| 1725 |
| 1726 if not change_desc.description: |
| 1727 print "Description is empty; aborting." |
| 1728 return 1 |
| 1729 |
| 1730 upload_args.extend(['--message', change_desc.description]) |
| 1731 if change_desc.get_reviewers(): |
| 1732 upload_args.append('--reviewers=%s' % ','.join( |
| 1733 change_desc.get_reviewers())) |
| 1734 if options.send_mail: |
| 1735 if not change_desc.get_reviewers(): |
| 1736 DieWithError("Must specify reviewers to send email.") |
| 1737 upload_args.append('--send_mail') |
| 1738 |
| 1739 # We check this before applying rietveld.private assuming that in |
| 1740 # rietveld.cc only addresses which we can send private CLs to are listed |
| 1741 # if rietveld.private is set, and so we should ignore rietveld.cc only |
| 1742 # when --private is specified explicitly on the command line. |
| 1743 if options.private: |
| 1744 logging.warn('rietveld.cc is ignored since private flag is specified. ' |
| 1745 'You need to review and add them manually if necessary.') |
| 1746 cc = self.GetCCListWithoutDefault() |
| 1747 else: |
| 1748 cc = self.GetCCList() |
| 1749 cc = ','.join(filter(None, (cc, ','.join(options.cc)))) |
| 1750 if cc: |
| 1751 upload_args.extend(['--cc', cc]) |
| 1752 |
| 1753 if options.private or settings.GetDefaultPrivateFlag() == "True": |
| 1754 upload_args.append('--private') |
| 1755 |
| 1756 upload_args.extend(['--git_similarity', str(options.similarity)]) |
| 1757 if not options.find_copies: |
| 1758 upload_args.extend(['--git_no_find_copies']) |
| 1759 |
| 1760 # Include the upstream repo's URL in the change -- this is useful for |
| 1761 # projects that have their source spread across multiple repos. |
| 1762 remote_url = self.GetGitBaseUrlFromConfig() |
| 1763 if not remote_url: |
| 1764 if settings.GetIsGitSvn(): |
| 1765 remote_url = self.GetGitSvnRemoteUrl() |
| 1766 else: |
| 1767 if self.GetRemoteUrl() and '/' in self.GetUpstreamBranch(): |
| 1768 remote_url = '%s@%s' % (self.GetRemoteUrl(), |
| 1769 self.GetUpstreamBranch().split('/')[-1]) |
| 1770 if remote_url: |
| 1771 upload_args.extend(['--base_url', remote_url]) |
| 1772 remote, remote_branch = self.GetRemoteBranch() |
| 1773 target_ref = GetTargetRef(remote, remote_branch, options.target_branch, |
| 1774 settings.GetPendingRefPrefix()) |
| 1775 if target_ref: |
| 1776 upload_args.extend(['--target_ref', target_ref]) |
| 1777 |
| 1778 # Look for dependent patchsets. See crbug.com/480453 for more details. |
| 1779 remote, upstream_branch = self.FetchUpstreamTuple(self.GetBranch()) |
| 1780 upstream_branch = ShortBranchName(upstream_branch) |
| 1781 if remote is '.': |
| 1782 # A local branch is being tracked. |
| 1783 local_branch = ShortBranchName(upstream_branch) |
| 1784 if settings.GetIsSkipDependencyUpload(local_branch): |
| 1785 print |
| 1786 print ('Skipping dependency patchset upload because git config ' |
| 1787 'branch.%s.skip-deps-uploads is set to True.' % local_branch) |
| 1788 print |
| 1789 else: |
| 1790 auth_config = auth.extract_auth_config_from_options(options) |
| 1791 branch_cl = Changelist(branchref=local_branch, |
| 1792 auth_config=auth_config) |
| 1793 branch_cl_issue_url = branch_cl.GetIssueURL() |
| 1794 branch_cl_issue = branch_cl.GetIssue() |
| 1795 branch_cl_patchset = branch_cl.GetPatchset() |
| 1796 if branch_cl_issue_url and branch_cl_issue and branch_cl_patchset: |
| 1797 upload_args.extend( |
| 1798 ['--depends_on_patchset', '%s:%s' % ( |
| 1799 branch_cl_issue, branch_cl_patchset)]) |
| 1800 print ( |
| 1801 '\n' |
| 1802 'The current branch (%s) is tracking a local branch (%s) with ' |
| 1803 'an associated CL.\n' |
| 1804 'Adding %s/#ps%s as a dependency patchset.\n' |
| 1805 '\n' % (self.GetBranch(), local_branch, branch_cl_issue_url, |
| 1806 branch_cl_patchset)) |
| 1807 |
| 1808 project = settings.GetProject() |
| 1809 if project: |
| 1810 upload_args.extend(['--project', project]) |
| 1811 |
| 1812 if options.cq_dry_run: |
| 1813 upload_args.extend(['--cq_dry_run']) |
| 1814 |
| 1815 try: |
| 1816 upload_args = ['upload'] + upload_args + args |
| 1817 logging.info('upload.RealMain(%s)', upload_args) |
| 1818 issue, patchset = upload.RealMain(upload_args) |
| 1819 issue = int(issue) |
| 1820 patchset = int(patchset) |
| 1821 except KeyboardInterrupt: |
| 1822 sys.exit(1) |
| 1823 except: |
| 1824 # If we got an exception after the user typed a description for their |
| 1825 # change, back up the description before re-raising. |
| 1826 if change_desc: |
| 1827 backup_path = os.path.expanduser(DESCRIPTION_BACKUP_FILE) |
| 1828 print('\nGot exception while uploading -- saving description to %s\n' % |
| 1829 backup_path) |
| 1830 backup_file = open(backup_path, 'w') |
| 1831 backup_file.write(change_desc.description) |
| 1832 backup_file.close() |
| 1833 raise |
| 1834 |
| 1835 if not self.GetIssue(): |
| 1836 self.SetIssue(issue) |
| 1837 self.SetPatchset(patchset) |
| 1838 |
| 1839 if options.use_commit_queue: |
| 1840 self.SetFlag('commit', '1') |
| 1841 return 0 |
| 1842 |
| 1690 | 1843 |
| 1691 class _GerritChangelistImpl(_ChangelistCodereviewBase): | 1844 class _GerritChangelistImpl(_ChangelistCodereviewBase): |
| 1692 def __init__(self, changelist, auth_config=None): | 1845 def __init__(self, changelist, auth_config=None): |
| 1693 # auth_config is Rietveld thing, kept here to preserve interface only. | 1846 # auth_config is Rietveld thing, kept here to preserve interface only. |
| 1694 super(_GerritChangelistImpl, self).__init__(changelist) | 1847 super(_GerritChangelistImpl, self).__init__(changelist) |
| 1695 self._change_id = None | 1848 self._change_id = None |
| 1696 self._gerrit_server = None # e.g. https://chromium-review.googlesource.com | 1849 self._gerrit_server = None # e.g. https://chromium-review.googlesource.com |
| 1697 self._gerrit_host = None # e.g. chromium-review.googlesource.com | 1850 self._gerrit_host = None # e.g. chromium-review.googlesource.com |
| 1698 | 1851 |
| 1699 def _GetGerritHost(self): | 1852 def _GetGerritHost(self): |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1819 # TODO(tandrii) | 1972 # TODO(tandrii) |
| 1820 raise NotImplementedError() | 1973 raise NotImplementedError() |
| 1821 | 1974 |
| 1822 def CloseIssue(self): | 1975 def CloseIssue(self): |
| 1823 gerrit_util.AbandonChange(self._GetGerritHost(), self.GetIssue(), msg='') | 1976 gerrit_util.AbandonChange(self._GetGerritHost(), self.GetIssue(), msg='') |
| 1824 | 1977 |
| 1825 def SubmitIssue(self, wait_for_merge=True): | 1978 def SubmitIssue(self, wait_for_merge=True): |
| 1826 gerrit_util.SubmitChange(self._GetGerritHost(), self.GetIssue(), | 1979 gerrit_util.SubmitChange(self._GetGerritHost(), self.GetIssue(), |
| 1827 wait_for_merge=wait_for_merge) | 1980 wait_for_merge=wait_for_merge) |
| 1828 | 1981 |
| 1829 def _GetChangeDetail(self, options): | 1982 def _GetChangeDetail(self, options=None, issue=None): |
| 1830 return gerrit_util.GetChangeDetail(self._GetGerritHost(), self.GetIssue(), | 1983 options = options or [] |
| 1831 options) | 1984 issue = issue or self.GetIssue() |
| 1985 assert issue, 'issue required to query Gerrit' |
| 1986 return gerrit_util.GetChangeDetail(self._GetGerritHost(), options, issue) |
| 1832 | 1987 |
| 1833 def CMDLand(self, force, bypass_hooks, verbose): | 1988 def CMDLand(self, force, bypass_hooks, verbose): |
| 1834 if git_common.is_dirty_git_tree('land'): | 1989 if git_common.is_dirty_git_tree('land'): |
| 1835 return 1 | 1990 return 1 |
| 1836 differs = True | 1991 differs = True |
| 1837 last_upload = RunGit(['config', | 1992 last_upload = RunGit(['config', |
| 1838 'branch.%s.gerritsquashhash' % self.GetBranch()], | 1993 'branch.%s.gerritsquashhash' % self.GetBranch()], |
| 1839 error_ok=True).strip() | 1994 error_ok=True).strip() |
| 1840 # Note: git diff outputs nothing if there is no diff. | 1995 # Note: git diff outputs nothing if there is no diff. |
| 1841 if not last_upload or RunGit(['diff', last_upload]).strip(): | 1996 if not last_upload or RunGit(['diff', last_upload]).strip(): |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1915 else: | 2070 else: |
| 1916 part = parsed_url.path | 2071 part = parsed_url.path |
| 1917 match = re.match('(/c)?/(\d+)(/(\d+)?/?)?$', part) | 2072 match = re.match('(/c)?/(\d+)(/(\d+)?/?)?$', part) |
| 1918 if match: | 2073 if match: |
| 1919 return _ParsedIssueNumberArgument( | 2074 return _ParsedIssueNumberArgument( |
| 1920 issue=int(match.group(2)), | 2075 issue=int(match.group(2)), |
| 1921 patchset=int(match.group(4)) if match.group(4) else None, | 2076 patchset=int(match.group(4)) if match.group(4) else None, |
| 1922 hostname=parsed_url.netloc) | 2077 hostname=parsed_url.netloc) |
| 1923 return None | 2078 return None |
| 1924 | 2079 |
| 2080 def CMDUploadChange(self, options, args, change): |
| 2081 """Upload the current branch to Gerrit.""" |
| 2082 # We assume the remote called "origin" is the one we want. |
| 2083 # It is probably not worthwhile to support different workflows. |
| 2084 gerrit_remote = 'origin' |
| 2085 |
| 2086 remote, remote_branch = self.GetRemoteBranch() |
| 2087 branch = GetTargetRef(remote, remote_branch, options.target_branch, |
| 2088 pending_prefix='') |
| 2089 |
| 2090 if options.title: |
| 2091 # TODO(tandrii): it's now supported by Gerrit, implement! |
| 2092 print "\nPatch titles (-t) are not supported in Gerrit. Aborting..." |
| 2093 return 1 |
| 2094 |
| 2095 if options.squash: |
| 2096 if not self.GetIssue(): |
| 2097 # TODO(tandrii): deperecate this after 2016Q2. Backwards compatibility |
| 2098 # with shadow branch, which used to contain change-id for a given |
| 2099 # branch, using which we can fetch actual issue number and set it as the |
| 2100 # property of the branch, which is the new way. |
| 2101 message = RunGitSilent([ |
| 2102 'show', '--format=%B', '-s', |
| 2103 'refs/heads/git_cl_uploads/%s' % self.GetBranch()]) |
| 2104 if message: |
| 2105 change_ids = git_footers.get_footer_change_id(message.strip()) |
| 2106 if change_ids and len(change_ids) == 1: |
| 2107 details = self._GetChangeDetail(issue=change_ids[0]) |
| 2108 if details: |
| 2109 print('WARNING: found old upload in branch git_cl_uploads/%s ' |
| 2110 'corresponding to issue %s' % |
| 2111 (self.GetBranch(), details['_number'])) |
| 2112 self.SetIssue(details['_number']) |
| 2113 if not self.GetIssue(): |
| 2114 DieWithError( |
| 2115 '\n' # For readability of the blob below. |
| 2116 'Found old upload in branch git_cl_uploads/%s, ' |
| 2117 'but failed to find corresponding Gerrit issue.\n' |
| 2118 'If you know the issue number, set it manually first:\n' |
| 2119 ' git cl issue 123456\n' |
| 2120 'If you intended to upload this CL as new issue, ' |
| 2121 'just delete or rename the old upload branch:\n' |
| 2122 ' git rename-branch git_cl_uploads/%s old_upload-%s\n' |
| 2123 'After that, please run git cl upload again.' % |
| 2124 tuple([self.GetBranch()] * 3)) |
| 2125 # End of backwards compatability. |
| 2126 |
| 2127 if self.GetIssue(): |
| 2128 # Try to get the message from a previous upload. |
| 2129 message = self.GetDescription() |
| 2130 if not message: |
| 2131 DieWithError( |
| 2132 'failed to fetch description from current Gerrit issue %d\n' |
| 2133 '%s' % (self.GetIssue(), self.GetIssueURL())) |
| 2134 change_id = self._GetChangeDetail()['change_id'] |
| 2135 while True: |
| 2136 footer_change_ids = git_footers.get_footer_change_id(message) |
| 2137 if footer_change_ids == [change_id]: |
| 2138 break |
| 2139 if not footer_change_ids: |
| 2140 message = git_footers.add_footer_change_id(message, change_id) |
| 2141 print('WARNING: appended missing Change-Id to issue description') |
| 2142 continue |
| 2143 # There is already a valid footer but with different or several ids. |
| 2144 # Doing this automatically is non-trivial as we don't want to lose |
| 2145 # existing other footers, yet we want to append just 1 desired |
| 2146 # Change-Id. Thus, just create a new footer, but let user verify the |
| 2147 # new description. |
| 2148 message = '%s\n\nChange-Id: %s' % (message, change_id) |
| 2149 print( |
| 2150 'WARNING: issue %s has Change-Id footer(s):\n' |
| 2151 ' %s\n' |
| 2152 'but issue has Change-Id %s, according to Gerrit.\n' |
| 2153 'Please, check the proposed correction to the description, ' |
| 2154 'and edit it if necessary but keep the "Change-Id: %s" footer\n' |
| 2155 % (self.GetIssue(), '\n '.join(footer_change_ids), change_id, |
| 2156 change_id)) |
| 2157 ask_for_data('Press enter to edit now, Ctrl+C to abort') |
| 2158 if not options.force: |
| 2159 change_desc = ChangeDescription(message) |
| 2160 change_desc.prompt() |
| 2161 message = change_desc.description |
| 2162 if not message: |
| 2163 DieWithError("Description is empty. Aborting...") |
| 2164 # Continue the while loop. |
| 2165 # Sanity check of this code - we should end up with proper message |
| 2166 # footer. |
| 2167 assert [change_id] == git_footers.get_footer_change_id(message) |
| 2168 change_desc = ChangeDescription(message) |
| 2169 else: |
| 2170 change_desc = ChangeDescription( |
| 2171 options.message or CreateDescriptionFromLog(args)) |
| 2172 if not options.force: |
| 2173 change_desc.prompt() |
| 2174 if not change_desc.description: |
| 2175 DieWithError("Description is empty. Aborting...") |
| 2176 message = change_desc.description |
| 2177 change_ids = git_footers.get_footer_change_id(message) |
| 2178 if len(change_ids) > 1: |
| 2179 DieWithError('too many Change-Id footers, at most 1 allowed.') |
| 2180 if not change_ids: |
| 2181 # Generate the Change-Id automatically. |
| 2182 message = git_footers.add_footer_change_id( |
| 2183 message, GenerateGerritChangeId(message)) |
| 2184 change_desc.set_description(message) |
| 2185 change_ids = git_footers.get_footer_change_id(message) |
| 2186 assert len(change_ids) == 1 |
| 2187 change_id = change_ids[0] |
| 2188 |
| 2189 remote, upstream_branch = self.FetchUpstreamTuple(self.GetBranch()) |
| 2190 if remote is '.': |
| 2191 # If our upstream branch is local, we base our squashed commit on its |
| 2192 # squashed version. |
| 2193 upstream_branch_name = scm.GIT.ShortBranchName(upstream_branch) |
| 2194 # Check the squashed hash of the parent. |
| 2195 parent = RunGit(['config', |
| 2196 'branch.%s.gerritsquashhash' % upstream_branch_name], |
| 2197 error_ok=True).strip() |
| 2198 # Verify that the upstream branch has been uploaded too, otherwise |
| 2199 # Gerrit will create additional CLs when uploading. |
| 2200 if not parent or (RunGitSilent(['rev-parse', upstream_branch + ':']) != |
| 2201 RunGitSilent(['rev-parse', parent + ':'])): |
| 2202 # TODO(tandrii): remove "old depot_tools" part on April 12, 2016. |
| 2203 DieWithError( |
| 2204 'Upload upstream branch %s first.\n' |
| 2205 'Note: maybe you\'ve uploaded it with --no-squash or with an old ' |
| 2206 'version of depot_tools. If so, then re-upload it with:\n' |
| 2207 ' git cl upload --squash\n' % upstream_branch_name) |
| 2208 else: |
| 2209 parent = self.GetCommonAncestorWithUpstream() |
| 2210 |
| 2211 tree = RunGit(['rev-parse', 'HEAD:']).strip() |
| 2212 ref_to_push = RunGit(['commit-tree', tree, '-p', parent, |
| 2213 '-m', message]).strip() |
| 2214 else: |
| 2215 change_desc = ChangeDescription( |
| 2216 options.message or CreateDescriptionFromLog(args)) |
| 2217 if not change_desc.description: |
| 2218 DieWithError("Description is empty. Aborting...") |
| 2219 |
| 2220 if not git_footers.get_footer_change_id(change_desc.description): |
| 2221 DownloadGerritHook(False) |
| 2222 change_desc.set_description(AddChangeIdToCommitMessage(options, args)) |
| 2223 ref_to_push = 'HEAD' |
| 2224 parent = '%s/%s' % (gerrit_remote, branch) |
| 2225 change_id = git_footers.get_footer_change_id(change_desc.description)[0] |
| 2226 |
| 2227 assert change_desc |
| 2228 commits = RunGitSilent(['rev-list', '%s..%s' % (parent, |
| 2229 ref_to_push)]).splitlines() |
| 2230 if len(commits) > 1: |
| 2231 print('WARNING: This will upload %d commits. Run the following command ' |
| 2232 'to see which commits will be uploaded: ' % len(commits)) |
| 2233 print('git log %s..%s' % (parent, ref_to_push)) |
| 2234 print('You can also use `git squash-branch` to squash these into a ' |
| 2235 'single commit.') |
| 2236 ask_for_data('About to upload; enter to confirm.') |
| 2237 |
| 2238 if options.reviewers or options.tbr_owners: |
| 2239 change_desc.update_reviewers(options.reviewers, options.tbr_owners, |
| 2240 change) |
| 2241 |
| 2242 receive_options = [] |
| 2243 cc = self.GetCCList().split(',') |
| 2244 if options.cc: |
| 2245 cc.extend(options.cc) |
| 2246 cc = filter(None, cc) |
| 2247 if cc: |
| 2248 receive_options += ['--cc=' + email for email in cc] |
| 2249 if change_desc.get_reviewers(): |
| 2250 receive_options.extend( |
| 2251 '--reviewer=' + email for email in change_desc.get_reviewers()) |
| 2252 |
| 2253 git_command = ['push'] |
| 2254 if receive_options: |
| 2255 git_command.append('--receive-pack=git receive-pack %s' % |
| 2256 ' '.join(receive_options)) |
| 2257 git_command += [gerrit_remote, ref_to_push + ':refs/for/' + branch] |
| 2258 push_stdout = gclient_utils.CheckCallAndFilter( |
| 2259 ['git'] + git_command, |
| 2260 print_stdout=True, |
| 2261 # Flush after every line: useful for seeing progress when running as |
| 2262 # recipe. |
| 2263 filter_fn=lambda _: sys.stdout.flush()) |
| 2264 |
| 2265 if options.squash: |
| 2266 regex = re.compile(r'remote:\s+https?://[\w\-\.\/]*/(\d+)\s.*') |
| 2267 change_numbers = [m.group(1) |
| 2268 for m in map(regex.match, push_stdout.splitlines()) |
| 2269 if m] |
| 2270 if len(change_numbers) != 1: |
| 2271 DieWithError( |
| 2272 ('Created|Updated %d issues on Gerrit, but only 1 expected.\n' |
| 2273 'Change-Id: %s') % (len(change_numbers), change_id)) |
| 2274 self.SetIssue(change_numbers[0]) |
| 2275 RunGit(['config', 'branch.%s.gerritsquashhash' % self.GetBranch(), |
| 2276 ref_to_push]) |
| 2277 return 0 |
| 2278 |
| 2279 |
| 1925 | 2280 |
| 1926 _CODEREVIEW_IMPLEMENTATIONS = { | 2281 _CODEREVIEW_IMPLEMENTATIONS = { |
| 1927 'rietveld': _RietveldChangelistImpl, | 2282 'rietveld': _RietveldChangelistImpl, |
| 1928 'gerrit': _GerritChangelistImpl, | 2283 'gerrit': _GerritChangelistImpl, |
| 1929 } | 2284 } |
| 1930 | 2285 |
| 1931 | 2286 |
| 1932 class ChangeDescription(object): | 2287 class ChangeDescription(object): |
| 1933 """Contains a parsed form of the change description.""" | 2288 """Contains a parsed form of the change description.""" |
| 1934 R_LINE = r'^[ \t]*(TBR|R)[ \t]*=[ \t]*(.*?)[ \t]*$' | 2289 R_LINE = r'^[ \t]*(TBR|R)[ \t]*=[ \t]*(.*?)[ \t]*$' |
| (...skipping 852 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2787 lines.append('') | 3142 lines.append('') |
| 2788 # Note: Gerrit's commit-hook actually cleans message of some lines and | 3143 # Note: Gerrit's commit-hook actually cleans message of some lines and |
| 2789 # whitespace. This code is not doing this, but it clearly won't decrease | 3144 # whitespace. This code is not doing this, but it clearly won't decrease |
| 2790 # entropy. | 3145 # entropy. |
| 2791 lines.append(message) | 3146 lines.append(message) |
| 2792 change_hash = RunCommand(['git', 'hash-object', '-t', 'commit', '--stdin'], | 3147 change_hash = RunCommand(['git', 'hash-object', '-t', 'commit', '--stdin'], |
| 2793 stdin='\n'.join(lines)) | 3148 stdin='\n'.join(lines)) |
| 2794 return 'I%s' % change_hash.strip() | 3149 return 'I%s' % change_hash.strip() |
| 2795 | 3150 |
| 2796 | 3151 |
| 2797 def GerritUpload(options, args, cl, change): | |
| 2798 """upload the current branch to gerrit.""" | |
| 2799 # TODO(tandrii): refactor this to be a method of _GerritChangelistImpl, | |
| 2800 # to avoid private members accessors below. | |
| 2801 | |
| 2802 # We assume the remote called "origin" is the one we want. | |
| 2803 # It is probably not worthwhile to support different workflows. | |
| 2804 gerrit_remote = 'origin' | |
| 2805 | |
| 2806 remote, remote_branch = cl.GetRemoteBranch() | |
| 2807 branch = GetTargetRef(remote, remote_branch, options.target_branch, | |
| 2808 pending_prefix='') | |
| 2809 | |
| 2810 if options.title: | |
| 2811 print "\nPatch titles (-t) are not supported in Gerrit. Aborting..." | |
| 2812 return 1 | |
| 2813 | |
| 2814 if options.squash: | |
| 2815 if not cl.GetIssue(): | |
| 2816 # TODO(tandrii): deperecate this after 2016Q2. | |
| 2817 # Backwards compatibility with shadow branch, which used to contain | |
| 2818 # change-id for a given branch, using which we can fetch actual issue | |
| 2819 # number and set it as the property of the branch, which is the new way. | |
| 2820 message = RunGitSilent(['show', '--format=%B', '-s', | |
| 2821 'refs/heads/git_cl_uploads/%s' % cl.GetBranch()]) | |
| 2822 if message: | |
| 2823 change_ids = git_footers.get_footer_change_id(message.strip()) | |
| 2824 if change_ids and len(change_ids) == 1: | |
| 2825 details = gerrit_util.GetChangeDetail( | |
| 2826 cl._codereview_impl._GetGerritHost(), change_ids[0]) | |
| 2827 if details: | |
| 2828 print('WARNING: found old upload in branch git_cl_uploads/%s ' | |
| 2829 'corresponding to issue %s' % | |
| 2830 (cl.GetBranch(), details['_number'])) | |
| 2831 cl.SetIssue(details['_number']) | |
| 2832 if not cl.GetIssue(): | |
| 2833 DieWithError( | |
| 2834 '\n' # For readability of the blob below. | |
| 2835 'Found old upload in branch git_cl_uploads/%s, ' | |
| 2836 'but failed to find corresponding Gerrit issue.\n' | |
| 2837 'If you know the issue number, set it manually first:\n' | |
| 2838 ' git cl issue 123456\n' | |
| 2839 'If you intended to upload this CL as new issue, ' | |
| 2840 'just delete or rename the old upload branch:\n' | |
| 2841 ' git rename-branch git_cl_uploads/%s old_upload-%s\n' | |
| 2842 'After that, please run git cl upload again.' % | |
| 2843 tuple([cl.GetBranch()] * 3)) | |
| 2844 # End of backwards compatability. | |
| 2845 | |
| 2846 if cl.GetIssue(): | |
| 2847 # Try to get the message from a previous upload. | |
| 2848 message = cl.GetDescription() | |
| 2849 if not message: | |
| 2850 DieWithError( | |
| 2851 'failed to fetch description from current Gerrit issue %d\n' | |
| 2852 '%s' % (cl.GetIssue(), cl.GetIssueURL())) | |
| 2853 change_id = cl._codereview_impl._GetChangeDetail([])['change_id'] | |
| 2854 while True: | |
| 2855 footer_change_ids = git_footers.get_footer_change_id(message) | |
| 2856 if footer_change_ids == [change_id]: | |
| 2857 break | |
| 2858 if not footer_change_ids: | |
| 2859 message = git_footers.add_footer_change_id(message, change_id) | |
| 2860 print('WARNING: appended missing Change-Id to issue description') | |
| 2861 continue | |
| 2862 # There is already a valid footer but with different or several ids. | |
| 2863 # Doing this automatically is non-trivial as we don't want to lose | |
| 2864 # existing other footers, yet we want to append just 1 desired | |
| 2865 # Change-Id. Thus, just create a new footer, but let user verify the new | |
| 2866 # description. | |
| 2867 message = '%s\n\nChange-Id: %s' % (message, change_id) | |
| 2868 print( | |
| 2869 'WARNING: issue %s has Change-Id footer(s):\n' | |
| 2870 ' %s\n' | |
| 2871 'but issue has Change-Id %s, according to Gerrit.\n' | |
| 2872 'Please, check the proposed correction to the description, ' | |
| 2873 'and edit it if necessary but keep the "Change-Id: %s" footer\n' | |
| 2874 % (cl.GetIssue(), '\n '.join(footer_change_ids), change_id, | |
| 2875 change_id)) | |
| 2876 ask_for_data('Press enter to edit now, Ctrl+C to abort') | |
| 2877 if not options.force: | |
| 2878 change_desc = ChangeDescription(message) | |
| 2879 change_desc.prompt() | |
| 2880 message = change_desc.description | |
| 2881 if not message: | |
| 2882 DieWithError("Description is empty. Aborting...") | |
| 2883 # Continue the while loop. | |
| 2884 # Sanity check of this code - we should end up with proper message footer. | |
| 2885 assert [change_id] == git_footers.get_footer_change_id(message) | |
| 2886 change_desc = ChangeDescription(message) | |
| 2887 else: | |
| 2888 change_desc = ChangeDescription( | |
| 2889 options.message or CreateDescriptionFromLog(args)) | |
| 2890 if not options.force: | |
| 2891 change_desc.prompt() | |
| 2892 if not change_desc.description: | |
| 2893 DieWithError("Description is empty. Aborting...") | |
| 2894 message = change_desc.description | |
| 2895 change_ids = git_footers.get_footer_change_id(message) | |
| 2896 if len(change_ids) > 1: | |
| 2897 DieWithError('too many Change-Id footers, at most 1 allowed.') | |
| 2898 if not change_ids: | |
| 2899 # Generate the Change-Id automatically. | |
| 2900 message = git_footers.add_footer_change_id( | |
| 2901 message, GenerateGerritChangeId(message)) | |
| 2902 change_desc.set_description(message) | |
| 2903 change_ids = git_footers.get_footer_change_id(message) | |
| 2904 assert len(change_ids) == 1 | |
| 2905 change_id = change_ids[0] | |
| 2906 | |
| 2907 remote, upstream_branch = cl.FetchUpstreamTuple(cl.GetBranch()) | |
| 2908 if remote is '.': | |
| 2909 # If our upstream branch is local, we base our squashed commit on its | |
| 2910 # squashed version. | |
| 2911 upstream_branch_name = scm.GIT.ShortBranchName(upstream_branch) | |
| 2912 # Check the squashed hash of the parent. | |
| 2913 parent = RunGit(['config', | |
| 2914 'branch.%s.gerritsquashhash' % upstream_branch_name], | |
| 2915 error_ok=True).strip() | |
| 2916 # Verify that the upstream branch has been uploaded too, otherwise | |
| 2917 # Gerrit will create additional CLs when uploading. | |
| 2918 if not parent or (RunGitSilent(['rev-parse', upstream_branch + ':']) != | |
| 2919 RunGitSilent(['rev-parse', parent + ':'])): | |
| 2920 # TODO(tandrii): remove "old depot_tools" part on April 12, 2016. | |
| 2921 DieWithError( | |
| 2922 'Upload upstream branch %s first.\n' | |
| 2923 'Note: maybe you\'ve uploaded it with --no-squash or with an old\n' | |
| 2924 ' version of depot_tools. If so, then re-upload it with:\n' | |
| 2925 ' git cl upload --squash\n' % upstream_branch_name) | |
| 2926 else: | |
| 2927 parent = cl.GetCommonAncestorWithUpstream() | |
| 2928 | |
| 2929 tree = RunGit(['rev-parse', 'HEAD:']).strip() | |
| 2930 ref_to_push = RunGit(['commit-tree', tree, '-p', parent, | |
| 2931 '-m', message]).strip() | |
| 2932 else: | |
| 2933 change_desc = ChangeDescription( | |
| 2934 options.message or CreateDescriptionFromLog(args)) | |
| 2935 if not change_desc.description: | |
| 2936 DieWithError("Description is empty. Aborting...") | |
| 2937 | |
| 2938 if not git_footers.get_footer_change_id(change_desc.description): | |
| 2939 DownloadGerritHook(False) | |
| 2940 change_desc.set_description(AddChangeIdToCommitMessage(options, args)) | |
| 2941 ref_to_push = 'HEAD' | |
| 2942 parent = '%s/%s' % (gerrit_remote, branch) | |
| 2943 change_id = git_footers.get_footer_change_id(change_desc.description)[0] | |
| 2944 | |
| 2945 assert change_desc | |
| 2946 commits = RunGitSilent(['rev-list', '%s..%s' % (parent, | |
| 2947 ref_to_push)]).splitlines() | |
| 2948 if len(commits) > 1: | |
| 2949 print('WARNING: This will upload %d commits. Run the following command ' | |
| 2950 'to see which commits will be uploaded: ' % len(commits)) | |
| 2951 print('git log %s..%s' % (parent, ref_to_push)) | |
| 2952 print('You can also use `git squash-branch` to squash these into a single ' | |
| 2953 'commit.') | |
| 2954 ask_for_data('About to upload; enter to confirm.') | |
| 2955 | |
| 2956 if options.reviewers or options.tbr_owners: | |
| 2957 change_desc.update_reviewers(options.reviewers, options.tbr_owners, change) | |
| 2958 | |
| 2959 receive_options = [] | |
| 2960 cc = cl.GetCCList().split(',') | |
| 2961 if options.cc: | |
| 2962 cc.extend(options.cc) | |
| 2963 cc = filter(None, cc) | |
| 2964 if cc: | |
| 2965 receive_options += ['--cc=' + email for email in cc] | |
| 2966 if change_desc.get_reviewers(): | |
| 2967 receive_options.extend( | |
| 2968 '--reviewer=' + email for email in change_desc.get_reviewers()) | |
| 2969 | |
| 2970 git_command = ['push'] | |
| 2971 if receive_options: | |
| 2972 git_command.append('--receive-pack=git receive-pack %s' % | |
| 2973 ' '.join(receive_options)) | |
| 2974 git_command += [gerrit_remote, ref_to_push + ':refs/for/' + branch] | |
| 2975 push_stdout = gclient_utils.CheckCallAndFilter( | |
| 2976 ['git'] + git_command, | |
| 2977 print_stdout=True, | |
| 2978 # Flush after every line: useful for seeing progress when running as | |
| 2979 # recipe. | |
| 2980 filter_fn=lambda _: sys.stdout.flush()) | |
| 2981 | |
| 2982 if options.squash: | |
| 2983 regex = re.compile(r'remote:\s+https?://[\w\-\.\/]*/(\d+)\s.*') | |
| 2984 change_numbers = [m.group(1) | |
| 2985 for m in map(regex.match, push_stdout.splitlines()) | |
| 2986 if m] | |
| 2987 if len(change_numbers) != 1: | |
| 2988 DieWithError( | |
| 2989 ('Created|Updated %d issues on Gerrit, but only 1 expected.\n' | |
| 2990 'Change-Id: %s') % (len(change_numbers), change_id)) | |
| 2991 cl.SetIssue(change_numbers[0]) | |
| 2992 RunGit(['config', 'branch.%s.gerritsquashhash' % cl.GetBranch(), | |
| 2993 ref_to_push]) | |
| 2994 return 0 | |
| 2995 | |
| 2996 | |
| 2997 def GetTargetRef(remote, remote_branch, target_branch, pending_prefix): | 3152 def GetTargetRef(remote, remote_branch, target_branch, pending_prefix): |
| 2998 """Computes the remote branch ref to use for the CL. | 3153 """Computes the remote branch ref to use for the CL. |
| 2999 | 3154 |
| 3000 Args: | 3155 Args: |
| 3001 remote (str): The git remote for the CL. | 3156 remote (str): The git remote for the CL. |
| 3002 remote_branch (str): The git remote branch for the CL. | 3157 remote_branch (str): The git remote branch for the CL. |
| 3003 target_branch (str): The target branch specified by the user. | 3158 target_branch (str): The target branch specified by the user. |
| 3004 pending_prefix (str): The pending prefix from the settings. | 3159 pending_prefix (str): The pending prefix from the settings. |
| 3005 """ | 3160 """ |
| 3006 if not (remote and remote_branch): | 3161 if not (remote and remote_branch): |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3042 remote_branch = remote_branch.replace('refs/remotes/%s/' % remote, | 3197 remote_branch = remote_branch.replace('refs/remotes/%s/' % remote, |
| 3043 'refs/heads/') | 3198 'refs/heads/') |
| 3044 elif remote_branch.startswith('refs/remotes/branch-heads'): | 3199 elif remote_branch.startswith('refs/remotes/branch-heads'): |
| 3045 remote_branch = remote_branch.replace('refs/remotes/', 'refs/') | 3200 remote_branch = remote_branch.replace('refs/remotes/', 'refs/') |
| 3046 # If a pending prefix exists then replace refs/ with it. | 3201 # If a pending prefix exists then replace refs/ with it. |
| 3047 if pending_prefix: | 3202 if pending_prefix: |
| 3048 remote_branch = remote_branch.replace('refs/', pending_prefix) | 3203 remote_branch = remote_branch.replace('refs/', pending_prefix) |
| 3049 return remote_branch | 3204 return remote_branch |
| 3050 | 3205 |
| 3051 | 3206 |
| 3052 def RietveldUpload(options, args, cl, change): | |
| 3053 """upload the patch to rietveld.""" | |
| 3054 upload_args = ['--assume_yes'] # Don't ask about untracked files. | |
| 3055 upload_args.extend(['--server', cl.GetCodereviewServer()]) | |
| 3056 # TODO(tandrii): refactor this ugliness into _RietveldChangelistImpl. | |
| 3057 upload_args.extend(auth.auth_config_to_command_options( | |
| 3058 cl._codereview_impl.GetAuthConfig())) | |
| 3059 if options.emulate_svn_auto_props: | |
| 3060 upload_args.append('--emulate_svn_auto_props') | |
| 3061 | |
| 3062 change_desc = None | |
| 3063 | |
| 3064 if options.email is not None: | |
| 3065 upload_args.extend(['--email', options.email]) | |
| 3066 | |
| 3067 if cl.GetIssue(): | |
| 3068 if options.title: | |
| 3069 upload_args.extend(['--title', options.title]) | |
| 3070 if options.message: | |
| 3071 upload_args.extend(['--message', options.message]) | |
| 3072 upload_args.extend(['--issue', str(cl.GetIssue())]) | |
| 3073 print ("This branch is associated with issue %s. " | |
| 3074 "Adding patch to that issue." % cl.GetIssue()) | |
| 3075 else: | |
| 3076 if options.title: | |
| 3077 upload_args.extend(['--title', options.title]) | |
| 3078 message = options.title or options.message or CreateDescriptionFromLog(args) | |
| 3079 change_desc = ChangeDescription(message) | |
| 3080 if options.reviewers or options.tbr_owners: | |
| 3081 change_desc.update_reviewers(options.reviewers, | |
| 3082 options.tbr_owners, | |
| 3083 change) | |
| 3084 if not options.force: | |
| 3085 change_desc.prompt() | |
| 3086 | |
| 3087 if not change_desc.description: | |
| 3088 print "Description is empty; aborting." | |
| 3089 return 1 | |
| 3090 | |
| 3091 upload_args.extend(['--message', change_desc.description]) | |
| 3092 if change_desc.get_reviewers(): | |
| 3093 upload_args.append('--reviewers=' + ','.join(change_desc.get_reviewers())) | |
| 3094 if options.send_mail: | |
| 3095 if not change_desc.get_reviewers(): | |
| 3096 DieWithError("Must specify reviewers to send email.") | |
| 3097 upload_args.append('--send_mail') | |
| 3098 | |
| 3099 # We check this before applying rietveld.private assuming that in | |
| 3100 # rietveld.cc only addresses which we can send private CLs to are listed | |
| 3101 # if rietveld.private is set, and so we should ignore rietveld.cc only when | |
| 3102 # --private is specified explicitly on the command line. | |
| 3103 if options.private: | |
| 3104 logging.warn('rietveld.cc is ignored since private flag is specified. ' | |
| 3105 'You need to review and add them manually if necessary.') | |
| 3106 cc = cl.GetCCListWithoutDefault() | |
| 3107 else: | |
| 3108 cc = cl.GetCCList() | |
| 3109 cc = ','.join(filter(None, (cc, ','.join(options.cc)))) | |
| 3110 if cc: | |
| 3111 upload_args.extend(['--cc', cc]) | |
| 3112 | |
| 3113 if options.private or settings.GetDefaultPrivateFlag() == "True": | |
| 3114 upload_args.append('--private') | |
| 3115 | |
| 3116 upload_args.extend(['--git_similarity', str(options.similarity)]) | |
| 3117 if not options.find_copies: | |
| 3118 upload_args.extend(['--git_no_find_copies']) | |
| 3119 | |
| 3120 # Include the upstream repo's URL in the change -- this is useful for | |
| 3121 # projects that have their source spread across multiple repos. | |
| 3122 remote_url = cl.GetGitBaseUrlFromConfig() | |
| 3123 if not remote_url: | |
| 3124 if settings.GetIsGitSvn(): | |
| 3125 remote_url = cl.GetGitSvnRemoteUrl() | |
| 3126 else: | |
| 3127 if cl.GetRemoteUrl() and '/' in cl.GetUpstreamBranch(): | |
| 3128 remote_url = (cl.GetRemoteUrl() + '@' | |
| 3129 + cl.GetUpstreamBranch().split('/')[-1]) | |
| 3130 if remote_url: | |
| 3131 upload_args.extend(['--base_url', remote_url]) | |
| 3132 remote, remote_branch = cl.GetRemoteBranch() | |
| 3133 target_ref = GetTargetRef(remote, remote_branch, options.target_branch, | |
| 3134 settings.GetPendingRefPrefix()) | |
| 3135 if target_ref: | |
| 3136 upload_args.extend(['--target_ref', target_ref]) | |
| 3137 | |
| 3138 # Look for dependent patchsets. See crbug.com/480453 for more details. | |
| 3139 remote, upstream_branch = cl.FetchUpstreamTuple(cl.GetBranch()) | |
| 3140 upstream_branch = ShortBranchName(upstream_branch) | |
| 3141 if remote is '.': | |
| 3142 # A local branch is being tracked. | |
| 3143 local_branch = ShortBranchName(upstream_branch) | |
| 3144 if settings.GetIsSkipDependencyUpload(local_branch): | |
| 3145 print | |
| 3146 print ('Skipping dependency patchset upload because git config ' | |
| 3147 'branch.%s.skip-deps-uploads is set to True.' % local_branch) | |
| 3148 print | |
| 3149 else: | |
| 3150 auth_config = auth.extract_auth_config_from_options(options) | |
| 3151 branch_cl = Changelist(branchref=local_branch, auth_config=auth_config) | |
| 3152 branch_cl_issue_url = branch_cl.GetIssueURL() | |
| 3153 branch_cl_issue = branch_cl.GetIssue() | |
| 3154 branch_cl_patchset = branch_cl.GetPatchset() | |
| 3155 if branch_cl_issue_url and branch_cl_issue and branch_cl_patchset: | |
| 3156 upload_args.extend( | |
| 3157 ['--depends_on_patchset', '%s:%s' % ( | |
| 3158 branch_cl_issue, branch_cl_patchset)]) | |
| 3159 print | |
| 3160 print ('The current branch (%s) is tracking a local branch (%s) with ' | |
| 3161 'an associated CL.') % (cl.GetBranch(), local_branch) | |
| 3162 print 'Adding %s/#ps%s as a dependency patchset.' % ( | |
| 3163 branch_cl_issue_url, branch_cl_patchset) | |
| 3164 print | |
| 3165 | |
| 3166 project = settings.GetProject() | |
| 3167 if project: | |
| 3168 upload_args.extend(['--project', project]) | |
| 3169 | |
| 3170 if options.cq_dry_run: | |
| 3171 upload_args.extend(['--cq_dry_run']) | |
| 3172 | |
| 3173 try: | |
| 3174 upload_args = ['upload'] + upload_args + args | |
| 3175 logging.info('upload.RealMain(%s)', upload_args) | |
| 3176 issue, patchset = upload.RealMain(upload_args) | |
| 3177 issue = int(issue) | |
| 3178 patchset = int(patchset) | |
| 3179 except KeyboardInterrupt: | |
| 3180 sys.exit(1) | |
| 3181 except: | |
| 3182 # If we got an exception after the user typed a description for their | |
| 3183 # change, back up the description before re-raising. | |
| 3184 if change_desc: | |
| 3185 backup_path = os.path.expanduser(DESCRIPTION_BACKUP_FILE) | |
| 3186 print '\nGot exception while uploading -- saving description to %s\n' \ | |
| 3187 % backup_path | |
| 3188 backup_file = open(backup_path, 'w') | |
| 3189 backup_file.write(change_desc.description) | |
| 3190 backup_file.close() | |
| 3191 raise | |
| 3192 | |
| 3193 if not cl.GetIssue(): | |
| 3194 cl.SetIssue(issue) | |
| 3195 cl.SetPatchset(patchset) | |
| 3196 | |
| 3197 if options.use_commit_queue: | |
| 3198 cl.SetFlag('commit', '1') | |
| 3199 return 0 | |
| 3200 | |
| 3201 | |
| 3202 def cleanup_list(l): | 3207 def cleanup_list(l): |
| 3203 """Fixes a list so that comma separated items are put as individual items. | 3208 """Fixes a list so that comma separated items are put as individual items. |
| 3204 | 3209 |
| 3205 So that "--reviewers joe@c,john@c --reviewers joa@c" results in | 3210 So that "--reviewers joe@c,john@c --reviewers joa@c" results in |
| 3206 options.reviewers == sorted(['joe@c', 'john@c', 'joa@c']). | 3211 options.reviewers == sorted(['joe@c', 'john@c', 'joa@c']). |
| 3207 """ | 3212 """ |
| 3208 items = sum((i.split(',') for i in l), []) | 3213 items = sum((i.split(',') for i in l), []) |
| 3209 stripped_items = (i.strip() for i in items) | 3214 stripped_items = (i.strip() for i in items) |
| 3210 return sorted(filter(None, stripped_items)) | 3215 return sorted(filter(None, stripped_items)) |
| 3211 | 3216 |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3342 ask_for_data('About to upload; enter to confirm.') | 3347 ask_for_data('About to upload; enter to confirm.') |
| 3343 | 3348 |
| 3344 print_stats(options.similarity, options.find_copies, args) | 3349 print_stats(options.similarity, options.find_copies, args) |
| 3345 if cl.IsGerrit(): | 3350 if cl.IsGerrit(): |
| 3346 if options.squash and options.no_squash: | 3351 if options.squash and options.no_squash: |
| 3347 DieWithError('Can only use one of --squash or --no-squash') | 3352 DieWithError('Can only use one of --squash or --no-squash') |
| 3348 | 3353 |
| 3349 options.squash = ((settings.GetSquashGerritUploads() or options.squash) and | 3354 options.squash = ((settings.GetSquashGerritUploads() or options.squash) and |
| 3350 not options.no_squash) | 3355 not options.no_squash) |
| 3351 | 3356 |
| 3352 ret = GerritUpload(options, args, cl, change) | 3357 ret = cl.CMDUploadChange(options, args, change) |
| 3353 else: | |
| 3354 ret = RietveldUpload(options, args, cl, change) | |
| 3355 if not ret: | 3358 if not ret: |
| 3356 git_set_branch_value('last-upload-hash', | 3359 git_set_branch_value('last-upload-hash', |
| 3357 RunGit(['rev-parse', 'HEAD']).strip()) | 3360 RunGit(['rev-parse', 'HEAD']).strip()) |
| 3358 # Run post upload hooks, if specified. | 3361 # Run post upload hooks, if specified. |
| 3359 if settings.GetRunPostUploadHook(): | 3362 if settings.GetRunPostUploadHook(): |
| 3360 presubmit_support.DoPostUploadExecuter( | 3363 presubmit_support.DoPostUploadExecuter( |
| 3361 change, | 3364 change, |
| 3362 cl, | 3365 cl, |
| 3363 settings.GetRoot(), | 3366 settings.GetRoot(), |
| 3364 options.verbose, | 3367 options.verbose, |
| (...skipping 1269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4634 if __name__ == '__main__': | 4637 if __name__ == '__main__': |
| 4635 # These affect sys.stdout so do it outside of main() to simplify mocks in | 4638 # These affect sys.stdout so do it outside of main() to simplify mocks in |
| 4636 # unit testing. | 4639 # unit testing. |
| 4637 fix_encoding.fix_encoding() | 4640 fix_encoding.fix_encoding() |
| 4638 setup_color.init() | 4641 setup_color.init() |
| 4639 try: | 4642 try: |
| 4640 sys.exit(main(sys.argv[1:])) | 4643 sys.exit(main(sys.argv[1:])) |
| 4641 except KeyboardInterrupt: | 4644 except KeyboardInterrupt: |
| 4642 sys.stderr.write('interrupted\n') | 4645 sys.stderr.write('interrupted\n') |
| 4643 sys.exit(1) | 4646 sys.exit(1) |
| OLD | NEW |