| 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 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 107 return e.stdout | 107 return e.stdout |
| 108 | 108 |
| 109 | 109 |
| 110 def RunGit(args, **kwargs): | 110 def RunGit(args, **kwargs): |
| 111 """Returns stdout.""" | 111 """Returns stdout.""" |
| 112 return RunCommand(['git'] + args, **kwargs) | 112 return RunCommand(['git'] + args, **kwargs) |
| 113 | 113 |
| 114 | 114 |
| 115 def RunGitWithCode(args, suppress_stderr=False): | 115 def RunGitWithCode(args, suppress_stderr=False): |
| 116 """Returns return code and stdout.""" | 116 """Returns return code and stdout.""" |
| 117 if suppress_stderr: |
| 118 stderr = subprocess2.VOID |
| 119 else: |
| 120 stderr = sys.stderr |
| 117 try: | 121 try: |
| 118 if suppress_stderr: | 122 (out, _), code = subprocess2.communicate(['git'] + args, |
| 119 stderr = subprocess2.VOID | 123 env=GetNoGitPagerEnv(), |
| 120 else: | 124 stdout=subprocess2.PIPE, |
| 121 stderr = sys.stderr | 125 stderr=stderr) |
| 122 out, code = subprocess2.communicate(['git'] + args, | 126 return code, out |
| 123 env=GetNoGitPagerEnv(), | 127 except subprocess2.CalledProcessError as e: |
| 124 stdout=subprocess2.PIPE, | 128 logging.debug('Failed running %s', args) |
| 125 stderr=stderr) | 129 return e.returncode, e.stdout |
| 126 return code, out[0] | |
| 127 except ValueError: | |
| 128 # When the subprocess fails, it returns None. That triggers a ValueError | |
| 129 # when trying to unpack the return value into (out, code). | |
| 130 return 1, '' | |
| 131 | 130 |
| 132 | 131 |
| 133 def RunGitSilent(args): | 132 def RunGitSilent(args): |
| 134 """Returns stdout, suppresses stderr and ignores the return code.""" | 133 """Returns stdout, suppresses stderr and ignores the return code.""" |
| 135 return RunGitWithCode(args, suppress_stderr=True)[1] | 134 return RunGitWithCode(args, suppress_stderr=True)[1] |
| 136 | 135 |
| 137 | 136 |
| 138 def IsGitVersionAtLeast(min_version): | 137 def IsGitVersionAtLeast(min_version): |
| 139 prefix = 'git version ' | 138 prefix = 'git version ' |
| 140 version = RunGit(['--version']).strip() | 139 version = RunGit(['--version']).strip() |
| 141 return (version.startswith(prefix) and | 140 return (version.startswith(prefix) and |
| 142 LooseVersion(version[len(prefix):]) >= LooseVersion(min_version)) | 141 LooseVersion(version[len(prefix):]) >= LooseVersion(min_version)) |
| 143 | 142 |
| 144 | 143 |
| 145 def BranchExists(branch): | 144 def BranchExists(branch): |
| 146 """Return True if specified branch exists.""" | 145 """Return True if specified branch exists.""" |
| 147 code, _ = RunGitWithCode(['rev-parse', '--verify', branch], | 146 code, _ = RunGitWithCode(['rev-parse', '--verify', branch], |
| 148 suppress_stderr=True) | 147 suppress_stderr=True) |
| 149 return not code | 148 return not code |
| 150 | 149 |
| 151 | 150 |
| 152 def ask_for_data(prompt): | 151 def ask_for_data(prompt): |
| 153 try: | 152 try: |
| 154 return raw_input(prompt) | 153 return raw_input(prompt) |
| 155 except KeyboardInterrupt: | 154 except KeyboardInterrupt: |
| 156 # Hide the exception. | 155 # Hide the exception. |
| 157 sys.exit(1) | 156 sys.exit(1) |
| 158 | 157 |
| 159 | 158 |
| 160 def git_set_branch_value(key, value): | 159 def _git_branch_config_key(branch, key): |
| 161 branch = GetCurrentBranch() | 160 """Helper method to return Git config key for a branch.""" |
| 162 if not branch: | 161 assert branch, 'branch name is required to set git config for it' |
| 163 return | 162 return 'branch.%s.%s' % (branch, key) |
| 164 | |
| 165 cmd = ['config'] | |
| 166 if isinstance(value, int): | |
| 167 cmd.append('--int') | |
| 168 git_key = 'branch.%s.%s' % (branch, key) | |
| 169 RunGit(cmd + [git_key, str(value)]) | |
| 170 | 163 |
| 171 | 164 |
| 172 def git_get_branch_default(key, default): | 165 def _git_get_branch_config_value(key, default=None, value_type=str, |
| 173 branch = GetCurrentBranch() | 166 branch=False): |
| 174 if branch: | 167 """Returns git config value of given or current branch if any. |
| 175 git_key = 'branch.%s.%s' % (branch, key) | 168 |
| 176 (_, stdout) = RunGitWithCode(['config', '--int', '--get', git_key]) | 169 Returns default in all other cases. |
| 177 try: | 170 """ |
| 178 return int(stdout.strip()) | 171 assert value_type in (int, str, bool) |
| 179 except ValueError: | 172 if branch is False: # Distinguishing default arg value from None. |
| 180 pass | 173 branch = GetCurrentBranch() |
| 174 |
| 175 if not branch: |
| 176 return default |
| 177 |
| 178 args = ['config'] |
| 179 if value_type == int: |
| 180 args.append('--int') |
| 181 elif value_type == bool: |
| 182 args.append('--bool') |
| 183 args.append(_git_branch_config_key(branch, key)) |
| 184 code, out = RunGitWithCode(args) |
| 185 if code == 0: |
| 186 value = out.strip() |
| 187 if value_type == int: |
| 188 return int(value) |
| 189 if value_type == bool: |
| 190 return bool(value.lower() == 'true') |
| 191 return value |
| 181 return default | 192 return default |
| 182 | 193 |
| 183 | 194 |
| 195 def _git_set_branch_config_value(key, value, branch=None, **kwargs): |
| 196 """Sets the value or unsets if it's None of a git branch config. |
| 197 |
| 198 Valid, though not necessarily existing, branch must be provided, |
| 199 otherwise currently checked out branch is used. |
| 200 """ |
| 201 if not branch: |
| 202 branch = GetCurrentBranch() |
| 203 assert branch, 'a branch name OR currently checked out branch is required' |
| 204 args = ['config'] |
| 205 # Check for boolean first, becuase bool is int, but int is not bool. |
| 206 if value is None: |
| 207 args.append('--unset') |
| 208 elif isinstance(value, bool): |
| 209 args.append('--bool') |
| 210 value = str(value).lower() |
| 211 elif isinstance(value, int): |
| 212 args.append('--int') |
| 213 value = str(value) |
| 214 else: |
| 215 value = str(value) |
| 216 args.append(_git_branch_config_key(branch, key)) |
| 217 if value is not None: |
| 218 args.append(value) |
| 219 RunGit(args, **kwargs) |
| 220 |
| 221 |
| 184 def add_git_similarity(parser): | 222 def add_git_similarity(parser): |
| 185 parser.add_option( | 223 parser.add_option( |
| 186 '--similarity', metavar='SIM', type='int', action='store', | 224 '--similarity', metavar='SIM', type=int, action='store', |
| 187 help='Sets the percentage that a pair of files need to match in order to' | 225 help='Sets the percentage that a pair of files need to match in order to' |
| 188 ' be considered copies (default 50)') | 226 ' be considered copies (default 50)') |
| 189 parser.add_option( | 227 parser.add_option( |
| 190 '--find-copies', action='store_true', | 228 '--find-copies', action='store_true', |
| 191 help='Allows git to look for copies.') | 229 help='Allows git to look for copies.') |
| 192 parser.add_option( | 230 parser.add_option( |
| 193 '--no-find-copies', action='store_false', dest='find_copies', | 231 '--no-find-copies', action='store_false', dest='find_copies', |
| 194 help='Disallows git from looking for copies.') | 232 help='Disallows git from looking for copies.') |
| 195 | 233 |
| 196 old_parser_args = parser.parse_args | 234 old_parser_args = parser.parse_args |
| 197 def Parse(args): | 235 def Parse(args): |
| 198 options, args = old_parser_args(args) | 236 options, args = old_parser_args(args) |
| 199 | 237 |
| 200 if options.similarity is None: | 238 if options.similarity is None: |
| 201 options.similarity = git_get_branch_default('git-cl-similarity', 50) | 239 options.similarity = _git_get_branch_config_value( |
| 240 'git-cl-similarity', default=50, value_type=int) |
| 202 else: | 241 else: |
| 203 print('Note: Saving similarity of %d%% in git config.' | 242 print('Note: Saving similarity of %d%% in git config.' |
| 204 % options.similarity) | 243 % options.similarity) |
| 205 git_set_branch_value('git-cl-similarity', options.similarity) | 244 _git_set_branch_config_value('git-cl-similarity', options.similarity) |
| 206 | 245 |
| 207 options.similarity = max(0, min(options.similarity, 100)) | 246 options.similarity = max(0, min(options.similarity, 100)) |
| 208 | 247 |
| 209 if options.find_copies is None: | 248 if options.find_copies is None: |
| 210 options.find_copies = bool( | 249 options.find_copies = _git_get_branch_config_value( |
| 211 git_get_branch_default('git-find-copies', True)) | 250 'git-find-copies', default=True, value_type=bool) |
| 212 else: | 251 else: |
| 213 git_set_branch_value('git-find-copies', int(options.find_copies)) | 252 _git_set_branch_config_value('git-find-copies', bool(options.find_copies)) |
| 214 | 253 |
| 215 print('Using %d%% similarity for rename/copy detection. ' | 254 print('Using %d%% similarity for rename/copy detection. ' |
| 216 'Override with --similarity.' % options.similarity) | 255 'Override with --similarity.' % options.similarity) |
| 217 | 256 |
| 218 return options, args | 257 return options, args |
| 219 parser.parse_args = Parse | 258 parser.parse_args = Parse |
| 220 | 259 |
| 221 | 260 |
| 222 def _get_properties_from_options(options): | 261 def _get_properties_from_options(options): |
| 223 properties = dict(x.split('=', 1) for x in options.properties) | 262 properties = dict(x.split('=', 1) for x in options.properties) |
| (...skipping 675 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 899 | 938 |
| 900 class Changelist(object): | 939 class Changelist(object): |
| 901 """Changelist works with one changelist in local branch. | 940 """Changelist works with one changelist in local branch. |
| 902 | 941 |
| 903 Supports two codereview backends: Rietveld or Gerrit, selected at object | 942 Supports two codereview backends: Rietveld or Gerrit, selected at object |
| 904 creation. | 943 creation. |
| 905 | 944 |
| 906 Notes: | 945 Notes: |
| 907 * Not safe for concurrent multi-{thread,process} use. | 946 * Not safe for concurrent multi-{thread,process} use. |
| 908 * Caches values from current branch. Therefore, re-use after branch change | 947 * Caches values from current branch. Therefore, re-use after branch change |
| 909 with care. | 948 with great care. |
| 910 """ | 949 """ |
| 911 | 950 |
| 912 def __init__(self, branchref=None, issue=None, codereview=None, **kwargs): | 951 def __init__(self, branchref=None, issue=None, codereview=None, **kwargs): |
| 913 """Create a new ChangeList instance. | 952 """Create a new ChangeList instance. |
| 914 | 953 |
| 915 If issue is given, the codereview must be given too. | 954 If issue is given, the codereview must be given too. |
| 916 | 955 |
| 917 If `codereview` is given, it must be 'rietveld' or 'gerrit'. | 956 If `codereview` is given, it must be 'rietveld' or 'gerrit'. |
| 918 Otherwise, it's decided based on current configuration of the local branch, | 957 Otherwise, it's decided based on current configuration of the local branch, |
| 919 with default being 'rietveld' for backwards compatibility. | 958 with default being 'rietveld' for backwards compatibility. |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 959 cls = _CODEREVIEW_IMPLEMENTATIONS[codereview] | 998 cls = _CODEREVIEW_IMPLEMENTATIONS[codereview] |
| 960 self._codereview = codereview | 999 self._codereview = codereview |
| 961 self._codereview_impl = cls(self, **kwargs) | 1000 self._codereview_impl = cls(self, **kwargs) |
| 962 return | 1001 return |
| 963 | 1002 |
| 964 # Automatic selection based on issue number set for a current branch. | 1003 # Automatic selection based on issue number set for a current branch. |
| 965 # Rietveld takes precedence over Gerrit. | 1004 # Rietveld takes precedence over Gerrit. |
| 966 assert not self.issue | 1005 assert not self.issue |
| 967 # Whether we find issue or not, we are doing the lookup. | 1006 # Whether we find issue or not, we are doing the lookup. |
| 968 self.lookedup_issue = True | 1007 self.lookedup_issue = True |
| 969 for codereview, cls in _CODEREVIEW_IMPLEMENTATIONS.iteritems(): | 1008 if self.GetBranch(): |
| 970 setting = cls.IssueSetting(self.GetBranch()) | 1009 for codereview, cls in _CODEREVIEW_IMPLEMENTATIONS.iteritems(): |
| 971 issue = RunGit(['config', setting], error_ok=True).strip() | 1010 issue = _git_get_branch_config_value( |
| 972 if issue: | 1011 cls.IssueConfigKey(), value_type=int, branch=self.GetBranch()) |
| 973 self._codereview = codereview | 1012 if issue: |
| 974 self._codereview_impl = cls(self, **kwargs) | 1013 self._codereview = codereview |
| 975 self.issue = int(issue) | 1014 self._codereview_impl = cls(self, **kwargs) |
| 976 return | 1015 self.issue = int(issue) |
| 1016 return |
| 977 | 1017 |
| 978 # No issue is set for this branch, so decide based on repo-wide settings. | 1018 # No issue is set for this branch, so decide based on repo-wide settings. |
| 979 return self._load_codereview_impl( | 1019 return self._load_codereview_impl( |
| 980 codereview='gerrit' if settings.GetIsGerrit() else 'rietveld', | 1020 codereview='gerrit' if settings.GetIsGerrit() else 'rietveld', |
| 981 **kwargs) | 1021 **kwargs) |
| 982 | 1022 |
| 983 def IsGerrit(self): | 1023 def IsGerrit(self): |
| 984 return self._codereview == 'gerrit' | 1024 return self._codereview == 'gerrit' |
| 985 | 1025 |
| 986 def GetCCList(self): | 1026 def GetCCList(self): |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1018 | 1058 |
| 1019 def GetBranchRef(self): | 1059 def GetBranchRef(self): |
| 1020 """Returns the full branch name, e.g. 'refs/heads/master'.""" | 1060 """Returns the full branch name, e.g. 'refs/heads/master'.""" |
| 1021 self.GetBranch() # Poke the lazy loader. | 1061 self.GetBranch() # Poke the lazy loader. |
| 1022 return self.branchref | 1062 return self.branchref |
| 1023 | 1063 |
| 1024 def ClearBranch(self): | 1064 def ClearBranch(self): |
| 1025 """Clears cached branch data of this object.""" | 1065 """Clears cached branch data of this object.""" |
| 1026 self.branch = self.branchref = None | 1066 self.branch = self.branchref = None |
| 1027 | 1067 |
| 1068 def _GitGetBranchConfigValue(self, key, default=None, **kwargs): |
| 1069 assert 'branch' not in kwargs, 'this CL branch is used automatically' |
| 1070 kwargs['branch'] = self.GetBranch() |
| 1071 return _git_get_branch_config_value(key, default, **kwargs) |
| 1072 |
| 1073 def _GitSetBranchConfigValue(self, key, value, **kwargs): |
| 1074 assert 'branch' not in kwargs, 'this CL branch is used automatically' |
| 1075 assert self.GetBranch(), ( |
| 1076 'this CL must have an associated branch to %sset %s%s' % |
| 1077 ('un' if value is None else '', |
| 1078 key, |
| 1079 '' if value is None else ' to %r' % value)) |
| 1080 kwargs['branch'] = self.GetBranch() |
| 1081 return _git_set_branch_config_value(key, value, **kwargs) |
| 1082 |
| 1028 @staticmethod | 1083 @staticmethod |
| 1029 def FetchUpstreamTuple(branch): | 1084 def FetchUpstreamTuple(branch): |
| 1030 """Returns a tuple containing remote and remote ref, | 1085 """Returns a tuple containing remote and remote ref, |
| 1031 e.g. 'origin', 'refs/heads/master' | 1086 e.g. 'origin', 'refs/heads/master' |
| 1032 """ | 1087 """ |
| 1033 remote = '.' | 1088 remote = '.' |
| 1034 upstream_branch = RunGit(['config', 'branch.%s.merge' % branch], | 1089 upstream_branch = _git_get_branch_config_value('merge', branch=branch) |
| 1035 error_ok=True).strip() | 1090 |
| 1036 if upstream_branch: | 1091 if upstream_branch: |
| 1037 remote = RunGit(['config', 'branch.%s.remote' % branch]).strip() | 1092 remote = _git_get_branch_config_value('remote', branch=branch) |
| 1038 else: | 1093 else: |
| 1039 upstream_branch = RunGit(['config', 'rietveld.upstream-branch'], | 1094 upstream_branch = RunGit(['config', 'rietveld.upstream-branch'], |
| 1040 error_ok=True).strip() | 1095 error_ok=True).strip() |
| 1041 if upstream_branch: | 1096 if upstream_branch: |
| 1042 remote = RunGit(['config', 'rietveld.upstream-remote']).strip() | 1097 remote = RunGit(['config', 'rietveld.upstream-remote']).strip() |
| 1043 else: | 1098 else: |
| 1044 # Fall back on trying a git-svn upstream branch. | 1099 # Fall back on trying a git-svn upstream branch. |
| 1045 if settings.GetIsGitSvn(): | 1100 if settings.GetIsGitSvn(): |
| 1046 upstream_branch = settings.GetSVNBranch() | 1101 upstream_branch = settings.GetSVNBranch() |
| 1047 else: | 1102 else: |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1161 len(common_commits), remote_branch, upstream_git_obj), | 1216 len(common_commits), remote_branch, upstream_git_obj), |
| 1162 file=sys.stderr) | 1217 file=sys.stderr) |
| 1163 return False | 1218 return False |
| 1164 return True | 1219 return True |
| 1165 | 1220 |
| 1166 def GetGitBaseUrlFromConfig(self): | 1221 def GetGitBaseUrlFromConfig(self): |
| 1167 """Return the configured base URL from branch.<branchname>.baseurl. | 1222 """Return the configured base URL from branch.<branchname>.baseurl. |
| 1168 | 1223 |
| 1169 Returns None if it is not set. | 1224 Returns None if it is not set. |
| 1170 """ | 1225 """ |
| 1171 return RunGit(['config', 'branch.%s.base-url' % self.GetBranch()], | 1226 return self._GitGetBranchConfigValue('base-url') |
| 1172 error_ok=True).strip() | |
| 1173 | 1227 |
| 1174 def GetGitSvnRemoteUrl(self): | 1228 def GetGitSvnRemoteUrl(self): |
| 1175 """Return the configured git-svn remote URL parsed from git svn info. | 1229 """Return the configured git-svn remote URL parsed from git svn info. |
| 1176 | 1230 |
| 1177 Returns None if it is not set. | 1231 Returns None if it is not set. |
| 1178 """ | 1232 """ |
| 1179 # URL is dependent on the current directory. | 1233 # URL is dependent on the current directory. |
| 1180 data = RunGit(['svn', 'info'], cwd=settings.GetRoot()) | 1234 data = RunGit(['svn', 'info'], cwd=settings.GetRoot()) |
| 1181 if data: | 1235 if data: |
| 1182 keys = dict(line.split(': ', 1) for line in data.splitlines() | 1236 keys = dict(line.split(': ', 1) for line in data.splitlines() |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1195 # If URL is pointing to a local directory, it is probably a git cache. | 1249 # If URL is pointing to a local directory, it is probably a git cache. |
| 1196 if os.path.isdir(url): | 1250 if os.path.isdir(url): |
| 1197 url = RunGit(['config', 'remote.%s.url' % remote], | 1251 url = RunGit(['config', 'remote.%s.url' % remote], |
| 1198 error_ok=True, | 1252 error_ok=True, |
| 1199 cwd=url).strip() | 1253 cwd=url).strip() |
| 1200 return url | 1254 return url |
| 1201 | 1255 |
| 1202 def GetIssue(self): | 1256 def GetIssue(self): |
| 1203 """Returns the issue number as a int or None if not set.""" | 1257 """Returns the issue number as a int or None if not set.""" |
| 1204 if self.issue is None and not self.lookedup_issue: | 1258 if self.issue is None and not self.lookedup_issue: |
| 1205 issue = RunGit(['config', | 1259 self.issue = self._GitGetBranchConfigValue( |
| 1206 self._codereview_impl.IssueSetting(self.GetBranch())], | 1260 self._codereview_impl.IssueConfigKey(), value_type=int) |
| 1207 error_ok=True).strip() | |
| 1208 self.issue = int(issue) or None if issue else None | |
| 1209 self.lookedup_issue = True | 1261 self.lookedup_issue = True |
| 1210 return self.issue | 1262 return self.issue |
| 1211 | 1263 |
| 1212 def GetIssueURL(self): | 1264 def GetIssueURL(self): |
| 1213 """Get the URL for a particular issue.""" | 1265 """Get the URL for a particular issue.""" |
| 1214 issue = self.GetIssue() | 1266 issue = self.GetIssue() |
| 1215 if not issue: | 1267 if not issue: |
| 1216 return None | 1268 return None |
| 1217 return '%s/%s' % (self._codereview_impl.GetCodereviewServer(), issue) | 1269 return '%s/%s' % (self._codereview_impl.GetCodereviewServer(), issue) |
| 1218 | 1270 |
| 1219 def GetDescription(self, pretty=False): | 1271 def GetDescription(self, pretty=False): |
| 1220 if not self.has_description: | 1272 if not self.has_description: |
| 1221 if self.GetIssue(): | 1273 if self.GetIssue(): |
| 1222 self.description = self._codereview_impl.FetchDescription() | 1274 self.description = self._codereview_impl.FetchDescription() |
| 1223 self.has_description = True | 1275 self.has_description = True |
| 1224 if pretty: | 1276 if pretty: |
| 1225 wrapper = textwrap.TextWrapper() | 1277 wrapper = textwrap.TextWrapper() |
| 1226 wrapper.initial_indent = wrapper.subsequent_indent = ' ' | 1278 wrapper.initial_indent = wrapper.subsequent_indent = ' ' |
| 1227 return wrapper.fill(self.description) | 1279 return wrapper.fill(self.description) |
| 1228 return self.description | 1280 return self.description |
| 1229 | 1281 |
| 1230 def GetPatchset(self): | 1282 def GetPatchset(self): |
| 1231 """Returns the patchset number as a int or None if not set.""" | 1283 """Returns the patchset number as a int or None if not set.""" |
| 1232 if self.patchset is None and not self.lookedup_patchset: | 1284 if self.patchset is None and not self.lookedup_patchset: |
| 1233 patchset = RunGit(['config', self._codereview_impl.PatchsetSetting()], | 1285 self.patchset = self._GitGetBranchConfigValue( |
| 1234 error_ok=True).strip() | 1286 self._codereview_impl.PatchsetConfigKey(), value_type=int) |
| 1235 self.patchset = int(patchset) or None if patchset else None | |
| 1236 self.lookedup_patchset = True | 1287 self.lookedup_patchset = True |
| 1237 return self.patchset | 1288 return self.patchset |
| 1238 | 1289 |
| 1239 def SetPatchset(self, patchset): | 1290 def SetPatchset(self, patchset): |
| 1240 """Set this branch's patchset. If patchset=0, clears the patchset.""" | 1291 """Set this branch's patchset. If patchset=0, clears the patchset.""" |
| 1241 patchset_setting = self._codereview_impl.PatchsetSetting() | 1292 assert self.GetBranch() |
| 1242 if patchset: | 1293 if not patchset: |
| 1243 RunGit(['config', patchset_setting, str(patchset)]) | 1294 self.patchset = None |
| 1244 self.patchset = patchset | |
| 1245 else: | 1295 else: |
| 1246 RunGit(['config', '--unset', patchset_setting], | 1296 self.patchset = int(patchset) |
| 1247 stderr=subprocess2.PIPE, error_ok=True) | 1297 self._GitSetBranchConfigValue( |
| 1248 self.patchset = None | 1298 self._codereview_impl.PatchsetConfigKey(), self.patchset) |
| 1249 | 1299 |
| 1250 def SetIssue(self, issue=None): | 1300 def SetIssue(self, issue=None): |
| 1251 """Set this branch's issue. If issue isn't given, clears the issue.""" | 1301 """Set this branch's issue. If issue isn't given, clears the issue.""" |
| 1252 issue_setting = self._codereview_impl.IssueSetting(self.GetBranch()) | 1302 assert self.GetBranch() |
| 1253 codereview_setting = self._codereview_impl.GetCodereviewServerSetting() | |
| 1254 if issue: | 1303 if issue: |
| 1304 issue = int(issue) |
| 1305 self._GitSetBranchConfigValue( |
| 1306 self._codereview_impl.IssueConfigKey(), issue) |
| 1255 self.issue = issue | 1307 self.issue = issue |
| 1256 RunGit(['config', issue_setting, str(issue)]) | |
| 1257 codereview_server = self._codereview_impl.GetCodereviewServer() | 1308 codereview_server = self._codereview_impl.GetCodereviewServer() |
| 1258 if codereview_server: | 1309 if codereview_server: |
| 1259 RunGit(['config', codereview_setting, codereview_server]) | 1310 self._GitSetBranchConfigValue( |
| 1311 self._codereview_impl.CodereviewServerConfigKey(), |
| 1312 codereview_server) |
| 1260 else: | 1313 else: |
| 1261 # Reset it regardless. It doesn't hurt. | 1314 # Reset all of these just to be clean. |
| 1262 config_settings = [issue_setting, self._codereview_impl.PatchsetSetting()] | 1315 reset_suffixes = [ |
| 1263 for prop in (['last-upload-hash'] + | 1316 'last-upload-hash', |
| 1264 self._codereview_impl._PostUnsetIssueProperties()): | 1317 self._codereview_impl.IssueConfigKey(), |
| 1265 config_settings.append('branch.%s.%s' % (self.GetBranch(), prop)) | 1318 self._codereview_impl.PatchsetConfigKey(), |
| 1266 for setting in config_settings: | 1319 self._codereview_impl.CodereviewServerConfigKey(), |
| 1267 RunGit(['config', '--unset', setting], error_ok=True) | 1320 ] + self._PostUnsetIssueProperties() |
| 1321 for prop in reset_suffixes: |
| 1322 self._GitSetBranchConfigValue(prop, None, error_ok=True) |
| 1268 self.issue = None | 1323 self.issue = None |
| 1269 self.patchset = None | 1324 self.patchset = None |
| 1270 | 1325 |
| 1271 def GetChange(self, upstream_branch, author): | 1326 def GetChange(self, upstream_branch, author): |
| 1272 if not self.GitSanityChecks(upstream_branch): | 1327 if not self.GitSanityChecks(upstream_branch): |
| 1273 DieWithError('\nGit sanity check failure') | 1328 DieWithError('\nGit sanity check failure') |
| 1274 | 1329 |
| 1275 root = settings.GetRelativeRoot() | 1330 root = settings.GetRelativeRoot() |
| 1276 if not root: | 1331 if not root: |
| 1277 root = '.' | 1332 root = '.' |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1401 ask_for_data('About to upload; enter to confirm.') | 1456 ask_for_data('About to upload; enter to confirm.') |
| 1402 | 1457 |
| 1403 print_stats(options.similarity, options.find_copies, git_diff_args) | 1458 print_stats(options.similarity, options.find_copies, git_diff_args) |
| 1404 ret = self.CMDUploadChange(options, git_diff_args, change) | 1459 ret = self.CMDUploadChange(options, git_diff_args, change) |
| 1405 if not ret: | 1460 if not ret: |
| 1406 if options.use_commit_queue: | 1461 if options.use_commit_queue: |
| 1407 self.SetCQState(_CQState.COMMIT) | 1462 self.SetCQState(_CQState.COMMIT) |
| 1408 elif options.cq_dry_run: | 1463 elif options.cq_dry_run: |
| 1409 self.SetCQState(_CQState.DRY_RUN) | 1464 self.SetCQState(_CQState.DRY_RUN) |
| 1410 | 1465 |
| 1411 git_set_branch_value('last-upload-hash', | 1466 _git_set_branch_config_value('last-upload-hash', |
| 1412 RunGit(['rev-parse', 'HEAD']).strip()) | 1467 RunGit(['rev-parse', 'HEAD']).strip()) |
| 1413 # Run post upload hooks, if specified. | 1468 # Run post upload hooks, if specified. |
| 1414 if settings.GetRunPostUploadHook(): | 1469 if settings.GetRunPostUploadHook(): |
| 1415 presubmit_support.DoPostUploadExecuter( | 1470 presubmit_support.DoPostUploadExecuter( |
| 1416 change, | 1471 change, |
| 1417 self, | 1472 self, |
| 1418 settings.GetRoot(), | 1473 settings.GetRoot(), |
| 1419 options.verbose, | 1474 options.verbose, |
| 1420 sys.stdout) | 1475 sys.stdout) |
| 1421 | 1476 |
| 1422 # Upload all dependencies if specified. | 1477 # Upload all dependencies if specified. |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1489 raise NotImplementedError() | 1544 raise NotImplementedError() |
| 1490 | 1545 |
| 1491 def GetCodereviewServer(self): | 1546 def GetCodereviewServer(self): |
| 1492 """Returns server URL without end slash, like "https://codereview.com".""" | 1547 """Returns server URL without end slash, like "https://codereview.com".""" |
| 1493 raise NotImplementedError() | 1548 raise NotImplementedError() |
| 1494 | 1549 |
| 1495 def FetchDescription(self): | 1550 def FetchDescription(self): |
| 1496 """Fetches and returns description from the codereview server.""" | 1551 """Fetches and returns description from the codereview server.""" |
| 1497 raise NotImplementedError() | 1552 raise NotImplementedError() |
| 1498 | 1553 |
| 1499 def GetCodereviewServerSetting(self): | 1554 @classmethod |
| 1500 """Returns git config setting for the codereview server.""" | 1555 def IssueConfigKey(cls): |
| 1556 """Returns branch setting storing issue number.""" |
| 1501 raise NotImplementedError() | 1557 raise NotImplementedError() |
| 1502 | 1558 |
| 1503 @classmethod | 1559 @classmethod |
| 1504 def IssueSetting(cls, branch): | 1560 def PatchsetConfigKey(cls): |
| 1505 return 'branch.%s.%s' % (branch, cls.IssueSettingSuffix()) | 1561 """Returns branch setting storing patchset number.""" |
| 1562 raise NotImplementedError() |
| 1506 | 1563 |
| 1507 @classmethod | 1564 @classmethod |
| 1508 def IssueSettingSuffix(cls): | 1565 def CodereviewServerConfigKey(cls): |
| 1509 """Returns name of git config setting which stores issue number for a given | 1566 """Returns branch setting storing codereview server.""" |
| 1510 branch.""" | |
| 1511 raise NotImplementedError() | |
| 1512 | |
| 1513 def PatchsetSetting(self): | |
| 1514 """Returns name of git config setting which stores issue number.""" | |
| 1515 raise NotImplementedError() | 1567 raise NotImplementedError() |
| 1516 | 1568 |
| 1517 def _PostUnsetIssueProperties(self): | 1569 def _PostUnsetIssueProperties(self): |
| 1518 """Which branch-specific properties to erase when unsettin issue.""" | 1570 """Which branch-specific properties to erase when unsettin issue.""" |
| 1519 raise NotImplementedError() | 1571 return [] |
| 1520 | 1572 |
| 1521 def GetRieveldObjForPresubmit(self): | 1573 def GetRieveldObjForPresubmit(self): |
| 1522 # This is an unfortunate Rietveld-embeddedness in presubmit. | 1574 # This is an unfortunate Rietveld-embeddedness in presubmit. |
| 1523 # For non-Rietveld codereviews, this probably should return a dummy object. | 1575 # For non-Rietveld codereviews, this probably should return a dummy object. |
| 1524 raise NotImplementedError() | 1576 raise NotImplementedError() |
| 1525 | 1577 |
| 1526 def GetGerritObjForPresubmit(self): | 1578 def GetGerritObjForPresubmit(self): |
| 1527 # None is valid return value, otherwise presubmit_support.GerritAccessor. | 1579 # None is valid return value, otherwise presubmit_support.GerritAccessor. |
| 1528 return None | 1580 return None |
| 1529 | 1581 |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1596 self._rietveld_server = rietveld_server | 1648 self._rietveld_server = rietveld_server |
| 1597 self._auth_config = auth_config | 1649 self._auth_config = auth_config |
| 1598 self._props = None | 1650 self._props = None |
| 1599 self._rpc_server = None | 1651 self._rpc_server = None |
| 1600 | 1652 |
| 1601 def GetCodereviewServer(self): | 1653 def GetCodereviewServer(self): |
| 1602 if not self._rietveld_server: | 1654 if not self._rietveld_server: |
| 1603 # If we're on a branch then get the server potentially associated | 1655 # If we're on a branch then get the server potentially associated |
| 1604 # with that branch. | 1656 # with that branch. |
| 1605 if self.GetIssue(): | 1657 if self.GetIssue(): |
| 1606 rietveld_server_setting = self.GetCodereviewServerSetting() | 1658 self._rietveld_server = gclient_utils.UpgradeToHttps( |
| 1607 if rietveld_server_setting: | 1659 self._GitGetBranchConfigValue(self.CodereviewServerConfigKey())) |
| 1608 self._rietveld_server = gclient_utils.UpgradeToHttps(RunGit( | |
| 1609 ['config', rietveld_server_setting], error_ok=True).strip()) | |
| 1610 if not self._rietveld_server: | 1660 if not self._rietveld_server: |
| 1611 self._rietveld_server = settings.GetDefaultServerUrl() | 1661 self._rietveld_server = settings.GetDefaultServerUrl() |
| 1612 return self._rietveld_server | 1662 return self._rietveld_server |
| 1613 | 1663 |
| 1614 def EnsureAuthenticated(self, force): | 1664 def EnsureAuthenticated(self, force): |
| 1615 """Best effort check that user is authenticated with Rietveld server.""" | 1665 """Best effort check that user is authenticated with Rietveld server.""" |
| 1616 if self._auth_config.use_oauth2: | 1666 if self._auth_config.use_oauth2: |
| 1617 authenticator = auth.get_authenticator_for_host( | 1667 authenticator = auth.get_authenticator_for_host( |
| 1618 self.GetCodereviewServer(), self._auth_config) | 1668 self.GetCodereviewServer(), self._auth_config) |
| 1619 if not authenticator.has_cached_credentials(): | 1669 if not authenticator.has_cached_credentials(): |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1753 def RpcServer(self): | 1803 def RpcServer(self): |
| 1754 """Returns an upload.RpcServer() to access this review's rietveld instance. | 1804 """Returns an upload.RpcServer() to access this review's rietveld instance. |
| 1755 """ | 1805 """ |
| 1756 if not self._rpc_server: | 1806 if not self._rpc_server: |
| 1757 self._rpc_server = rietveld.CachingRietveld( | 1807 self._rpc_server = rietveld.CachingRietveld( |
| 1758 self.GetCodereviewServer(), | 1808 self.GetCodereviewServer(), |
| 1759 self._auth_config or auth.make_auth_config()) | 1809 self._auth_config or auth.make_auth_config()) |
| 1760 return self._rpc_server | 1810 return self._rpc_server |
| 1761 | 1811 |
| 1762 @classmethod | 1812 @classmethod |
| 1763 def IssueSettingSuffix(cls): | 1813 def IssueConfigKey(cls): |
| 1764 return 'rietveldissue' | 1814 return 'rietveldissue' |
| 1765 | 1815 |
| 1766 def PatchsetSetting(self): | 1816 @classmethod |
| 1767 """Return the git setting that stores this change's most recent patchset.""" | 1817 def PatchsetConfigKey(cls): |
| 1768 return 'branch.%s.rietveldpatchset' % self.GetBranch() | 1818 return 'rietveldpatchset' |
| 1769 | 1819 |
| 1770 def GetCodereviewServerSetting(self): | 1820 @classmethod |
| 1771 """Returns the git setting that stores this change's rietveld server.""" | 1821 def CodereviewServerConfigKey(cls): |
| 1772 branch = self.GetBranch() | 1822 return 'rietveldserver' |
| 1773 if branch: | |
| 1774 return 'branch.%s.rietveldserver' % branch | |
| 1775 return None | |
| 1776 | |
| 1777 def _PostUnsetIssueProperties(self): | |
| 1778 """Which branch-specific properties to erase when unsetting issue.""" | |
| 1779 return ['rietveldserver'] | |
| 1780 | 1823 |
| 1781 def GetRieveldObjForPresubmit(self): | 1824 def GetRieveldObjForPresubmit(self): |
| 1782 return self.RpcServer() | 1825 return self.RpcServer() |
| 1783 | 1826 |
| 1784 def SetCQState(self, new_state): | 1827 def SetCQState(self, new_state): |
| 1785 props = self.GetIssueProperties() | 1828 props = self.GetIssueProperties() |
| 1786 if props.get('private'): | 1829 if props.get('private'): |
| 1787 DieWithError('Cannot set-commit on private issue') | 1830 DieWithError('Cannot set-commit on private issue') |
| 1788 | 1831 |
| 1789 if new_state == _CQState.COMMIT: | 1832 if new_state == _CQState.COMMIT: |
| (...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2063 | 2106 |
| 2064 def _GetGitHost(self): | 2107 def _GetGitHost(self): |
| 2065 """Returns git host to be used when uploading change to Gerrit.""" | 2108 """Returns git host to be used when uploading change to Gerrit.""" |
| 2066 return urlparse.urlparse(self.GetRemoteUrl()).netloc | 2109 return urlparse.urlparse(self.GetRemoteUrl()).netloc |
| 2067 | 2110 |
| 2068 def GetCodereviewServer(self): | 2111 def GetCodereviewServer(self): |
| 2069 if not self._gerrit_server: | 2112 if not self._gerrit_server: |
| 2070 # If we're on a branch then get the server potentially associated | 2113 # If we're on a branch then get the server potentially associated |
| 2071 # with that branch. | 2114 # with that branch. |
| 2072 if self.GetIssue(): | 2115 if self.GetIssue(): |
| 2073 gerrit_server_setting = self.GetCodereviewServerSetting() | 2116 self._gerrit_server = self._GitGetBranchConfigValue( |
| 2074 if gerrit_server_setting: | 2117 self.CodereviewServerConfigKey()) |
| 2075 self._gerrit_server = RunGit(['config', gerrit_server_setting], | 2118 if self._gerrit_server: |
| 2076 error_ok=True).strip() | 2119 self._gerrit_host = urlparse.urlparse(self._gerrit_server).netloc |
| 2077 if self._gerrit_server: | |
| 2078 self._gerrit_host = urlparse.urlparse(self._gerrit_server).netloc | |
| 2079 if not self._gerrit_server: | 2120 if not self._gerrit_server: |
| 2080 # We assume repo to be hosted on Gerrit, and hence Gerrit server | 2121 # We assume repo to be hosted on Gerrit, and hence Gerrit server |
| 2081 # has "-review" suffix for lowest level subdomain. | 2122 # has "-review" suffix for lowest level subdomain. |
| 2082 parts = self._GetGitHost().split('.') | 2123 parts = self._GetGitHost().split('.') |
| 2083 parts[0] = parts[0] + '-review' | 2124 parts[0] = parts[0] + '-review' |
| 2084 self._gerrit_host = '.'.join(parts) | 2125 self._gerrit_host = '.'.join(parts) |
| 2085 self._gerrit_server = 'https://%s' % self._gerrit_host | 2126 self._gerrit_server = 'https://%s' % self._gerrit_host |
| 2086 return self._gerrit_server | 2127 return self._gerrit_server |
| 2087 | 2128 |
| 2088 @classmethod | 2129 @classmethod |
| 2089 def IssueSettingSuffix(cls): | 2130 def IssueConfigKey(cls): |
| 2090 return 'gerritissue' | 2131 return 'gerritissue' |
| 2091 | 2132 |
| 2133 @classmethod |
| 2134 def PatchsetConfigKey(cls): |
| 2135 return 'gerritpatchset' |
| 2136 |
| 2137 @classmethod |
| 2138 def CodereviewServerConfigKey(cls): |
| 2139 return 'gerritserver' |
| 2140 |
| 2092 def EnsureAuthenticated(self, force): | 2141 def EnsureAuthenticated(self, force): |
| 2093 """Best effort check that user is authenticated with Gerrit server.""" | 2142 """Best effort check that user is authenticated with Gerrit server.""" |
| 2094 if settings.GetGerritSkipEnsureAuthenticated(): | 2143 if settings.GetGerritSkipEnsureAuthenticated(): |
| 2095 # For projects with unusual authentication schemes. | 2144 # For projects with unusual authentication schemes. |
| 2096 # See http://crbug.com/603378. | 2145 # See http://crbug.com/603378. |
| 2097 return | 2146 return |
| 2098 # Lazy-loader to identify Gerrit and Git hosts. | 2147 # Lazy-loader to identify Gerrit and Git hosts. |
| 2099 if gerrit_util.GceAuthenticator.is_gce(): | 2148 if gerrit_util.GceAuthenticator.is_gce(): |
| 2100 return | 2149 return |
| 2101 self.GetCodereviewServer() | 2150 self.GetCodereviewServer() |
| (...skipping 25 matching lines...) Expand all Loading... |
| 2127 [] if git_auth else [git_host]) | 2176 [] if git_auth else [git_host]) |
| 2128 DieWithError('Credentials for the following hosts are required:\n' | 2177 DieWithError('Credentials for the following hosts are required:\n' |
| 2129 ' %s\n' | 2178 ' %s\n' |
| 2130 'These are read from %s (or legacy %s)\n' | 2179 'These are read from %s (or legacy %s)\n' |
| 2131 '%s' % ( | 2180 '%s' % ( |
| 2132 '\n '.join(missing), | 2181 '\n '.join(missing), |
| 2133 cookie_auth.get_gitcookies_path(), | 2182 cookie_auth.get_gitcookies_path(), |
| 2134 cookie_auth.get_netrc_path(), | 2183 cookie_auth.get_netrc_path(), |
| 2135 cookie_auth.get_new_password_message(git_host))) | 2184 cookie_auth.get_new_password_message(git_host))) |
| 2136 | 2185 |
| 2137 | |
| 2138 def PatchsetSetting(self): | |
| 2139 """Return the git setting that stores this change's most recent patchset.""" | |
| 2140 return 'branch.%s.gerritpatchset' % self.GetBranch() | |
| 2141 | |
| 2142 def GetCodereviewServerSetting(self): | |
| 2143 """Returns the git setting that stores this change's Gerrit server.""" | |
| 2144 branch = self.GetBranch() | |
| 2145 if branch: | |
| 2146 return 'branch.%s.gerritserver' % branch | |
| 2147 return None | |
| 2148 | |
| 2149 def _PostUnsetIssueProperties(self): | 2186 def _PostUnsetIssueProperties(self): |
| 2150 """Which branch-specific properties to erase when unsetting issue.""" | 2187 """Which branch-specific properties to erase when unsetting issue.""" |
| 2151 return [ | 2188 return ['gerritsquashhash'] |
| 2152 'gerritserver', | |
| 2153 'gerritsquashhash', | |
| 2154 ] | |
| 2155 | 2189 |
| 2156 def GetRieveldObjForPresubmit(self): | 2190 def GetRieveldObjForPresubmit(self): |
| 2157 class ThisIsNotRietveldIssue(object): | 2191 class ThisIsNotRietveldIssue(object): |
| 2158 def __nonzero__(self): | 2192 def __nonzero__(self): |
| 2159 # This is a hack to make presubmit_support think that rietveld is not | 2193 # This is a hack to make presubmit_support think that rietveld is not |
| 2160 # defined, yet still ensure that calls directly result in a decent | 2194 # defined, yet still ensure that calls directly result in a decent |
| 2161 # exception message below. | 2195 # exception message below. |
| 2162 return False | 2196 return False |
| 2163 | 2197 |
| 2164 def __getattr__(self, attr): | 2198 def __getattr__(self, attr): |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2267 return 1 | 2301 return 1 |
| 2268 detail = self._GetChangeDetail(['CURRENT_REVISION', 'LABELS']) | 2302 detail = self._GetChangeDetail(['CURRENT_REVISION', 'LABELS']) |
| 2269 if u'Commit-Queue' in detail.get('labels', {}): | 2303 if u'Commit-Queue' in detail.get('labels', {}): |
| 2270 if not force: | 2304 if not force: |
| 2271 ask_for_data('\nIt seems this repository has a Commit Queue, ' | 2305 ask_for_data('\nIt seems this repository has a Commit Queue, ' |
| 2272 'which can test and land changes for you. ' | 2306 'which can test and land changes for you. ' |
| 2273 'Are you sure you wish to bypass it?\n' | 2307 'Are you sure you wish to bypass it?\n' |
| 2274 'Press Enter to continue, Ctrl+C to abort.') | 2308 'Press Enter to continue, Ctrl+C to abort.') |
| 2275 | 2309 |
| 2276 differs = True | 2310 differs = True |
| 2277 last_upload = RunGit(['config', | 2311 last_upload = RunGit(['config', self._GitBranchSetting('gerritsquashhash')], |
| 2278 'branch.%s.gerritsquashhash' % self.GetBranch()], | |
| 2279 error_ok=True).strip() | 2312 error_ok=True).strip() |
| 2280 # Note: git diff outputs nothing if there is no diff. | 2313 # Note: git diff outputs nothing if there is no diff. |
| 2281 if not last_upload or RunGit(['diff', last_upload]).strip(): | 2314 if not last_upload or RunGit(['diff', last_upload]).strip(): |
| 2282 print('WARNING: some changes from local branch haven\'t been uploaded') | 2315 print('WARNING: some changes from local branch haven\'t been uploaded') |
| 2283 else: | 2316 else: |
| 2284 if detail['current_revision'] == last_upload: | 2317 if detail['current_revision'] == last_upload: |
| 2285 differs = False | 2318 differs = False |
| 2286 else: | 2319 else: |
| 2287 print('WARNING: local branch contents differ from latest uploaded ' | 2320 print('WARNING: local branch contents differ from latest uploaded ' |
| 2288 'patchset') | 2321 'patchset') |
| (...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2571 if options.squash: | 2604 if options.squash: |
| 2572 regex = re.compile(r'remote:\s+https?://[\w\-\.\/]*/(\d+)\s.*') | 2605 regex = re.compile(r'remote:\s+https?://[\w\-\.\/]*/(\d+)\s.*') |
| 2573 change_numbers = [m.group(1) | 2606 change_numbers = [m.group(1) |
| 2574 for m in map(regex.match, push_stdout.splitlines()) | 2607 for m in map(regex.match, push_stdout.splitlines()) |
| 2575 if m] | 2608 if m] |
| 2576 if len(change_numbers) != 1: | 2609 if len(change_numbers) != 1: |
| 2577 DieWithError( | 2610 DieWithError( |
| 2578 ('Created|Updated %d issues on Gerrit, but only 1 expected.\n' | 2611 ('Created|Updated %d issues on Gerrit, but only 1 expected.\n' |
| 2579 'Change-Id: %s') % (len(change_numbers), change_id)) | 2612 'Change-Id: %s') % (len(change_numbers), change_id)) |
| 2580 self.SetIssue(change_numbers[0]) | 2613 self.SetIssue(change_numbers[0]) |
| 2581 RunGit(['config', 'branch.%s.gerritsquashhash' % self.GetBranch(), | 2614 self._GitSetBranchConfigValue('gerritsquashhash', ref_to_push) |
| 2582 ref_to_push]) | |
| 2583 return 0 | 2615 return 0 |
| 2584 | 2616 |
| 2585 def _AddChangeIdToCommitMessage(self, options, args): | 2617 def _AddChangeIdToCommitMessage(self, options, args): |
| 2586 """Re-commits using the current message, assumes the commit hook is in | 2618 """Re-commits using the current message, assumes the commit hook is in |
| 2587 place. | 2619 place. |
| 2588 """ | 2620 """ |
| 2589 log_desc = options.message or CreateDescriptionFromLog(args) | 2621 log_desc = options.message or CreateDescriptionFromLog(args) |
| 2590 git_command = ['commit', '--amend', '-m', log_desc] | 2622 git_command = ['commit', '--amend', '-m', log_desc] |
| 2591 RunGit(git_command) | 2623 RunGit(git_command) |
| 2592 new_log_desc = CreateDescriptionFromLog(args) | 2624 new_log_desc = CreateDescriptionFromLog(args) |
| (...skipping 2479 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5072 def find_issues(issueprefix): | 5104 def find_issues(issueprefix): |
| 5073 output = RunGit(['config', '--local', '--get-regexp', | 5105 output = RunGit(['config', '--local', '--get-regexp', |
| 5074 r'branch\..*\.%s' % issueprefix], | 5106 r'branch\..*\.%s' % issueprefix], |
| 5075 error_ok=True) | 5107 error_ok=True) |
| 5076 for key, issue in [x.split() for x in output.splitlines()]: | 5108 for key, issue in [x.split() for x in output.splitlines()]: |
| 5077 if issue == target_issue: | 5109 if issue == target_issue: |
| 5078 yield re.sub(r'branch\.(.*)\.%s' % issueprefix, r'\1', key) | 5110 yield re.sub(r'branch\.(.*)\.%s' % issueprefix, r'\1', key) |
| 5079 | 5111 |
| 5080 branches = [] | 5112 branches = [] |
| 5081 for cls in _CODEREVIEW_IMPLEMENTATIONS.values(): | 5113 for cls in _CODEREVIEW_IMPLEMENTATIONS.values(): |
| 5082 branches.extend(find_issues(cls.IssueSettingSuffix())) | 5114 branches.extend(find_issues(cls.IssueConfigKey())) |
| 5083 if len(branches) == 0: | 5115 if len(branches) == 0: |
| 5084 print('No branch found for issue %s.' % target_issue) | 5116 print('No branch found for issue %s.' % target_issue) |
| 5085 return 1 | 5117 return 1 |
| 5086 if len(branches) == 1: | 5118 if len(branches) == 1: |
| 5087 RunGit(['checkout', branches[0]]) | 5119 RunGit(['checkout', branches[0]]) |
| 5088 else: | 5120 else: |
| 5089 print('Multiple branches match issue %s:' % target_issue) | 5121 print('Multiple branches match issue %s:' % target_issue) |
| 5090 for i in range(len(branches)): | 5122 for i in range(len(branches)): |
| 5091 print('%d: %s' % (i, branches[i])) | 5123 print('%d: %s' % (i, branches[i])) |
| 5092 which = raw_input('Choose by index: ') | 5124 which = raw_input('Choose by index: ') |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5153 if __name__ == '__main__': | 5185 if __name__ == '__main__': |
| 5154 # These affect sys.stdout so do it outside of main() to simplify mocks in | 5186 # These affect sys.stdout so do it outside of main() to simplify mocks in |
| 5155 # unit testing. | 5187 # unit testing. |
| 5156 fix_encoding.fix_encoding() | 5188 fix_encoding.fix_encoding() |
| 5157 setup_color.init() | 5189 setup_color.init() |
| 5158 try: | 5190 try: |
| 5159 sys.exit(main(sys.argv[1:])) | 5191 sys.exit(main(sys.argv[1:])) |
| 5160 except KeyboardInterrupt: | 5192 except KeyboardInterrupt: |
| 5161 sys.stderr.write('interrupted\n') | 5193 sys.stderr.write('interrupted\n') |
| 5162 sys.exit(1) | 5194 sys.exit(1) |
| OLD | NEW |