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 |