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

Side by Side Diff: tools/check_git_config.py

Issue 488243002: Show additional warning about managed workflow. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | 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 2014 The Chromium Authors. All rights reserved. 2 # Copyright 2014 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 """Script that attempts to push to a special git repository to verify that git 6 """Script that attempts to push to a special git repository to verify that git
7 credentials are configured correctly. It also verifies that gclient solution is 7 credentials are configured correctly. It also verifies that gclient solution is
8 configured to use git checkout. 8 configured to use git checkout.
9 9
10 It will be added as gclient hook shortly before Chromium switches to git and 10 It will be added as gclient hook shortly before Chromium switches to git and
(...skipping 26 matching lines...) Expand all
37 37
38 38
39 # Absolute path to src/ directory. 39 # Absolute path to src/ directory.
40 REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 40 REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
41 41
42 # Absolute path to a file with gclient solutions. 42 # Absolute path to a file with gclient solutions.
43 GCLIENT_CONFIG = os.path.join(os.path.dirname(REPO_ROOT), '.gclient') 43 GCLIENT_CONFIG = os.path.join(os.path.dirname(REPO_ROOT), '.gclient')
44 44
45 # Incremented whenever some changes to scrip logic are made. Change in version 45 # Incremented whenever some changes to scrip logic are made. Change in version
46 # will cause the check to be rerun on next gclient runhooks invocation. 46 # will cause the check to be rerun on next gclient runhooks invocation.
47 CHECKER_VERSION = 0 47 CHECKER_VERSION = 1
48 48
49 # Do not attempt to upload a report after this date. 49 # Do not attempt to upload a report after this date.
50 UPLOAD_DISABLE_TS = datetime.datetime(2014, 10, 1) 50 UPLOAD_DISABLE_TS = datetime.datetime(2014, 10, 1)
51 51
52 # URL to POST json with results to. 52 # URL to POST json with results to.
53 MOTHERSHIP_URL = ( 53 MOTHERSHIP_URL = (
54 'https://chromium-git-access.appspot.com/' 54 'https://chromium-git-access.appspot.com/'
55 'git_access/api/v1/reports/access_check') 55 'git_access/api/v1/reports/access_check')
56 56
57 # Repository to push test commits to. 57 # Repository to push test commits to.
58 TEST_REPO_URL = 'https://chromium.googlesource.com/a/playground/access_test' 58 TEST_REPO_URL = 'https://chromium.googlesource.com/a/playground/access_test'
59 59
60 # Git-compatible gclient solution. 60 # Git-compatible gclient solution.
61 GOOD_GCLIENT_SOLUTION = { 61 GOOD_GCLIENT_SOLUTION = {
62 'name': 'src', 62 'name': 'src',
63 'deps_file': '.DEPS.git', 63 'deps_file': '.DEPS.git',
64 'managed': False, 64 'managed': False,
65 'url': 'https://chromium.googlesource.com/chromium/src.git', 65 'url': 'https://chromium.googlesource.com/chromium/src.git',
66 } 66 }
67 67
68 # Possible chunks of git push response in case .netrc is misconfigured. 68 # Possible chunks of git push response in case .netrc is misconfigured.
69 BAD_ACL_ERRORS = ( 69 BAD_ACL_ERRORS = (
70 '(prohibited by Gerrit)', 70 '(prohibited by Gerrit)',
71 'does not match your user account', 71 'does not match your user account',
72 'Git repository not found',
72 'Invalid user name or password', 73 'Invalid user name or password',
73 'Please make sure you have the correct access rights', 74 'Please make sure you have the correct access rights',
74 ) 75 )
75 76
77 # Git executable to call.
78 GIT_EXE = 'git.bat' if sys.platform == 'win32' else 'git'
79
76 80
77 def is_on_bot(): 81 def is_on_bot():
78 """True when running under buildbot.""" 82 """True when running under buildbot."""
79 return os.environ.get('CHROME_HEADLESS') == '1' 83 return os.environ.get('CHROME_HEADLESS') == '1'
80 84
81 85
82 def is_in_google_corp(): 86 def is_in_google_corp():
83 """True when running in google corp network.""" 87 """True when running in google corp network."""
84 try: 88 try:
85 return socket.getfqdn().endswith('.corp.google.com') 89 return socket.getfqdn().endswith('.corp.google.com')
(...skipping 12 matching lines...) Expand all
98 return os.path.exists(os.path.join(REPO_ROOT, '.svn')) 102 return os.path.exists(os.path.join(REPO_ROOT, '.svn'))
99 103
100 104
101 def read_git_config(prop): 105 def read_git_config(prop):
102 """Reads git config property of src.git repo. 106 """Reads git config property of src.git repo.
103 107
104 Returns empty string in case of errors. 108 Returns empty string in case of errors.
105 """ 109 """
106 try: 110 try:
107 proc = subprocess.Popen( 111 proc = subprocess.Popen(
108 ['git', 'config', prop], stdout=subprocess.PIPE, cwd=REPO_ROOT) 112 [GIT_EXE, 'config', prop], stdout=subprocess.PIPE, cwd=REPO_ROOT)
109 out, _ = proc.communicate() 113 out, _ = proc.communicate()
110 return out.strip() 114 return out.strip()
111 except OSError as exc: 115 except OSError as exc:
112 if exc.errno != errno.ENOENT: 116 if exc.errno != errno.ENOENT:
113 logging.exception('Unexpected error when calling git') 117 logging.exception('Unexpected error when calling git')
114 return '' 118 return ''
115 119
116 120
117 def read_netrc_user(netrc_obj, host): 121 def read_netrc_user(netrc_obj, host):
118 """Reads 'user' field of a host entry in netrc. 122 """Reads 'user' field of a host entry in netrc.
119 123
120 Returns empty string if netrc is missing, or host is not there. 124 Returns empty string if netrc is missing, or host is not there.
121 """ 125 """
122 if not netrc_obj: 126 if not netrc_obj:
123 return '' 127 return ''
124 entry = netrc_obj.authenticators(host) 128 entry = netrc_obj.authenticators(host)
125 if not entry: 129 if not entry:
126 return '' 130 return ''
127 return entry[0] 131 return entry[0]
128 132
129 133
130 def get_git_version(): 134 def get_git_version():
131 """Returns version of git or None if git is not available.""" 135 """Returns version of git or None if git is not available."""
132 try: 136 try:
133 proc = subprocess.Popen(['git', '--version'], stdout=subprocess.PIPE) 137 proc = subprocess.Popen([GIT_EXE, '--version'], stdout=subprocess.PIPE)
134 out, _ = proc.communicate() 138 out, _ = proc.communicate()
135 return out.strip() if proc.returncode == 0 else '' 139 return out.strip() if proc.returncode == 0 else ''
136 except OSError as exc: 140 except OSError as exc:
137 if exc.errno != errno.ENOENT: 141 if exc.errno != errno.ENOENT:
138 logging.exception('Unexpected error when calling git') 142 logging.exception('Unexpected error when calling git')
139 return '' 143 return ''
140 144
141 145
142 def read_gclient_solution(): 146 def read_gclient_solution():
143 """Read information about 'src' gclient solution from .gclient file. 147 """Read information about 'src' gclient solution from .gclient file.
144 148
145 Returns tuple: 149 Returns tuple:
146 (url, deps_file, managed) 150 (url, deps_file, managed)
147 or 151 or
148 (None, None, None) if no such solution. 152 (None, None, None) if no such solution.
149 """ 153 """
150 try: 154 try:
151 env = {} 155 env = {}
152 execfile(GCLIENT_CONFIG, env, env) 156 execfile(GCLIENT_CONFIG, env, env)
153 for sol in env['solutions']: 157 for sol in env['solutions']:
154 if sol['name'] == 'src': 158 if sol['name'] == 'src':
155 return sol.get('url'), sol.get('deps_file'), sol.get('managed') 159 return sol.get('url'), sol.get('deps_file'), sol.get('managed')
156 return None, None, None 160 return None, None, None
157 except Exception: 161 except Exception:
158 logging.exception('Failed to read .gclient solution') 162 logging.exception('Failed to read .gclient solution')
159 return None, None, None 163 return None, None, None
160 164
161 165
166 def read_git_insteadof(host):
167 """Reads relevant insteadOf config entries."""
168 try:
169 proc = subprocess.Popen([GIT_EXE, 'config', '-l'], stdout=subprocess.PIPE)
170 out, _ = proc.communicate()
171 lines = []
172 for line in out.strip().split('\n'):
173 line = line.lower()
174 if 'insteadof=' in line and host in line:
175 lines.append(line)
176 return '\n'.join(lines)
177 except OSError as exc:
178 if exc.errno != errno.ENOENT:
179 logging.exception('Unexpected error when calling git')
180 return ''
181
182
162 def scan_configuration(): 183 def scan_configuration():
163 """Scans local environment for git related configuration values.""" 184 """Scans local environment for git related configuration values."""
164 # Git checkout? 185 # Git checkout?
165 is_git = is_using_git() 186 is_git = is_using_git()
166 187
167 # On Windows HOME should be set. 188 # On Windows HOME should be set.
168 if 'HOME' in os.environ: 189 if 'HOME' in os.environ:
169 netrc_path = os.path.join( 190 netrc_path = os.path.join(
170 os.environ['HOME'], 191 os.environ['HOME'],
171 '_netrc' if sys.platform.startswith('win') else '.netrc') 192 '_netrc' if sys.platform.startswith('win') else '.netrc')
(...skipping 19 matching lines...) Expand all
191 'checker_version': CHECKER_VERSION, 212 'checker_version': CHECKER_VERSION,
192 'is_git': is_git, 213 'is_git': is_git,
193 'is_home_set': 'HOME' in os.environ, 214 'is_home_set': 'HOME' in os.environ,
194 'is_using_netrc': is_using_netrc, 215 'is_using_netrc': is_using_netrc,
195 'netrc_file_mode': os.stat(netrc_path).st_mode if is_using_netrc else 0, 216 'netrc_file_mode': os.stat(netrc_path).st_mode if is_using_netrc else 0,
196 'git_version': get_git_version(), 217 'git_version': get_git_version(),
197 'platform': sys.platform, 218 'platform': sys.platform,
198 'username': getpass.getuser(), 219 'username': getpass.getuser(),
199 'git_user_email': read_git_config('user.email') if is_git else '', 220 'git_user_email': read_git_config('user.email') if is_git else '',
200 'git_user_name': read_git_config('user.name') if is_git else '', 221 'git_user_name': read_git_config('user.name') if is_git else '',
222 'git_insteadof': read_git_insteadof('chromium.googlesource.com'),
201 'chromium_netrc_email': 223 'chromium_netrc_email':
202 read_netrc_user(netrc_obj, 'chromium.googlesource.com'), 224 read_netrc_user(netrc_obj, 'chromium.googlesource.com'),
203 'chrome_internal_netrc_email': 225 'chrome_internal_netrc_email':
204 read_netrc_user(netrc_obj, 'chrome-internal.googlesource.com'), 226 read_netrc_user(netrc_obj, 'chrome-internal.googlesource.com'),
205 'gclient_deps': gclient_deps, 227 'gclient_deps': gclient_deps,
206 'gclient_managed': gclient_managed, 228 'gclient_managed': gclient_managed,
207 'gclient_url': gclient_url, 229 'gclient_url': gclient_url,
208 } 230 }
209 231
210 232
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
303 ref = 'refs/push-test/%s' % conf['chromium_netrc_email'] 325 ref = 'refs/push-test/%s' % conf['chromium_netrc_email']
304 326
305 push_works = False 327 push_works = False
306 flake = False 328 flake = False
307 started = time.time() 329 started = time.time()
308 try: 330 try:
309 logging.warning('Checking push access to the git repository...') 331 logging.warning('Checking push access to the git repository...')
310 with temp_directory() as tmp: 332 with temp_directory() as tmp:
311 # Prepare a simple commit on a new timeline. 333 # Prepare a simple commit on a new timeline.
312 runner = Runner(tmp, verbose) 334 runner = Runner(tmp, verbose)
313 runner.run(['git', 'init', '.']) 335 runner.run([GIT_EXE, 'init', '.'])
314 if conf['git_user_name']: 336 if conf['git_user_name']:
315 runner.run(['git', 'config', 'user.name', conf['git_user_name']]) 337 runner.run([GIT_EXE, 'config', 'user.name', conf['git_user_name']])
316 if conf['git_user_email']: 338 if conf['git_user_email']:
317 runner.run(['git', 'config', 'user.email', conf['git_user_email']]) 339 runner.run([GIT_EXE, 'config', 'user.email', conf['git_user_email']])
318 with open(os.path.join(tmp, 'timestamp'), 'w') as f: 340 with open(os.path.join(tmp, 'timestamp'), 'w') as f:
319 f.write(str(int(time.time() * 1000))) 341 f.write(str(int(time.time() * 1000)))
320 runner.run(['git', 'add', 'timestamp']) 342 runner.run([GIT_EXE, 'add', 'timestamp'])
321 runner.run(['git', 'commit', '-m', 'Push test.']) 343 runner.run([GIT_EXE, 'commit', '-m', 'Push test.'])
322 # Try to push multiple times if it fails due to issues other than ACLs. 344 # Try to push multiple times if it fails due to issues other than ACLs.
323 attempt = 0 345 attempt = 0
324 while attempt < 5: 346 while attempt < 5:
325 attempt += 1 347 attempt += 1
326 logging.info('Pushing to %s %s', TEST_REPO_URL, ref) 348 logging.info('Pushing to %s %s', TEST_REPO_URL, ref)
327 ret = runner.run(['git', 'push', TEST_REPO_URL, 'HEAD:%s' % ref, '-f']) 349 ret = runner.run(
350 [GIT_EXE, 'push', TEST_REPO_URL, 'HEAD:%s' % ref, '-f'])
328 if not ret: 351 if not ret:
329 push_works = True 352 push_works = True
330 break 353 break
331 if any(x in runner.log[-1] for x in BAD_ACL_ERRORS): 354 if any(x in runner.log[-1] for x in BAD_ACL_ERRORS):
332 push_works = False 355 push_works = False
333 break 356 break
334 except Exception: 357 except Exception:
335 logging.exception('Unexpected exception when pushing') 358 logging.exception('Unexpected exception when pushing')
336 flake = True 359 flake = True
337 360
(...skipping 11 matching lines...) Expand all
349 push_log='\n'.join(runner.log), 372 push_log='\n'.join(runner.log),
350 push_duration_ms=int((time.time() - started) * 1000)) 373 push_duration_ms=int((time.time() - started) * 1000))
351 return uploaded and not flake 374 return uploaded and not flake
352 375
353 376
354 def check_gclient_config(conf): 377 def check_gclient_config(conf):
355 """Shows warning if gclient solution is not properly configured for git.""" 378 """Shows warning if gclient solution is not properly configured for git."""
356 current = { 379 current = {
357 'name': 'src', 380 'name': 'src',
358 'deps_file': conf['gclient_deps'], 381 'deps_file': conf['gclient_deps'],
359 'managed': conf['gclient_managed'], 382 'managed': conf['gclient_managed'] or False,
360 'url': conf['gclient_url'], 383 'url': conf['gclient_url'],
361 } 384 }
362 if current != GOOD_GCLIENT_SOLUTION: 385 good = GOOD_GCLIENT_SOLUTION
386 if current == good:
387 return
388 # Show big warning if url or deps_file is wrong.
389 if current['url'] != good['url'] or current['deps_file'] != good['deps_file']:
363 print '-' * 80 390 print '-' * 80
364 print 'Your gclient solution is not set to use supported git workflow!' 391 print 'Your gclient solution is not set to use supported git workflow!'
365 print 392 print
366 print 'Your \'src\' solution (in %s):' % GCLIENT_CONFIG 393 print 'Your \'src\' solution (in %s):' % GCLIENT_CONFIG
367 print pprint.pformat(current, indent=2) 394 print pprint.pformat(current, indent=2)
368 print 395 print
369 print 'Correct \'src\' solution to use git:' 396 print 'Correct \'src\' solution to use git:'
370 print pprint.pformat(GOOD_GCLIENT_SOLUTION, indent=2) 397 print pprint.pformat(good, indent=2)
371 print 398 print
372 print 'Please update your .gclient file ASAP.' 399 print 'Please update your .gclient file ASAP.'
373 print '-' * 80 400 print '-' * 80
401 # Show smaller (additional) warning about managed workflow.
402 if current['managed']:
403 print '-' * 80
404 print (
405 'You are using managed gclient mode with git, which was deprecated '
406 'on 8/22/13:')
407 print (
408 'https://groups.google.com/a/chromium.org/'
409 'forum/#!topic/chromium-dev/n9N5N3JL2_U')
410 print
411 print (
412 'It is strongly advised to switch to unmanaged mode. For more '
413 'information about managed mode and reasons for its deprecation see:')
414 print 'http://www.chromium.org/developers/how-tos/get-the-code#Managed_mode'
415 print
416 print (
417 'There\'s also a large suite of tools to assist managing git '
418 'checkouts.\nSee \'man depot_tools\' (or read '
419 'depot_tools/man/html/depot_tools.html).')
420 print '-' * 80
374 421
375 422
376 def upload_report( 423 def upload_report(
377 conf, report_url, verbose, push_works, push_log, push_duration_ms): 424 conf, report_url, verbose, push_works, push_log, push_duration_ms):
378 """Posts report to the server, returns True if server accepted it. 425 """Posts report to the server, returns True if server accepted it.
379 426
380 Uploads the report only if script is running in Google corp network. Otherwise 427 Uploads the report only if script is running in Google corp network. Otherwise
381 just prints the report. 428 just prints the report.
382 """ 429 """
383 report = conf.copy() 430 report = conf.copy()
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
479 write_last_configuration(config) 526 write_last_configuration(config)
480 else: 527 else:
481 logging.warning('Check failed and will be retried on the next run') 528 logging.warning('Check failed and will be retried on the next run')
482 except Exception: 529 except Exception:
483 logging.exception('Unexpected exception when performing git access check') 530 logging.exception('Unexpected exception when performing git access check')
484 return 0 531 return 0
485 532
486 533
487 if __name__ == '__main__': 534 if __name__ == '__main__':
488 sys.exit(main(sys.argv[1:])) 535 sys.exit(main(sys.argv[1:]))
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698