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

Side by Side Diff: git_cl.py

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

Powered by Google App Engine
This is Rietveld 408576698