Chromium Code Reviews| 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 __future__ import print_function | 10 from __future__ import print_function |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 57 import rietveld | 57 import rietveld |
| 58 import scm | 58 import scm |
| 59 import subcommand | 59 import subcommand |
| 60 import subprocess2 | 60 import subprocess2 |
| 61 import watchlists | 61 import watchlists |
| 62 | 62 |
| 63 __version__ = '2.0' | 63 __version__ = '2.0' |
| 64 | 64 |
| 65 COMMIT_BOT_EMAIL = 'commit-bot@chromium.org' | 65 COMMIT_BOT_EMAIL = 'commit-bot@chromium.org' |
| 66 DEFAULT_SERVER = 'https://codereview.chromium.org' | 66 DEFAULT_SERVER = 'https://codereview.chromium.org' |
| 67 POSTUPSTREAM_HOOK_PATTERN = '.git/hooks/post-cl-%s' | 67 POSTUPSTREAM_HOOK_PATTERN = '.git/hooks/post-cl-land' |
| 68 DESCRIPTION_BACKUP_FILE = '~/.git_cl_description_backup' | 68 DESCRIPTION_BACKUP_FILE = '~/.git_cl_description_backup' |
| 69 GIT_INSTRUCTIONS_URL = 'http://code.google.com/p/chromium/wiki/UsingGit' | |
| 70 REFS_THAT_ALIAS_TO_OTHER_REFS = { | 69 REFS_THAT_ALIAS_TO_OTHER_REFS = { |
| 71 'refs/remotes/origin/lkgr': 'refs/remotes/origin/master', | 70 'refs/remotes/origin/lkgr': 'refs/remotes/origin/master', |
| 72 'refs/remotes/origin/lkcr': 'refs/remotes/origin/master', | 71 'refs/remotes/origin/lkcr': 'refs/remotes/origin/master', |
| 73 } | 72 } |
| 74 | 73 |
| 75 # Valid extensions for files we want to lint. | 74 # Valid extensions for files we want to lint. |
| 76 DEFAULT_LINT_REGEX = r"(.*\.cpp|.*\.cc|.*\.h)" | 75 DEFAULT_LINT_REGEX = r"(.*\.cpp|.*\.cc|.*\.h)" |
| 77 DEFAULT_LINT_IGNORE_REGEX = r"$^" | 76 DEFAULT_LINT_IGNORE_REGEX = r"$^" |
| 78 | 77 |
| 79 # Shortcut since it quickly becomes redundant. | 78 # Shortcut since it quickly becomes redundant. |
| (...skipping 471 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 551 'failure_reason': build.get('failure_reason'), | 550 'failure_reason': build.get('failure_reason'), |
| 552 'url': build.get('url'), | 551 'url': build.get('url'), |
| 553 } | 552 } |
| 554 | 553 |
| 555 converted = [] | 554 converted = [] |
| 556 for _, build in sorted(builds.items()): | 555 for _, build in sorted(builds.items()): |
| 557 converted.append(convert_build_dict(build)) | 556 converted.append(convert_build_dict(build)) |
| 558 write_json(output_file, converted) | 557 write_json(output_file, converted) |
| 559 | 558 |
| 560 | 559 |
| 561 def MatchSvnGlob(url, base_url, glob_spec, allow_wildcards): | |
| 562 """Return the corresponding git ref if |base_url| together with |glob_spec| | |
| 563 matches the full |url|. | |
| 564 | |
| 565 If |allow_wildcards| is true, |glob_spec| can contain wildcards (see below). | |
| 566 """ | |
| 567 fetch_suburl, as_ref = glob_spec.split(':') | |
| 568 if allow_wildcards: | |
| 569 glob_match = re.match('(.+/)?(\*|{[^/]*})(/.+)?', fetch_suburl) | |
| 570 if glob_match: | |
| 571 # Parse specs like "branches/*/src:refs/remotes/svn/*" or | |
| 572 # "branches/{472,597,648}/src:refs/remotes/svn/*". | |
| 573 branch_re = re.escape(base_url) | |
| 574 if glob_match.group(1): | |
| 575 branch_re += '/' + re.escape(glob_match.group(1)) | |
| 576 wildcard = glob_match.group(2) | |
| 577 if wildcard == '*': | |
| 578 branch_re += '([^/]*)' | |
| 579 else: | |
| 580 # Escape and replace surrounding braces with parentheses and commas | |
| 581 # with pipe symbols. | |
| 582 wildcard = re.escape(wildcard) | |
| 583 wildcard = re.sub('^\\\\{', '(', wildcard) | |
| 584 wildcard = re.sub('\\\\,', '|', wildcard) | |
| 585 wildcard = re.sub('\\\\}$', ')', wildcard) | |
| 586 branch_re += wildcard | |
| 587 if glob_match.group(3): | |
| 588 branch_re += re.escape(glob_match.group(3)) | |
| 589 match = re.match(branch_re, url) | |
| 590 if match: | |
| 591 return re.sub('\*$', match.group(1), as_ref) | |
| 592 | |
| 593 # Parse specs like "trunk/src:refs/remotes/origin/trunk". | |
| 594 if fetch_suburl: | |
| 595 full_url = base_url + '/' + fetch_suburl | |
| 596 else: | |
| 597 full_url = base_url | |
| 598 if full_url == url: | |
| 599 return as_ref | |
| 600 return None | |
| 601 | |
| 602 | |
| 603 def print_stats(similarity, find_copies, args): | 560 def print_stats(similarity, find_copies, args): |
| 604 """Prints statistics about the change to the user.""" | 561 """Prints statistics about the change to the user.""" |
| 605 # --no-ext-diff is broken in some versions of Git, so try to work around | 562 # --no-ext-diff is broken in some versions of Git, so try to work around |
| 606 # this by overriding the environment (but there is still a problem if the | 563 # this by overriding the environment (but there is still a problem if the |
| 607 # git config key "diff.external" is used). | 564 # git config key "diff.external" is used). |
| 608 env = GetNoGitPagerEnv() | 565 env = GetNoGitPagerEnv() |
| 609 if 'GIT_EXTERNAL_DIFF' in env: | 566 if 'GIT_EXTERNAL_DIFF' in env: |
| 610 del env['GIT_EXTERNAL_DIFF'] | 567 del env['GIT_EXTERNAL_DIFF'] |
| 611 | 568 |
| 612 if find_copies: | 569 if find_copies: |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 627 | 584 |
| 628 class BuildbucketResponseException(Exception): | 585 class BuildbucketResponseException(Exception): |
| 629 pass | 586 pass |
| 630 | 587 |
| 631 | 588 |
| 632 class Settings(object): | 589 class Settings(object): |
| 633 def __init__(self): | 590 def __init__(self): |
| 634 self.default_server = None | 591 self.default_server = None |
| 635 self.cc = None | 592 self.cc = None |
| 636 self.root = None | 593 self.root = None |
| 637 self.is_git_svn = None | |
| 638 self.svn_branch = None | |
| 639 self.tree_status_url = None | 594 self.tree_status_url = None |
| 640 self.viewvc_url = None | 595 self.viewvc_url = None |
| 641 self.updated = False | 596 self.updated = False |
| 642 self.is_gerrit = None | 597 self.is_gerrit = None |
| 643 self.squash_gerrit_uploads = None | 598 self.squash_gerrit_uploads = None |
| 644 self.gerrit_skip_ensure_authenticated = None | 599 self.gerrit_skip_ensure_authenticated = None |
| 645 self.git_editor = None | 600 self.git_editor = None |
| 646 self.project = None | 601 self.project = None |
| 647 self.force_https_commit_url = None | 602 self.force_https_commit_url = None |
| 648 self.pending_ref_prefix = None | 603 self.pending_ref_prefix = None |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 691 if not os.path.isdir(local_url): | 646 if not os.path.isdir(local_url): |
| 692 return None | 647 return None |
| 693 git_cache.Mirror.SetCachePath(os.path.dirname(local_url)) | 648 git_cache.Mirror.SetCachePath(os.path.dirname(local_url)) |
| 694 remote_url = git_cache.Mirror.CacheDirToUrl(local_url) | 649 remote_url = git_cache.Mirror.CacheDirToUrl(local_url) |
| 695 # Use the /dev/null print_func to avoid terminal spew in WaitForRealCommit. | 650 # Use the /dev/null print_func to avoid terminal spew in WaitForRealCommit. |
| 696 mirror = git_cache.Mirror(remote_url, print_func = lambda *args: None) | 651 mirror = git_cache.Mirror(remote_url, print_func = lambda *args: None) |
| 697 if mirror.exists(): | 652 if mirror.exists(): |
| 698 return mirror | 653 return mirror |
| 699 return None | 654 return None |
| 700 | 655 |
| 701 def GetIsGitSvn(self): | |
| 702 """Return true if this repo looks like it's using git-svn.""" | |
| 703 if self.is_git_svn is None: | |
| 704 if self.GetPendingRefPrefix(): | |
| 705 # If PENDING_REF_PREFIX is set then it's a pure git repo no matter what. | |
| 706 self.is_git_svn = False | |
| 707 else: | |
| 708 # If you have any "svn-remote.*" config keys, we think you're using svn. | |
| 709 self.is_git_svn = RunGitWithCode( | |
| 710 ['config', '--local', '--get-regexp', r'^svn-remote\.'])[0] == 0 | |
| 711 return self.is_git_svn | |
| 712 | |
| 713 def GetSVNBranch(self): | |
| 714 if self.svn_branch is None: | |
| 715 if not self.GetIsGitSvn(): | |
| 716 DieWithError('Repo doesn\'t appear to be a git-svn repo.') | |
| 717 | |
| 718 # Try to figure out which remote branch we're based on. | |
| 719 # Strategy: | |
| 720 # 1) iterate through our branch history and find the svn URL. | |
| 721 # 2) find the svn-remote that fetches from the URL. | |
| 722 | |
| 723 # regexp matching the git-svn line that contains the URL. | |
| 724 git_svn_re = re.compile(r'^\s*git-svn-id: (\S+)@', re.MULTILINE) | |
| 725 | |
| 726 # We don't want to go through all of history, so read a line from the | |
| 727 # pipe at a time. | |
| 728 # The -100 is an arbitrary limit so we don't search forever. | |
| 729 cmd = ['git', 'log', '-100', '--pretty=medium'] | |
| 730 proc = subprocess2.Popen(cmd, stdout=subprocess2.PIPE, | |
| 731 env=GetNoGitPagerEnv()) | |
| 732 url = None | |
| 733 for line in proc.stdout: | |
| 734 match = git_svn_re.match(line) | |
| 735 if match: | |
| 736 url = match.group(1) | |
| 737 proc.stdout.close() # Cut pipe. | |
| 738 break | |
| 739 | |
| 740 if url: | |
| 741 svn_remote_re = re.compile(r'^svn-remote\.([^.]+)\.url (.*)$') | |
| 742 remotes = RunGit(['config', '--get-regexp', | |
| 743 r'^svn-remote\..*\.url']).splitlines() | |
| 744 for remote in remotes: | |
| 745 match = svn_remote_re.match(remote) | |
| 746 if match: | |
| 747 remote = match.group(1) | |
| 748 base_url = match.group(2) | |
| 749 rewrite_root = RunGit( | |
| 750 ['config', 'svn-remote.%s.rewriteRoot' % remote], | |
| 751 error_ok=True).strip() | |
| 752 if rewrite_root: | |
| 753 base_url = rewrite_root | |
| 754 fetch_spec = RunGit( | |
| 755 ['config', 'svn-remote.%s.fetch' % remote], | |
| 756 error_ok=True).strip() | |
| 757 if fetch_spec: | |
| 758 self.svn_branch = MatchSvnGlob(url, base_url, fetch_spec, False) | |
| 759 if self.svn_branch: | |
| 760 break | |
| 761 branch_spec = RunGit( | |
| 762 ['config', 'svn-remote.%s.branches' % remote], | |
| 763 error_ok=True).strip() | |
| 764 if branch_spec: | |
| 765 self.svn_branch = MatchSvnGlob(url, base_url, branch_spec, True) | |
| 766 if self.svn_branch: | |
| 767 break | |
| 768 tag_spec = RunGit( | |
| 769 ['config', 'svn-remote.%s.tags' % remote], | |
| 770 error_ok=True).strip() | |
| 771 if tag_spec: | |
| 772 self.svn_branch = MatchSvnGlob(url, base_url, tag_spec, True) | |
| 773 if self.svn_branch: | |
| 774 break | |
| 775 | |
| 776 if not self.svn_branch: | |
| 777 DieWithError('Can\'t guess svn branch -- try specifying it on the ' | |
| 778 'command line') | |
| 779 | |
| 780 return self.svn_branch | |
| 781 | |
| 782 def GetTreeStatusUrl(self, error_ok=False): | 656 def GetTreeStatusUrl(self, error_ok=False): |
| 783 if not self.tree_status_url: | 657 if not self.tree_status_url: |
| 784 error_message = ('You must configure your tree status URL by running ' | 658 error_message = ('You must configure your tree status URL by running ' |
| 785 '"git cl config".') | 659 '"git cl config".') |
| 786 self.tree_status_url = self._GetRietveldConfig( | 660 self.tree_status_url = self._GetRietveldConfig( |
| 787 'tree-status-url', error_ok=error_ok, error_message=error_message) | 661 'tree-status-url', error_ok=error_ok, error_message=error_message) |
| 788 return self.tree_status_url | 662 return self.tree_status_url |
| 789 | 663 |
| 790 def GetViewVCUrl(self): | 664 def GetViewVCUrl(self): |
| 791 if not self.viewvc_url: | 665 if not self.viewvc_url: |
| (...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1122 upstream_branch = _git_get_branch_config_value('merge', branch=branch) | 996 upstream_branch = _git_get_branch_config_value('merge', branch=branch) |
| 1123 | 997 |
| 1124 if upstream_branch: | 998 if upstream_branch: |
| 1125 remote = _git_get_branch_config_value('remote', branch=branch) | 999 remote = _git_get_branch_config_value('remote', branch=branch) |
| 1126 else: | 1000 else: |
| 1127 upstream_branch = RunGit(['config', 'rietveld.upstream-branch'], | 1001 upstream_branch = RunGit(['config', 'rietveld.upstream-branch'], |
| 1128 error_ok=True).strip() | 1002 error_ok=True).strip() |
| 1129 if upstream_branch: | 1003 if upstream_branch: |
| 1130 remote = RunGit(['config', 'rietveld.upstream-remote']).strip() | 1004 remote = RunGit(['config', 'rietveld.upstream-remote']).strip() |
| 1131 else: | 1005 else: |
| 1132 # Fall back on trying a git-svn upstream branch. | 1006 # Else, try to guess the origin remote. |
| 1133 if settings.GetIsGitSvn(): | 1007 remote_branches = RunGit(['branch', '-r']).split() |
| 1134 upstream_branch = settings.GetSVNBranch() | 1008 if 'origin/master' in remote_branches: |
| 1009 # Fall back on origin/master if it exits. | |
| 1010 remote = 'origin' | |
| 1011 upstream_branch = 'refs/heads/master' | |
| 1135 else: | 1012 else: |
| 1136 # Else, try to guess the origin remote. | 1013 DieWithError( |
| 1137 remote_branches = RunGit(['branch', '-r']).split() | 1014 'Unable to determine default branch to diff against.\n' |
| 1138 if 'origin/master' in remote_branches: | 1015 'Either pass complete "git diff"-style arguments, like\n' |
| 1139 # Fall back on origin/master if it exits. | 1016 ' git cl upload origin/master\n' |
| 1140 remote = 'origin' | 1017 'or verify this branch is set up to track another \n' |
| 1141 upstream_branch = 'refs/heads/master' | 1018 '(via the --track argument to "git checkout -b ...").') |
| 1142 elif 'origin/trunk' in remote_branches: | |
| 1143 # Fall back on origin/trunk if it exists. Generally a shared | |
| 1144 # git-svn clone | |
| 1145 remote = 'origin' | |
| 1146 upstream_branch = 'refs/heads/trunk' | |
| 1147 else: | |
| 1148 DieWithError( | |
| 1149 'Unable to determine default branch to diff against.\n' | |
| 1150 'Either pass complete "git diff"-style arguments, like\n' | |
| 1151 ' git cl upload origin/master\n' | |
| 1152 'or verify this branch is set up to track another \n' | |
| 1153 '(via the --track argument to "git checkout -b ...").') | |
| 1154 | 1019 |
| 1155 return remote, upstream_branch | 1020 return remote, upstream_branch |
| 1156 | 1021 |
| 1157 def GetCommonAncestorWithUpstream(self): | 1022 def GetCommonAncestorWithUpstream(self): |
| 1158 upstream_branch = self.GetUpstreamBranch() | 1023 upstream_branch = self.GetUpstreamBranch() |
| 1159 if not BranchExists(upstream_branch): | 1024 if not BranchExists(upstream_branch): |
| 1160 DieWithError('The upstream for the current branch (%s) does not exist ' | 1025 DieWithError('The upstream for the current branch (%s) does not exist ' |
| 1161 'anymore.\nPlease fix it and try again.' % self.GetBranch()) | 1026 'anymore.\nPlease fix it and try again.' % self.GetBranch()) |
| 1162 return git_common.get_or_create_merge_base(self.GetBranch(), | 1027 return git_common.get_or_create_merge_base(self.GetBranch(), |
| 1163 upstream_branch) | 1028 upstream_branch) |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 1182 remote, branch = self.FetchUpstreamTuple(branch) | 1047 remote, branch = self.FetchUpstreamTuple(branch) |
| 1183 branch = ShortBranchName(branch) | 1048 branch = ShortBranchName(branch) |
| 1184 if remote != '.' or branch.startswith('refs/remotes'): | 1049 if remote != '.' or branch.startswith('refs/remotes'): |
| 1185 break | 1050 break |
| 1186 else: | 1051 else: |
| 1187 remotes = RunGit(['remote'], error_ok=True).split() | 1052 remotes = RunGit(['remote'], error_ok=True).split() |
| 1188 if len(remotes) == 1: | 1053 if len(remotes) == 1: |
| 1189 remote, = remotes | 1054 remote, = remotes |
| 1190 elif 'origin' in remotes: | 1055 elif 'origin' in remotes: |
| 1191 remote = 'origin' | 1056 remote = 'origin' |
| 1192 logging.warning('Could not determine which remote this change is ' | 1057 logging.warn('Could not determine which remote this change is ' |
| 1193 'associated with, so defaulting to "%s". This may ' | 1058 'associated with, so defaulting to "%s".' % self._remote) |
| 1194 'not be what you want. You may prevent this message ' | |
| 1195 'by running "git svn info" as documented here: %s', | |
| 1196 self._remote, | |
| 1197 GIT_INSTRUCTIONS_URL) | |
| 1198 else: | 1059 else: |
| 1199 logging.warn('Could not determine which remote this change is ' | 1060 logging.warn('Could not determine which remote this change is ' |
| 1200 'associated with. You may prevent this message by ' | 1061 'associated with.') |
| 1201 'running "git svn info" as documented here: %s', | |
| 1202 GIT_INSTRUCTIONS_URL) | |
| 1203 branch = 'HEAD' | 1062 branch = 'HEAD' |
| 1204 if branch.startswith('refs/remotes'): | 1063 if branch.startswith('refs/remotes'): |
| 1205 self._remote = (remote, branch) | 1064 self._remote = (remote, branch) |
| 1206 elif branch.startswith('refs/branch-heads/'): | 1065 elif branch.startswith('refs/branch-heads/'): |
| 1207 self._remote = (remote, branch.replace('refs/', 'refs/remotes/')) | 1066 self._remote = (remote, branch.replace('refs/', 'refs/remotes/')) |
| 1208 else: | 1067 else: |
| 1209 self._remote = (remote, 'refs/remotes/%s/%s' % (remote, branch)) | 1068 self._remote = (remote, 'refs/remotes/%s/%s' % (remote, branch)) |
| 1210 return self._remote | 1069 return self._remote |
| 1211 | 1070 |
| 1212 def GitSanityChecks(self, upstream_git_obj): | 1071 def GitSanityChecks(self, upstream_git_obj): |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1251 return False | 1110 return False |
| 1252 return True | 1111 return True |
| 1253 | 1112 |
| 1254 def GetGitBaseUrlFromConfig(self): | 1113 def GetGitBaseUrlFromConfig(self): |
| 1255 """Return the configured base URL from branch.<branchname>.baseurl. | 1114 """Return the configured base URL from branch.<branchname>.baseurl. |
| 1256 | 1115 |
| 1257 Returns None if it is not set. | 1116 Returns None if it is not set. |
| 1258 """ | 1117 """ |
| 1259 return self._GitGetBranchConfigValue('base-url') | 1118 return self._GitGetBranchConfigValue('base-url') |
| 1260 | 1119 |
| 1261 def GetGitSvnRemoteUrl(self): | |
| 1262 """Return the configured git-svn remote URL parsed from git svn info. | |
| 1263 | |
| 1264 Returns None if it is not set. | |
| 1265 """ | |
| 1266 # URL is dependent on the current directory. | |
| 1267 data = RunGit(['svn', 'info'], cwd=settings.GetRoot()) | |
| 1268 if data: | |
| 1269 keys = dict(line.split(': ', 1) for line in data.splitlines() | |
| 1270 if ': ' in line) | |
| 1271 return keys.get('URL', None) | |
| 1272 return None | |
| 1273 | |
| 1274 def GetRemoteUrl(self): | 1120 def GetRemoteUrl(self): |
| 1275 """Return the configured remote URL, e.g. 'git://example.org/foo.git/'. | 1121 """Return the configured remote URL, e.g. 'git://example.org/foo.git/'. |
| 1276 | 1122 |
| 1277 Returns None if there is no remote. | 1123 Returns None if there is no remote. |
| 1278 """ | 1124 """ |
| 1279 remote, _ = self.GetRemoteBranch() | 1125 remote, _ = self.GetRemoteBranch() |
| 1280 url = RunGit(['config', 'remote.%s.url' % remote], error_ok=True).strip() | 1126 url = RunGit(['config', 'remote.%s.url' % remote], error_ok=True).strip() |
| 1281 | 1127 |
| 1282 # If URL is pointing to a local directory, it is probably a git cache. | 1128 # If URL is pointing to a local directory, it is probably a git cache. |
| 1283 if os.path.isdir(url): | 1129 if os.path.isdir(url): |
| (...skipping 750 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2034 upload_args.append('--private') | 1880 upload_args.append('--private') |
| 2035 | 1881 |
| 2036 upload_args.extend(['--git_similarity', str(options.similarity)]) | 1882 upload_args.extend(['--git_similarity', str(options.similarity)]) |
| 2037 if not options.find_copies: | 1883 if not options.find_copies: |
| 2038 upload_args.extend(['--git_no_find_copies']) | 1884 upload_args.extend(['--git_no_find_copies']) |
| 2039 | 1885 |
| 2040 # Include the upstream repo's URL in the change -- this is useful for | 1886 # Include the upstream repo's URL in the change -- this is useful for |
| 2041 # projects that have their source spread across multiple repos. | 1887 # projects that have their source spread across multiple repos. |
| 2042 remote_url = self.GetGitBaseUrlFromConfig() | 1888 remote_url = self.GetGitBaseUrlFromConfig() |
| 2043 if not remote_url: | 1889 if not remote_url: |
| 2044 if settings.GetIsGitSvn(): | 1890 if self.GetRemoteUrl() and '/' in self.GetUpstreamBranch(): |
| 2045 remote_url = self.GetGitSvnRemoteUrl() | 1891 remote_url = '%s@%s' % (self.GetRemoteUrl(), |
| 2046 else: | 1892 self.GetUpstreamBranch().split('/')[-1]) |
| 2047 if self.GetRemoteUrl() and '/' in self.GetUpstreamBranch(): | |
| 2048 remote_url = '%s@%s' % (self.GetRemoteUrl(), | |
| 2049 self.GetUpstreamBranch().split('/')[-1]) | |
| 2050 if remote_url: | 1893 if remote_url: |
| 2051 remote, remote_branch = self.GetRemoteBranch() | 1894 remote, remote_branch = self.GetRemoteBranch() |
| 2052 target_ref = GetTargetRef(remote, remote_branch, options.target_branch, | 1895 target_ref = GetTargetRef(remote, remote_branch, options.target_branch, |
| 2053 settings.GetPendingRefPrefix()) | 1896 settings.GetPendingRefPrefix()) |
| 2054 if target_ref: | 1897 if target_ref: |
| 2055 upload_args.extend(['--target_ref', target_ref]) | 1898 upload_args.extend(['--target_ref', target_ref]) |
| 2056 | 1899 |
| 2057 # Look for dependent patchsets. See crbug.com/480453 for more details. | 1900 # Look for dependent patchsets. See crbug.com/480453 for more details. |
| 2058 remote, upstream_branch = self.FetchUpstreamTuple(self.GetBranch()) | 1901 remote, upstream_branch = self.FetchUpstreamTuple(self.GetBranch()) |
| 2059 upstream_branch = ShortBranchName(upstream_branch) | 1902 upstream_branch = ShortBranchName(upstream_branch) |
| (...skipping 1917 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3977 if options.cq_dry_run and options.use_commit_queue: | 3820 if options.cq_dry_run and options.use_commit_queue: |
| 3978 parser.error('only one of --use-commit-queue and --cq-dry-run allowed.') | 3821 parser.error('only one of --use-commit-queue and --cq-dry-run allowed.') |
| 3979 | 3822 |
| 3980 # For sanity of test expectations, do this otherwise lazy-loading *now*. | 3823 # For sanity of test expectations, do this otherwise lazy-loading *now*. |
| 3981 settings.GetIsGerrit() | 3824 settings.GetIsGerrit() |
| 3982 | 3825 |
| 3983 cl = Changelist(auth_config=auth_config, codereview=options.forced_codereview) | 3826 cl = Changelist(auth_config=auth_config, codereview=options.forced_codereview) |
| 3984 return cl.CMDUpload(options, args, orig_args) | 3827 return cl.CMDUpload(options, args, orig_args) |
| 3985 | 3828 |
| 3986 | 3829 |
| 3987 def IsSubmoduleMergeCommit(ref): | |
| 3988 # When submodules are added to the repo, we expect there to be a single | |
| 3989 # non-git-svn merge commit at remote HEAD with a signature comment. | |
| 3990 pattern = '^SVN changes up to revision [0-9]*$' | |
| 3991 cmd = ['rev-list', '--merges', '--grep=%s' % pattern, '%s^!' % ref] | |
| 3992 return RunGit(cmd) != '' | |
| 3993 | |
| 3994 | |
| 3995 def SendUpstream(parser, args, cmd): | 3830 def SendUpstream(parser, args, cmd): |
| 3996 """Common code for CMDland and CmdDCommit | 3831 """Common code for CMDland and CmdDCommit |
| 3997 | 3832 |
| 3998 In case of Gerrit, uses Gerrit REST api to "submit" the issue, which pushes | 3833 In case of Gerrit, uses Gerrit REST api to "submit" the issue, which pushes |
| 3999 upstream and closes the issue automatically and atomically. | 3834 upstream and closes the issue automatically and atomically. |
| 4000 | 3835 |
| 4001 Otherwise (in case of Rietveld): | 3836 Otherwise (in case of Rietveld): |
| 4002 Squashes branch into a single commit. | 3837 Squashes branch into a single commit. |
| 4003 Updates changelog with metadata (e.g. pointer to review). | 3838 Updates changelog with metadata (e.g. pointer to review). |
| 4004 Pushes/dcommits the code upstream. | 3839 Pushes/dcommits the code upstream. |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4038 '"Forge-Author" permission.') | 3873 '"Forge-Author" permission.') |
| 4039 if not cl.GetIssue(): | 3874 if not cl.GetIssue(): |
| 4040 DieWithError('You must upload the issue first to Gerrit.\n' | 3875 DieWithError('You must upload the issue first to Gerrit.\n' |
| 4041 ' If you would rather have `git cl land` upload ' | 3876 ' If you would rather have `git cl land` upload ' |
| 4042 'automatically for you, see http://crbug.com/642759') | 3877 'automatically for you, see http://crbug.com/642759') |
| 4043 return cl._codereview_impl.CMDLand(options.force, options.bypass_hooks, | 3878 return cl._codereview_impl.CMDLand(options.force, options.bypass_hooks, |
| 4044 options.verbose) | 3879 options.verbose) |
| 4045 | 3880 |
| 4046 current = cl.GetBranch() | 3881 current = cl.GetBranch() |
| 4047 remote, upstream_branch = cl.FetchUpstreamTuple(cl.GetBranch()) | 3882 remote, upstream_branch = cl.FetchUpstreamTuple(cl.GetBranch()) |
| 4048 if not settings.GetIsGitSvn() and remote == '.': | 3883 if remote == '.': |
| 4049 print() | 3884 print() |
| 4050 print('Attempting to push branch %r into another local branch!' % current) | 3885 print('Attempting to push branch %r into another local branch!' % current) |
| 4051 print() | 3886 print() |
| 4052 print('Either reparent this branch on top of origin/master:') | 3887 print('Either reparent this branch on top of origin/master:') |
| 4053 print(' git reparent-branch --root') | 3888 print(' git reparent-branch --root') |
| 4054 print() | 3889 print() |
| 4055 print('OR run `git rebase-update` if you think the parent branch is ') | 3890 print('OR run `git rebase-update` if you think the parent branch is ') |
| 4056 print('already committed.') | 3891 print('already committed.') |
| 4057 print() | 3892 print() |
| 4058 print(' Current parent: %r' % upstream_branch) | 3893 print(' Current parent: %r' % upstream_branch) |
| 4059 return 1 | 3894 return 1 |
| 4060 | 3895 |
| 4061 if not args or cmd == 'land': | 3896 if not args: |
| 4062 # Default to merging against our best guess of the upstream branch. | 3897 # Default to merging against our best guess of the upstream branch. |
| 4063 args = [cl.GetUpstreamBranch()] | 3898 args = [cl.GetUpstreamBranch()] |
| 4064 | 3899 |
| 4065 if options.contributor: | 3900 if options.contributor: |
| 4066 if not re.match('^.*\s<\S+@\S+>$', options.contributor): | 3901 if not re.match('^.*\s<\S+@\S+>$', options.contributor): |
| 4067 print("Please provide contibutor as 'First Last <email@example.com>'") | 3902 print("Please provide contibutor as 'First Last <email@example.com>'") |
| 4068 return 1 | 3903 return 1 |
| 4069 | 3904 |
| 4070 base_branch = args[0] | 3905 base_branch = args[0] |
| 4071 base_has_submodules = IsSubmoduleMergeCommit(base_branch) | |
| 4072 | 3906 |
| 4073 if git_common.is_dirty_git_tree(cmd): | 3907 if git_common.is_dirty_git_tree('land'): |
| 4074 return 1 | 3908 return 1 |
| 4075 | 3909 |
| 4076 # This rev-list syntax means "show all commits not in my branch that | 3910 # This rev-list syntax means "show all commits not in my branch that |
| 4077 # are in base_branch". | 3911 # are in base_branch". |
| 4078 upstream_commits = RunGit(['rev-list', '^' + cl.GetBranchRef(), | 3912 upstream_commits = RunGit(['rev-list', '^' + cl.GetBranchRef(), |
| 4079 base_branch]).splitlines() | 3913 base_branch]).splitlines() |
| 4080 if upstream_commits: | 3914 if upstream_commits: |
| 4081 print('Base branch "%s" has %d commits ' | 3915 print('Base branch "%s" has %d commits ' |
| 4082 'not in this branch.' % (base_branch, len(upstream_commits))) | 3916 'not in this branch.' % (base_branch, len(upstream_commits))) |
| 4083 print('Run "git merge %s" before attempting to %s.' % (base_branch, cmd)) | 3917 print('Run "git merge %s" before attempting to land.' % base_branch) |
| 4084 return 1 | 3918 return 1 |
| 4085 | 3919 |
| 4086 # This is the revision `svn dcommit` will commit on top of. | |
| 4087 svn_head = None | |
| 4088 if cmd == 'dcommit' or base_has_submodules: | |
| 4089 svn_head = RunGit(['log', '--grep=^git-svn-id:', '-1', | |
| 4090 '--pretty=format:%H']) | |
| 4091 | |
| 4092 if cmd == 'dcommit': | |
| 4093 # If the base_head is a submodule merge commit, the first parent of the | |
| 4094 # base_head should be a git-svn commit, which is what we're interested in. | |
| 4095 base_svn_head = base_branch | |
| 4096 if base_has_submodules: | |
| 4097 base_svn_head += '^1' | |
| 4098 | |
| 4099 extra_commits = RunGit(['rev-list', '^' + svn_head, base_svn_head]) | |
| 4100 if extra_commits: | |
| 4101 print('This branch has %d additional commits not upstreamed yet.' | |
| 4102 % len(extra_commits.splitlines())) | |
| 4103 print('Upstream "%s" or rebase this branch on top of the upstream trunk ' | |
| 4104 'before attempting to %s.' % (base_branch, cmd)) | |
| 4105 return 1 | |
| 4106 | |
| 4107 merge_base = RunGit(['merge-base', base_branch, 'HEAD']).strip() | 3920 merge_base = RunGit(['merge-base', base_branch, 'HEAD']).strip() |
| 4108 if not options.bypass_hooks: | 3921 if not options.bypass_hooks: |
| 4109 author = None | 3922 author = None |
| 4110 if options.contributor: | 3923 if options.contributor: |
| 4111 author = re.search(r'\<(.*)\>', options.contributor).group(1) | 3924 author = re.search(r'\<(.*)\>', options.contributor).group(1) |
| 4112 hook_results = cl.RunHook( | 3925 hook_results = cl.RunHook( |
| 4113 committing=True, | 3926 committing=True, |
| 4114 may_prompt=not options.force, | 3927 may_prompt=not options.force, |
| 4115 verbose=options.verbose, | 3928 verbose=options.verbose, |
| 4116 change=cl.GetChange(merge_base, author)) | 3929 change=cl.GetChange(merge_base, author)) |
| 4117 if not hook_results.should_continue(): | 3930 if not hook_results.should_continue(): |
| 4118 return 1 | 3931 return 1 |
| 4119 | 3932 |
| 4120 # Check the tree status if the tree status URL is set. | 3933 # Check the tree status if the tree status URL is set. |
| 4121 status = GetTreeStatus() | 3934 status = GetTreeStatus() |
| 4122 if 'closed' == status: | 3935 if 'closed' == status: |
| 4123 print('The tree is closed. Please wait for it to reopen. Use ' | 3936 print('The tree is closed. Please wait for it to reopen. Use ' |
| 4124 '"git cl %s --bypass-hooks" to commit on a closed tree.' % cmd) | 3937 '"git cl land --bypass-hooks" to commit on a closed tree.') |
| 4125 return 1 | 3938 return 1 |
| 4126 elif 'unknown' == status: | 3939 elif 'unknown' == status: |
| 4127 print('Unable to determine tree status. Please verify manually and ' | 3940 print('Unable to determine tree status. Please verify manually and ' |
| 4128 'use "git cl %s --bypass-hooks" to commit on a closed tree.' % cmd) | 3941 'use "git cl land --bypass-hooks" to commit on a closed tree.') |
| 4129 return 1 | 3942 return 1 |
| 4130 | 3943 |
| 4131 change_desc = ChangeDescription(options.message) | 3944 change_desc = ChangeDescription(options.message) |
| 4132 if not change_desc.description and cl.GetIssue(): | 3945 if not change_desc.description and cl.GetIssue(): |
| 4133 change_desc = ChangeDescription(cl.GetDescription()) | 3946 change_desc = ChangeDescription(cl.GetDescription()) |
| 4134 | 3947 |
| 4135 if not change_desc.description: | 3948 if not change_desc.description: |
| 4136 if not cl.GetIssue() and options.bypass_hooks: | 3949 if not cl.GetIssue() and options.bypass_hooks: |
| 4137 change_desc = ChangeDescription(CreateDescriptionFromLog([merge_base])) | 3950 change_desc = ChangeDescription(CreateDescriptionFromLog([merge_base])) |
| 4138 else: | 3951 else: |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 4159 | 3972 |
| 4160 print('Description:') | 3973 print('Description:') |
| 4161 print(commit_desc.description) | 3974 print(commit_desc.description) |
| 4162 | 3975 |
| 4163 branches = [merge_base, cl.GetBranchRef()] | 3976 branches = [merge_base, cl.GetBranchRef()] |
| 4164 if not options.force: | 3977 if not options.force: |
| 4165 print_stats(options.similarity, options.find_copies, branches) | 3978 print_stats(options.similarity, options.find_copies, branches) |
| 4166 | 3979 |
| 4167 # We want to squash all this branch's commits into one commit with the proper | 3980 # We want to squash all this branch's commits into one commit with the proper |
| 4168 # description. We do this by doing a "reset --soft" to the base branch (which | 3981 # description. We do this by doing a "reset --soft" to the base branch (which |
| 4169 # keeps the working copy the same), then dcommitting that. If origin/master | 3982 # keeps the working copy the same), then dcommitting that. |
| 4170 # has a submodule merge commit, we'll also need to cherry-pick the squashed | |
| 4171 # commit onto a branch based on the git-svn head. | |
| 4172 MERGE_BRANCH = 'git-cl-commit' | 3983 MERGE_BRANCH = 'git-cl-commit' |
| 4173 CHERRY_PICK_BRANCH = 'git-cl-cherry-pick' | 3984 CHERRY_PICK_BRANCH = 'git-cl-cherry-pick' |
| 4174 # Delete the branches if they exist. | 3985 # Delete the branches if they exist. |
| 4175 for branch in [MERGE_BRANCH, CHERRY_PICK_BRANCH]: | 3986 for branch in [MERGE_BRANCH, CHERRY_PICK_BRANCH]: |
| 4176 showref_cmd = ['show-ref', '--quiet', '--verify', 'refs/heads/%s' % branch] | 3987 showref_cmd = ['show-ref', '--quiet', '--verify', 'refs/heads/%s' % branch] |
| 4177 result = RunGitWithCode(showref_cmd) | 3988 result = RunGitWithCode(showref_cmd) |
| 4178 if result[0] == 0: | 3989 if result[0] == 0: |
| 4179 RunGit(['branch', '-D', branch]) | 3990 RunGit(['branch', '-D', branch]) |
| 4180 | 3991 |
| 4181 # We might be in a directory that's present in this branch but not in the | 3992 # We might be in a directory that's present in this branch but not in the |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 4196 RunGit(['checkout', '-q', '-b', MERGE_BRANCH]) | 4007 RunGit(['checkout', '-q', '-b', MERGE_BRANCH]) |
| 4197 RunGit(['reset', '--soft', merge_base]) | 4008 RunGit(['reset', '--soft', merge_base]) |
| 4198 if options.contributor: | 4009 if options.contributor: |
| 4199 RunGit( | 4010 RunGit( |
| 4200 [ | 4011 [ |
| 4201 'commit', '--author', options.contributor, | 4012 'commit', '--author', options.contributor, |
| 4202 '-m', commit_desc.description, | 4013 '-m', commit_desc.description, |
| 4203 ]) | 4014 ]) |
| 4204 else: | 4015 else: |
| 4205 RunGit(['commit', '-m', commit_desc.description]) | 4016 RunGit(['commit', '-m', commit_desc.description]) |
| 4206 if base_has_submodules: | 4017 remote, branch = cl.FetchUpstreamTuple(cl.GetBranch()) |
| 4207 cherry_pick_commit = RunGit(['rev-list', 'HEAD^!']).rstrip() | 4018 mirror = settings.GetGitMirror(remote) |
| 4208 RunGit(['branch', CHERRY_PICK_BRANCH, svn_head]) | 4019 pushurl = mirror.url if mirror else remote |
| 4209 RunGit(['checkout', CHERRY_PICK_BRANCH]) | 4020 pending_prefix = settings.GetPendingRefPrefix() |
| 4210 RunGit(['cherry-pick', cherry_pick_commit]) | 4021 if not pending_prefix or branch.startswith(pending_prefix): |
| 4211 if cmd == 'land': | 4022 # If not using refs/pending/heads/* at all, or target ref is already set |
| 4212 remote, branch = cl.FetchUpstreamTuple(cl.GetBranch()) | 4023 # to pending, then push to the target ref directly. |
| 4213 mirror = settings.GetGitMirror(remote) | 4024 retcode, output = RunGitWithCode( |
| 4214 pushurl = mirror.url if mirror else remote | 4025 ['push', '--porcelain', pushurl, 'HEAD:%s' % branch]) |
| 4215 pending_prefix = settings.GetPendingRefPrefix() | 4026 pushed_to_pending = pending_prefix and branch.startswith(pending_prefix) |
| 4216 if not pending_prefix or branch.startswith(pending_prefix): | |
| 4217 # If not using refs/pending/heads/* at all, or target ref is already set | |
| 4218 # to pending, then push to the target ref directly. | |
| 4219 retcode, output = RunGitWithCode( | |
| 4220 ['push', '--porcelain', pushurl, 'HEAD:%s' % branch]) | |
| 4221 pushed_to_pending = pending_prefix and branch.startswith(pending_prefix) | |
| 4222 else: | |
| 4223 # Cherry-pick the change on top of pending ref and then push it. | |
| 4224 assert branch.startswith('refs/'), branch | |
| 4225 assert pending_prefix[-1] == '/', pending_prefix | |
| 4226 pending_ref = pending_prefix + branch[len('refs/'):] | |
| 4227 retcode, output = PushToGitPending(pushurl, pending_ref) | |
| 4228 pushed_to_pending = (retcode == 0) | |
| 4229 if retcode == 0: | |
| 4230 revision = RunGit(['rev-parse', 'HEAD']).strip() | |
| 4231 else: | 4027 else: |
| 4232 # dcommit the merge branch. | 4028 # Cherry-pick the change on top of pending ref and then push it. |
| 4233 cmd_args = [ | 4029 assert branch.startswith('refs/'), branch |
| 4234 'svn', 'dcommit', | 4030 assert pending_prefix[-1] == '/', pending_prefix |
| 4235 '-C%s' % options.similarity, | 4031 pending_ref = pending_prefix + branch[len('refs/'):] |
| 4236 '--no-rebase', '--rmdir', | 4032 retcode, output = PushToGitPending(pushurl, pending_ref) |
| 4237 ] | 4033 pushed_to_pending = (retcode == 0) |
| 4238 if settings.GetForceHttpsCommitUrl(): | 4034 if retcode == 0: |
| 4239 # Allow forcing https commit URLs for some projects that don't allow | 4035 revision = RunGit(['rev-parse', 'HEAD']).strip() |
| 4240 # committing to http URLs (like Google Code). | |
| 4241 remote_url = cl.GetGitSvnRemoteUrl() | |
| 4242 if urlparse.urlparse(remote_url).scheme == 'http': | |
| 4243 remote_url = remote_url.replace('http://', 'https://') | |
| 4244 cmd_args.append('--commit-url=%s' % remote_url) | |
| 4245 _, output = RunGitWithCode(cmd_args) | |
| 4246 if 'Committed r' in output: | |
| 4247 revision = re.match( | |
| 4248 '.*?\nCommitted r(\\d+)', output, re.DOTALL).group(1) | |
| 4249 logging.debug(output) | 4036 logging.debug(output) |
| 4250 finally: | 4037 finally: |
| 4251 # And then swap back to the original branch and clean up. | 4038 # And then swap back to the original branch and clean up. |
| 4252 RunGit(['checkout', '-q', cl.GetBranch()]) | 4039 RunGit(['checkout', '-q', cl.GetBranch()]) |
| 4253 RunGit(['branch', '-D', MERGE_BRANCH]) | 4040 RunGit(['branch', '-D', MERGE_BRANCH]) |
| 4254 if base_has_submodules: | |
| 4255 RunGit(['branch', '-D', CHERRY_PICK_BRANCH]) | |
| 4256 | 4041 |
| 4257 if not revision: | 4042 if not revision: |
| 4258 print('Failed to push. If this persists, please file a bug.') | 4043 print('Failed to push. If this persists, please file a bug.') |
| 4259 return 1 | 4044 return 1 |
| 4260 | 4045 |
| 4261 killed = False | 4046 killed = False |
| 4262 if pushed_to_pending: | 4047 if pushed_to_pending: |
| 4263 try: | 4048 try: |
| 4264 revision = WaitForRealCommit(remote, revision, base_branch, branch) | 4049 revision = WaitForRealCommit(remote, revision, base_branch, branch) |
| 4265 # We set pushed_to_pending to False, since it made it all the way to the | 4050 # We set pushed_to_pending to False, since it made it all the way to the |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 4290 else: | 4075 else: |
| 4291 comment += ' (presubmit successful).' | 4076 comment += ' (presubmit successful).' |
| 4292 cl.RpcServer().add_comment(cl.GetIssue(), comment) | 4077 cl.RpcServer().add_comment(cl.GetIssue(), comment) |
| 4293 | 4078 |
| 4294 if pushed_to_pending: | 4079 if pushed_to_pending: |
| 4295 _, branch = cl.FetchUpstreamTuple(cl.GetBranch()) | 4080 _, branch = cl.FetchUpstreamTuple(cl.GetBranch()) |
| 4296 print('The commit is in the pending queue (%s).' % pending_ref) | 4081 print('The commit is in the pending queue (%s).' % pending_ref) |
| 4297 print('It will show up on %s in ~1 min, once it gets a Cr-Commit-Position ' | 4082 print('It will show up on %s in ~1 min, once it gets a Cr-Commit-Position ' |
| 4298 'footer.' % branch) | 4083 'footer.' % branch) |
| 4299 | 4084 |
| 4300 hook = POSTUPSTREAM_HOOK_PATTERN % cmd | 4085 hook = POSTUPSTREAM_HOOK_PATTERN |
| 4301 if os.path.isfile(hook): | 4086 if os.path.isfile(hook): |
| 4302 RunCommand([hook, merge_base], error_ok=True) | 4087 RunCommand([hook, merge_base], error_ok=True) |
| 4303 | 4088 |
| 4304 return 1 if killed else 0 | 4089 return 1 if killed else 0 |
| 4305 | 4090 |
| 4306 | 4091 |
| 4307 def WaitForRealCommit(remote, pushed_commit, local_base_ref, real_ref): | 4092 def WaitForRealCommit(remote, pushed_commit, local_base_ref, real_ref): |
| 4308 print() | 4093 print() |
| 4309 print('Waiting for commit to be landed on %s...' % real_ref) | 4094 print('Waiting for commit to be landed on %s...' % real_ref) |
| 4310 print('(If you are impatient, you may Ctrl-C once without harm)') | 4095 print('(If you are impatient, you may Ctrl-C once without harm)') |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4392 return code, out | 4177 return code, out |
| 4393 | 4178 |
| 4394 | 4179 |
| 4395 def IsFatalPushFailure(push_stdout): | 4180 def IsFatalPushFailure(push_stdout): |
| 4396 """True if retrying push won't help.""" | 4181 """True if retrying push won't help.""" |
| 4397 return '(prohibited by Gerrit)' in push_stdout | 4182 return '(prohibited by Gerrit)' in push_stdout |
| 4398 | 4183 |
| 4399 | 4184 |
| 4400 @subcommand.usage('[upstream branch to apply against]') | 4185 @subcommand.usage('[upstream branch to apply against]') |
| 4401 def CMDdcommit(parser, args): | 4186 def CMDdcommit(parser, args): |
| 4402 """Commits the current changelist via git-svn.""" | 4187 """DEPRECATED: Used to commit the current changelist via git-svn.""" |
| 4403 if not settings.GetIsGitSvn(): | 4188 message = ('git-cl no longer supports committing to SVN repositories via' |
| 4404 if git_footers.get_footer_svn_id(): | 4189 'git-svn. You probably want to use `git cl land` instead.') |
| 4405 # If it looks like previous commits were mirrored with git-svn. | 4190 print(message) |
|
tandrii(chromium)
2016/10/06 08:04:01
I'd add return 1 so command results in error.
agable
2016/10/06 21:43:15
Done.
| |
| 4406 message = """This repository appears to be a git-svn mirror, but we | |
| 4407 don't support git-svn mirrors anymore.""" | |
| 4408 else: | |
| 4409 message = """This doesn't appear to be an SVN repository. | |
| 4410 If your project has a true, writeable git repository, you probably want to run | |
| 4411 'git cl land' instead. | |
| 4412 If your project has a git mirror of an upstream SVN master, you probably need | |
| 4413 to run 'git svn init'. | |
| 4414 | |
| 4415 Using the wrong command might cause your commit to appear to succeed, and the | |
| 4416 review to be closed, without actually landing upstream. If you choose to | |
| 4417 proceed, please verify that the commit lands upstream as expected.""" | |
| 4418 print(message) | |
| 4419 ask_for_data('[Press enter to dcommit or ctrl-C to quit]') | |
| 4420 print('WARNING: chrome infrastructure is migrating SVN repos to Git.\n' | |
| 4421 'Please let us know of this project you are committing to:' | |
| 4422 ' http://crbug.com/600451') | |
| 4423 return SendUpstream(parser, args, 'dcommit') | |
| 4424 | 4191 |
| 4425 | 4192 |
| 4426 @subcommand.usage('[upstream branch to apply against]') | 4193 @subcommand.usage('[upstream branch to apply against]') |
| 4427 def CMDland(parser, args): | 4194 def CMDland(parser, args): |
| 4428 """Commits the current changelist via git.""" | 4195 """Commits the current changelist via git.""" |
| 4429 if settings.GetIsGitSvn() or git_footers.get_footer_svn_id(): | |
| 4430 print('This appears to be an SVN repository.') | |
| 4431 print('Are you sure you didn\'t mean \'git cl dcommit\'?') | |
| 4432 print('(Ignore if this is the first commit after migrating from svn->git)') | |
| 4433 ask_for_data('[Press enter to push or ctrl-C to quit]') | |
| 4434 return SendUpstream(parser, args, 'land') | 4196 return SendUpstream(parser, args, 'land') |
| 4435 | 4197 |
| 4436 | 4198 |
| 4437 @subcommand.usage('<patch url or issue id or issue url>') | 4199 @subcommand.usage('<patch url or issue id or issue url>') |
| 4438 def CMDpatch(parser, args): | 4200 def CMDpatch(parser, args): |
| 4439 """Patches in a code review.""" | 4201 """Patches in a code review.""" |
| 4440 parser.add_option('-b', dest='newbranch', | 4202 parser.add_option('-b', dest='newbranch', |
| 4441 help='create a new branch off trunk for the patch') | 4203 help='create a new branch off trunk for the patch') |
| 4442 parser.add_option('-f', '--force', action='store_true', | 4204 parser.add_option('-f', '--force', action='store_true', |
| 4443 help='with -b, clobber any existing branch') | 4205 help='with -b, clobber any existing branch') |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4517 parser.error('--reject is not supported with Gerrit codereview.') | 4279 parser.error('--reject is not supported with Gerrit codereview.') |
| 4518 if options.nocommit: | 4280 if options.nocommit: |
| 4519 parser.error('--nocommit is not supported with Gerrit codereview.') | 4281 parser.error('--nocommit is not supported with Gerrit codereview.') |
| 4520 if options.directory: | 4282 if options.directory: |
| 4521 parser.error('--directory is not supported with Gerrit codereview.') | 4283 parser.error('--directory is not supported with Gerrit codereview.') |
| 4522 | 4284 |
| 4523 return cl.CMDPatchIssue(args[0], options.reject, options.nocommit, | 4285 return cl.CMDPatchIssue(args[0], options.reject, options.nocommit, |
| 4524 options.directory) | 4286 options.directory) |
| 4525 | 4287 |
| 4526 | 4288 |
| 4527 def CMDrebase(parser, args): | |
| 4528 """Rebases current branch on top of svn repo.""" | |
| 4529 # Provide a wrapper for git svn rebase to help avoid accidental | |
| 4530 # git svn dcommit. | |
| 4531 # It's the only command that doesn't use parser at all since we just defer | |
| 4532 # execution to git-svn. | |
| 4533 | |
| 4534 return RunGitWithCode(['svn', 'rebase'] + args)[1] | |
| 4535 | |
| 4536 | |
| 4537 def GetTreeStatus(url=None): | 4289 def GetTreeStatus(url=None): |
| 4538 """Fetches the tree status and returns either 'open', 'closed', | 4290 """Fetches the tree status and returns either 'open', 'closed', |
| 4539 'unknown' or 'unset'.""" | 4291 'unknown' or 'unset'.""" |
| 4540 url = url or settings.GetTreeStatusUrl(error_ok=True) | 4292 url = url or settings.GetTreeStatusUrl(error_ok=True) |
| 4541 if url: | 4293 if url: |
| 4542 status = urllib2.urlopen(url).read().lower() | 4294 status = urllib2.urlopen(url).read().lower() |
| 4543 if status.find('closed') != -1 or status == '0': | 4295 if status.find('closed') != -1 or status == '0': |
| 4544 return 'closed' | 4296 return 'closed' |
| 4545 elif status.find('open') != -1 or status == '1': | 4297 elif status.find('open') != -1 or status == '1': |
| 4546 return 'open' | 4298 return 'open' |
| (...skipping 752 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5299 if __name__ == '__main__': | 5051 if __name__ == '__main__': |
| 5300 # These affect sys.stdout so do it outside of main() to simplify mocks in | 5052 # These affect sys.stdout so do it outside of main() to simplify mocks in |
| 5301 # unit testing. | 5053 # unit testing. |
| 5302 fix_encoding.fix_encoding() | 5054 fix_encoding.fix_encoding() |
| 5303 setup_color.init() | 5055 setup_color.init() |
| 5304 try: | 5056 try: |
| 5305 sys.exit(main(sys.argv[1:])) | 5057 sys.exit(main(sys.argv[1:])) |
| 5306 except KeyboardInterrupt: | 5058 except KeyboardInterrupt: |
| 5307 sys.stderr.write('interrupted\n') | 5059 sys.stderr.write('interrupted\n') |
| 5308 sys.exit(1) | 5060 sys.exit(1) |
| OLD | NEW |