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

Side by Side Diff: git_cl.py

Issue 496073002: Add support for landing to pending ref. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
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 (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.""" 8 """A git-command for integrating reviews on Rietveld."""
9 9
10 from distutils.version import LooseVersion 10 from distutils.version import LooseVersion
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
67 print >> sys.stderr, message 67 print >> sys.stderr, message
68 sys.exit(1) 68 sys.exit(1)
69 69
70 70
71 def GetNoGitPagerEnv(): 71 def GetNoGitPagerEnv():
72 env = os.environ.copy() 72 env = os.environ.copy()
73 # 'cat' is a magical git string that disables pagers on all platforms. 73 # 'cat' is a magical git string that disables pagers on all platforms.
74 env['GIT_PAGER'] = 'cat' 74 env['GIT_PAGER'] = 'cat'
75 return env 75 return env
76 76
77
77 def RunCommand(args, error_ok=False, error_message=None, **kwargs): 78 def RunCommand(args, error_ok=False, error_message=None, **kwargs):
78 try: 79 try:
79 return subprocess2.check_output(args, shell=False, **kwargs) 80 return subprocess2.check_output(args, shell=False, **kwargs)
80 except subprocess2.CalledProcessError as e: 81 except subprocess2.CalledProcessError as e:
81 logging.debug('Failed running %s', args) 82 logging.debug('Failed running %s', args)
82 if not error_ok: 83 if not error_ok:
83 DieWithError( 84 DieWithError(
84 'Command "%s" failed.\n%s' % ( 85 'Command "%s" failed.\n%s' % (
85 ' '.join(args), error_message or e.stdout or '')) 86 ' '.join(args), error_message or e.stdout or ''))
86 return e.stdout 87 return e.stdout
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
273 self.cc = None 274 self.cc = None
274 self.root = None 275 self.root = None
275 self.is_git_svn = None 276 self.is_git_svn = None
276 self.svn_branch = None 277 self.svn_branch = None
277 self.tree_status_url = None 278 self.tree_status_url = None
278 self.viewvc_url = None 279 self.viewvc_url = None
279 self.updated = False 280 self.updated = False
280 self.is_gerrit = None 281 self.is_gerrit = None
281 self.git_editor = None 282 self.git_editor = None
282 self.project = None 283 self.project = None
284 self.pending_ref_prefix = None
283 285
284 def LazyUpdateIfNeeded(self): 286 def LazyUpdateIfNeeded(self):
285 """Updates the settings from a codereview.settings file, if available.""" 287 """Updates the settings from a codereview.settings file, if available."""
286 if not self.updated: 288 if not self.updated:
287 # The only value that actually changes the behavior is 289 # The only value that actually changes the behavior is
288 # autoupdate = "false". Everything else means "true". 290 # autoupdate = "false". Everything else means "true".
289 autoupdate = RunGit(['config', 'rietveld.autoupdate'], 291 autoupdate = RunGit(['config', 'rietveld.autoupdate'],
290 error_ok=True 292 error_ok=True
291 ).strip().lower() 293 ).strip().lower()
292 294
(...skipping 25 matching lines...) Expand all
318 return RunGit(['rev-parse', '--show-cdup']).strip() 320 return RunGit(['rev-parse', '--show-cdup']).strip()
319 321
320 def GetRoot(self): 322 def GetRoot(self):
321 if self.root is None: 323 if self.root is None:
322 self.root = os.path.abspath(self.GetRelativeRoot()) 324 self.root = os.path.abspath(self.GetRelativeRoot())
323 return self.root 325 return self.root
324 326
325 def GetIsGitSvn(self): 327 def GetIsGitSvn(self):
326 """Return true if this repo looks like it's using git-svn.""" 328 """Return true if this repo looks like it's using git-svn."""
327 if self.is_git_svn is None: 329 if self.is_git_svn is None:
328 # If you have any "svn-remote.*" config keys, we think you're using svn. 330 if self.GetPendingRefPrefix():
329 self.is_git_svn = RunGitWithCode( 331 # If PENDING_REF_PREFIX is set then it's a pure git repo no matter what.
330 ['config', '--local', '--get-regexp', r'^svn-remote\.'])[0] == 0 332 self.is_git_svn = False
333 else:
334 # If you have any "svn-remote.*" config keys, we think you're using svn.
335 self.is_git_svn = RunGitWithCode(
336 ['config', '--local', '--get-regexp', r'^svn-remote\.'])[0] == 0
331 return self.is_git_svn 337 return self.is_git_svn
332 338
333 def GetSVNBranch(self): 339 def GetSVNBranch(self):
334 if self.svn_branch is None: 340 if self.svn_branch is None:
335 if not self.GetIsGitSvn(): 341 if not self.GetIsGitSvn():
336 DieWithError('Repo doesn\'t appear to be a git-svn repo.') 342 DieWithError('Repo doesn\'t appear to be a git-svn repo.')
337 343
338 # Try to figure out which remote branch we're based on. 344 # Try to figure out which remote branch we're based on.
339 # Strategy: 345 # Strategy:
340 # 1) iterate through our branch history and find the svn URL. 346 # 1) iterate through our branch history and find the svn URL.
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
439 445
440 def GetLintIgnoreRegex(self): 446 def GetLintIgnoreRegex(self):
441 return (self._GetRietveldConfig('cpplint-ignore-regex', error_ok=True) or 447 return (self._GetRietveldConfig('cpplint-ignore-regex', error_ok=True) or
442 DEFAULT_LINT_IGNORE_REGEX) 448 DEFAULT_LINT_IGNORE_REGEX)
443 449
444 def GetProject(self): 450 def GetProject(self):
445 if not self.project: 451 if not self.project:
446 self.project = self._GetRietveldConfig('project', error_ok=True) 452 self.project = self._GetRietveldConfig('project', error_ok=True)
447 return self.project 453 return self.project
448 454
455 def GetPendingRefPrefix(self):
456 if not self.pending_ref_prefix:
457 self.pending_ref_prefix = self._GetRietveldConfig(
458 'pending-ref-prefix', error_ok=True)
459 if self.pending_ref_prefix:
460 self.pending_ref_prefix = self.pending_ref_prefix.rstrip('/') + '/'
iannucci 2014/08/21 20:32:20 why not just take it as-is and then commit the rig
Vadim Sh. 2014/08/21 21:14:35 Okay... just defensive programming.
461 return self.pending_ref_prefix
462
449 def _GetRietveldConfig(self, param, **kwargs): 463 def _GetRietveldConfig(self, param, **kwargs):
450 return self._GetConfig('rietveld.' + param, **kwargs) 464 return self._GetConfig('rietveld.' + param, **kwargs)
451 465
452 def _GetConfig(self, param, **kwargs): 466 def _GetConfig(self, param, **kwargs):
453 self.LazyUpdateIfNeeded() 467 self.LazyUpdateIfNeeded()
454 return RunGit(['config', param], **kwargs).strip() 468 return RunGit(['config', param], **kwargs).strip()
455 469
456 470
457 def ShortBranchName(branch): 471 def ShortBranchName(branch):
458 """Convert a name like 'refs/heads/foo' to just 'foo'.""" 472 """Convert a name like 'refs/heads/foo' to just 'foo'."""
(...skipping 619 matching lines...) Expand 10 before | Expand all | Expand 10 after
1078 # Only server setting is required. Other settings can be absent. 1092 # Only server setting is required. Other settings can be absent.
1079 # In that case, we ignore errors raised during option deletion attempt. 1093 # In that case, we ignore errors raised during option deletion attempt.
1080 SetProperty('cc', 'CC_LIST', unset_error_ok=True) 1094 SetProperty('cc', 'CC_LIST', unset_error_ok=True)
1081 SetProperty('private', 'PRIVATE', unset_error_ok=True) 1095 SetProperty('private', 'PRIVATE', unset_error_ok=True)
1082 SetProperty('tree-status-url', 'STATUS', unset_error_ok=True) 1096 SetProperty('tree-status-url', 'STATUS', unset_error_ok=True)
1083 SetProperty('viewvc-url', 'VIEW_VC', unset_error_ok=True) 1097 SetProperty('viewvc-url', 'VIEW_VC', unset_error_ok=True)
1084 SetProperty('bug-prefix', 'BUG_PREFIX', unset_error_ok=True) 1098 SetProperty('bug-prefix', 'BUG_PREFIX', unset_error_ok=True)
1085 SetProperty('cpplint-regex', 'LINT_REGEX', unset_error_ok=True) 1099 SetProperty('cpplint-regex', 'LINT_REGEX', unset_error_ok=True)
1086 SetProperty('cpplint-ignore-regex', 'LINT_IGNORE_REGEX', unset_error_ok=True) 1100 SetProperty('cpplint-ignore-regex', 'LINT_IGNORE_REGEX', unset_error_ok=True)
1087 SetProperty('project', 'PROJECT', unset_error_ok=True) 1101 SetProperty('project', 'PROJECT', unset_error_ok=True)
1102 SetProperty('pending-ref-prefix', 'PENDING_REF_PREFIX', unset_error_ok=True)
1088 1103
1089 if 'GERRIT_HOST' in keyvals: 1104 if 'GERRIT_HOST' in keyvals:
1090 RunGit(['config', 'gerrit.host', keyvals['GERRIT_HOST']]) 1105 RunGit(['config', 'gerrit.host', keyvals['GERRIT_HOST']])
1091 1106
1092 if 'PUSH_URL_CONFIG' in keyvals and 'ORIGIN_URL_CONFIG' in keyvals: 1107 if 'PUSH_URL_CONFIG' in keyvals and 'ORIGIN_URL_CONFIG' in keyvals:
1093 #should be of the form 1108 #should be of the form
1094 #PUSH_URL_CONFIG: url.ssh://gitrw.chromium.org.pushinsteadof 1109 #PUSH_URL_CONFIG: url.ssh://gitrw.chromium.org.pushinsteadof
1095 #ORIGIN_URL_CONFIG: http://src.chromium.org/git 1110 #ORIGIN_URL_CONFIG: http://src.chromium.org/git
1096 RunGit(['config', keyvals['PUSH_URL_CONFIG'], 1111 RunGit(['config', keyvals['PUSH_URL_CONFIG'],
1097 keyvals['ORIGIN_URL_CONFIG']]) 1112 keyvals['ORIGIN_URL_CONFIG']])
(...skipping 742 matching lines...) Expand 10 before | Expand all | Expand 10 after
1840 print 1855 print
1841 print 'Either reparent this branch on top of origin/master:' 1856 print 'Either reparent this branch on top of origin/master:'
1842 print ' git reparent-branch --root' 1857 print ' git reparent-branch --root'
1843 print 1858 print
1844 print 'OR run `git rebase-update` if you think the parent branch is already' 1859 print 'OR run `git rebase-update` if you think the parent branch is already'
1845 print 'committed.' 1860 print 'committed.'
1846 print 1861 print
1847 print ' Current parent: %r' % upstream_branch 1862 print ' Current parent: %r' % upstream_branch
1848 return 1 1863 return 1
1849 1864
1850 if not args or cmd == 'push': 1865 if not args or cmd == 'land':
iannucci 2014/08/21 20:32:20 good catch
1851 # Default to merging against our best guess of the upstream branch. 1866 # Default to merging against our best guess of the upstream branch.
1852 args = [cl.GetUpstreamBranch()] 1867 args = [cl.GetUpstreamBranch()]
1853 1868
1854 if options.contributor: 1869 if options.contributor:
1855 if not re.match('^.*\s<\S+@\S+>$', options.contributor): 1870 if not re.match('^.*\s<\S+@\S+>$', options.contributor):
1856 print "Please provide contibutor as 'First Last <email@example.com>'" 1871 print "Please provide contibutor as 'First Last <email@example.com>'"
1857 return 1 1872 return 1
1858 1873
1859 base_branch = args[0] 1874 base_branch = args[0]
1860 base_has_submodules = IsSubmoduleMergeCommit(base_branch) 1875 base_has_submodules = IsSubmoduleMergeCommit(base_branch)
1861 1876
1862 if is_dirty_git_tree(cmd): 1877 if is_dirty_git_tree(cmd):
1863 return 1 1878 return 1
1864 1879
1865 # This rev-list syntax means "show all commits not in my branch that 1880 # This rev-list syntax means "show all commits not in my branch that
1866 # are in base_branch". 1881 # are in base_branch".
1867 upstream_commits = RunGit(['rev-list', '^' + cl.GetBranchRef(), 1882 upstream_commits = RunGit(['rev-list', '^' + cl.GetBranchRef(),
1868 base_branch]).splitlines() 1883 base_branch]).splitlines()
1869 if upstream_commits: 1884 if upstream_commits:
1870 print ('Base branch "%s" has %d commits ' 1885 print ('Base branch "%s" has %d commits '
1871 'not in this branch.' % (base_branch, len(upstream_commits))) 1886 'not in this branch.' % (base_branch, len(upstream_commits)))
1872 print 'Run "git merge %s" before attempting to %s.' % (base_branch, cmd) 1887 print 'Run "git merge %s" before attempting to %s.' % (base_branch, cmd)
1873 return 1 1888 return 1
1874 1889
1875 # This is the revision `svn dcommit` will commit on top of. 1890 # This is the revision `svn dcommit` will commit on top of.
1876 svn_head = RunGit(['log', '--grep=^git-svn-id:', '-1', 1891 svn_head = None
1877 '--pretty=format:%H']) 1892 if cmd == 'dcommit' or base_has_submodules:
iannucci 2014/08/21 20:32:20 dcommit?
1893 svn_head = RunGit(['log', '--grep=^git-svn-id:', '-1',
Vadim Sh. 2014/08/21 19:31:22 This stuff finds svn HEADs in pure git repos... Fo
1894 '--pretty=format:%H'])
1878 1895
1879 if cmd == 'dcommit': 1896 if cmd == 'dcommit':
1880 # If the base_head is a submodule merge commit, the first parent of the 1897 # If the base_head is a submodule merge commit, the first parent of the
1881 # base_head should be a git-svn commit, which is what we're interested in. 1898 # base_head should be a git-svn commit, which is what we're interested in.
1882 base_svn_head = base_branch 1899 base_svn_head = base_branch
1883 if base_has_submodules: 1900 if base_has_submodules:
1884 base_svn_head += '^1' 1901 base_svn_head += '^1'
1885 1902
1886 extra_commits = RunGit(['rev-list', '^' + svn_head, base_svn_head]) 1903 extra_commits = RunGit(['rev-list', '^' + svn_head, base_svn_head])
1887 if extra_commits: 1904 if extra_commits:
1888 print ('This branch has %d additional commits not upstreamed yet.' 1905 print ('This branch has %d additional commits not upstreamed yet.'
1889 % len(extra_commits.splitlines())) 1906 % len(extra_commits.splitlines()))
1890 print ('Upstream "%s" or rebase this branch on top of the upstream trunk ' 1907 print ('Upstream "%s" or rebase this branch on top of the upstream trunk '
1891 'before attempting to %s.' % (base_branch, cmd)) 1908 'before attempting to %s.' % (base_branch, cmd))
1892 return 1 1909 return 1
1893 1910
1894 base_branch = RunGit(['merge-base', base_branch, 'HEAD']).strip() 1911 base_branch = RunGit(['merge-base', base_branch, 'HEAD']).strip()
1895 if not options.bypass_hooks: 1912 if not options.bypass_hooks:
1896 author = None 1913 author = None
1897 if options.contributor: 1914 if options.contributor:
1898 author = re.search(r'\<(.*)\>', options.contributor).group(1) 1915 author = re.search(r'\<(.*)\>', options.contributor).group(1)
1899 hook_results = cl.RunHook( 1916 hook_results = cl.RunHook(
1900 committing=True, 1917 committing=True,
1901 may_prompt=not options.force, 1918 may_prompt=not options.force,
1902 verbose=options.verbose, 1919 verbose=options.verbose,
1903 change=cl.GetChange(base_branch, author)) 1920 change=cl.GetChange(base_branch, author))
1904 if not hook_results.should_continue(): 1921 if not hook_results.should_continue():
1905 return 1 1922 return 1
1906 1923
1907 if cmd == 'dcommit': 1924 # Check the tree status if the tree status URL is set.
Vadim Sh. 2014/08/21 19:31:22 Now checks with 'git cl land' too.
1908 # Check the tree status if the tree status URL is set. 1925 status = GetTreeStatus()
1909 status = GetTreeStatus() 1926 if 'closed' == status:
1910 if 'closed' == status: 1927 print('The tree is closed. Please wait for it to reopen. Use '
1911 print('The tree is closed. Please wait for it to reopen. Use ' 1928 '"git cl %s --bypass-hooks" to commit on a closed tree.' % cmd)
1912 '"git cl dcommit --bypass-hooks" to commit on a closed tree.') 1929 return 1
1913 return 1 1930 elif 'unknown' == status:
1914 elif 'unknown' == status: 1931 print('Unable to determine tree status. Please verify manually and '
1915 print('Unable to determine tree status. Please verify manually and ' 1932 'use "git cl %s --bypass-hooks" to commit on a closed tree.' % cmd)
1916 'use "git cl dcommit --bypass-hooks" to commit on a closed tree.') 1933 return 1
Vadim Sh. 2014/08/21 19:31:22 Now aborts if tree status is unknown, as error mes
1917 else: 1934 else:
1918 breakpad.SendStack( 1935 breakpad.SendStack(
1919 'GitClHooksBypassedCommit', 1936 'GitClHooksBypassedCommit',
1920 'Issue %s/%s bypassed hook when committing (tree status was "%s")' % 1937 'Issue %s/%s bypassed hook when committing (tree status was "%s")' %
1921 (cl.GetRietveldServer(), cl.GetIssue(), GetTreeStatus()), 1938 (cl.GetRietveldServer(), cl.GetIssue(), GetTreeStatus()),
1922 verbose=False) 1939 verbose=False)
1923 1940
1924 change_desc = ChangeDescription(options.message) 1941 change_desc = ChangeDescription(options.message)
1925 if not change_desc.description and cl.GetIssue(): 1942 if not change_desc.description and cl.GetIssue():
1926 change_desc = ChangeDescription(cl.GetDescription()) 1943 change_desc = ChangeDescription(cl.GetDescription())
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
1971 # trunk. Move up to the top of the tree so that git commands that expect a 1988 # trunk. Move up to the top of the tree so that git commands that expect a
1972 # valid CWD won't fail after we check out the merge branch. 1989 # valid CWD won't fail after we check out the merge branch.
1973 rel_base_path = settings.GetRelativeRoot() 1990 rel_base_path = settings.GetRelativeRoot()
1974 if rel_base_path: 1991 if rel_base_path:
1975 os.chdir(rel_base_path) 1992 os.chdir(rel_base_path)
1976 1993
1977 # Stuff our change into the merge branch. 1994 # Stuff our change into the merge branch.
1978 # We wrap in a try...finally block so if anything goes wrong, 1995 # We wrap in a try...finally block so if anything goes wrong,
1979 # we clean up the branches. 1996 # we clean up the branches.
1980 retcode = -1 1997 retcode = -1
1998 used_pending = False
1981 try: 1999 try:
1982 RunGit(['checkout', '-q', '-b', MERGE_BRANCH]) 2000 RunGit(['checkout', '-q', '-b', MERGE_BRANCH])
1983 RunGit(['reset', '--soft', base_branch]) 2001 RunGit(['reset', '--soft', base_branch])
1984 if options.contributor: 2002 if options.contributor:
1985 RunGit( 2003 RunGit(
1986 [ 2004 [
1987 'commit', '--author', options.contributor, 2005 'commit', '--author', options.contributor,
1988 '-m', commit_desc.description, 2006 '-m', commit_desc.description,
1989 ]) 2007 ])
1990 else: 2008 else:
1991 RunGit(['commit', '-m', commit_desc.description]) 2009 RunGit(['commit', '-m', commit_desc.description])
1992 if base_has_submodules: 2010 if base_has_submodules:
1993 cherry_pick_commit = RunGit(['rev-list', 'HEAD^!']).rstrip() 2011 cherry_pick_commit = RunGit(['rev-list', 'HEAD^!']).rstrip()
1994 RunGit(['branch', CHERRY_PICK_BRANCH, svn_head]) 2012 RunGit(['branch', CHERRY_PICK_BRANCH, svn_head])
1995 RunGit(['checkout', CHERRY_PICK_BRANCH]) 2013 RunGit(['checkout', CHERRY_PICK_BRANCH])
1996 RunGit(['cherry-pick', cherry_pick_commit]) 2014 RunGit(['cherry-pick', cherry_pick_commit])
1997 if cmd == 'push': 2015 if cmd == 'land':
1998 # push the merge branch.
1999 remote, branch = cl.FetchUpstreamTuple(cl.GetBranch()) 2016 remote, branch = cl.FetchUpstreamTuple(cl.GetBranch())
2000 retcode, output = RunGitWithCode( 2017 pending_prefix = settings.GetPendingRefPrefix()
2001 ['push', '--porcelain', remote, 'HEAD:%s' % branch]) 2018 if not pending_prefix or branch.startswith(pending_prefix):
2019 # If not using refs/pending/heads/* at all, or target ref is already set
2020 # to pending, then push to the target ref directly.
2021 retcode, output = RunGitWithCode(
2022 ['push', '--porcelain', remote, 'HEAD:%s' % branch])
2023 used_pending = pending_prefix and branch.startswith(pending_prefix)
2024 else:
2025 # Cherry-pick the change on top of pending ref and then push it.
2026 assert branch.startswith('refs/'), branch
2027 assert pending_prefix[-1] == '/', pending_prefix
2028 pending_ref = pending_prefix + branch[len('refs/'):]
2029 retcode, output = PushToGitPending(remote, pending_ref)
2030 used_pending = True
2002 logging.debug(output) 2031 logging.debug(output)
2003 else: 2032 else:
2004 # dcommit the merge branch. 2033 # dcommit the merge branch.
2005 retcode, output = RunGitWithCode(['svn', 'dcommit', 2034 retcode, output = RunGitWithCode(['svn', 'dcommit',
2006 '-C%s' % options.similarity, 2035 '-C%s' % options.similarity,
2007 '--no-rebase', '--rmdir']) 2036 '--no-rebase', '--rmdir'])
2008 finally: 2037 finally:
2009 # And then swap back to the original branch and clean up. 2038 # And then swap back to the original branch and clean up.
2010 RunGit(['checkout', '-q', cl.GetBranch()]) 2039 RunGit(['checkout', '-q', cl.GetBranch()])
2011 RunGit(['branch', '-D', MERGE_BRANCH]) 2040 RunGit(['branch', '-D', MERGE_BRANCH])
2012 if base_has_submodules: 2041 if base_has_submodules:
2013 RunGit(['branch', '-D', CHERRY_PICK_BRANCH]) 2042 RunGit(['branch', '-D', CHERRY_PICK_BRANCH])
2014 2043
2015 if cl.GetIssue(): 2044 if cl.GetIssue():
2016 if cmd == 'dcommit' and 'Committed r' in output: 2045 if cmd == 'dcommit' and 'Committed r' in output:
2017 revision = re.match('.*?\nCommitted r(\\d+)', output, re.DOTALL).group(1) 2046 revision = re.match('.*?\nCommitted r(\\d+)', output, re.DOTALL).group(1)
2018 elif cmd == 'push' and retcode == 0: 2047 elif cmd == 'land' and retcode == 0:
2019 match = (re.match(r'.*?([a-f0-9]{7,})\.\.([a-f0-9]{7,})$', l) 2048 match = (re.match(r'.*?([a-f0-9]{7,})\.\.([a-f0-9]{7,})$', l)
2020 for l in output.splitlines(False)) 2049 for l in output.splitlines(False))
2021 match = filter(None, match) 2050 match = filter(None, match)
2022 if len(match) != 1: 2051 if len(match) != 1:
2023 DieWithError("Couldn't parse ouput to extract the committed hash:\n%s" % 2052 DieWithError("Couldn't parse ouput to extract the committed hash:\n%s" %
2024 output) 2053 output)
2025 revision = match[0].group(2) 2054 revision = match[0].group(2)
2026 else: 2055 else:
2027 return 1 2056 return 1
2057 to_pending = ' to pending' if used_pending else ''
2028 viewvc_url = settings.GetViewVCUrl() 2058 viewvc_url = settings.GetViewVCUrl()
2029 if viewvc_url and revision: 2059 if viewvc_url and revision:
2030 change_desc.append_footer('Committed: ' + viewvc_url + revision) 2060 change_desc.append_footer(
2061 'Committed%s: %s%s' % (to_pending, viewvc_url, revision))
2031 elif revision: 2062 elif revision:
2032 change_desc.append_footer('Committed: ' + revision) 2063 change_desc.append_footer('Committed%s: %s' % (to_pending, revision))
2033 print ('Closing issue ' 2064 print ('Closing issue '
2034 '(you may be prompted for your codereview password)...') 2065 '(you may be prompted for your codereview password)...')
2035 cl.UpdateDescription(change_desc.description) 2066 cl.UpdateDescription(change_desc.description)
2036 cl.CloseIssue() 2067 cl.CloseIssue()
2037 props = cl.GetIssueProperties() 2068 props = cl.GetIssueProperties()
2038 patch_num = len(props['patchsets']) 2069 patch_num = len(props['patchsets'])
2039 comment = "Committed patchset #%d manually as %s" % (patch_num, revision) 2070 comment = "Committed patchset #%d%s manually as %s" % (
2071 patch_num, to_pending, revision)
2040 if options.bypass_hooks: 2072 if options.bypass_hooks:
2041 comment += ' (tree was closed).' if GetTreeStatus() == 'closed' else '.' 2073 comment += ' (tree was closed).' if GetTreeStatus() == 'closed' else '.'
2042 else: 2074 else:
2043 comment += ' (presubmit successful).' 2075 comment += ' (presubmit successful).'
2044 cl.RpcServer().add_comment(cl.GetIssue(), comment) 2076 cl.RpcServer().add_comment(cl.GetIssue(), comment)
2045 cl.SetIssue(None) 2077 cl.SetIssue(None)
2046 2078
2047 if retcode == 0: 2079 if retcode == 0:
2048 hook = POSTUPSTREAM_HOOK_PATTERN % cmd 2080 hook = POSTUPSTREAM_HOOK_PATTERN % cmd
2049 if os.path.isfile(hook): 2081 if os.path.isfile(hook):
2050 RunCommand([hook, base_branch], error_ok=True) 2082 RunCommand([hook, base_branch], error_ok=True)
2051 2083
2052 return 0 2084 return 0
2053 2085
2054 2086
2087 def PushToGitPending(remote, pending_ref):
2088 """Fetches pending_ref, cherry-picks current HEAD on top of it, pushes.
2089
2090 Returns:
2091 (retcode of last operation, output log of last operation).
2092 """
2093 cherry = RunGit(['rev-parse', 'HEAD']).strip()
2094 code = 0
2095 out = ''
2096 attempt = 0
2097 while attempt < 5:
2098 attempt += 1
2099
2100 # Fetch. Retry fetch errors.
2101 code, out = RunGitWithCode(
2102 ['fetch', remote, '+%s:refs/git-cl/pending' % pending_ref])
2103 if code:
2104 continue
2105
2106 # Try to cherry pick. Abort on merge conflicts.
2107 RunGitWithCode(['checkout', 'refs/git-cl/pending'])
iannucci 2014/08/21 20:37:03 let's make this refs/git-cl/pending/heads/master
Vadim Sh. 2014/08/21 21:14:35 Done.
2108 code, out = RunGitWithCode(['cherry-pick', cherry])
Vadim Sh. 2014/08/21 19:31:22 cherry-pick supports different merge strategies. A
2109 if code:
2110 RunGitWithCode(['cherry-pick', '--abort'])
Vadim Sh. 2014/08/21 19:31:22 Not sure it's needed...
iannucci 2014/08/21 20:32:20 yep
2111 return code, out
2112
2113 # Applied cleanly, try to push now. Retry on error (flake or non-ff push).
2114 code, out = RunGitWithCode(['push', remote, 'HEAD:%s' % pending_ref])
Vadim Sh. 2014/08/21 19:31:22 This can fail in 3 cases: 1. Network\git flake. 2.
iannucci 2014/08/21 20:32:20 I think we should just put 'retry' before 'push'
Vadim Sh. 2014/08/21 21:14:35 Done.
2115 if not code:
iannucci 2014/08/21 20:32:20 let's do `code == 0`
Vadim Sh. 2014/08/21 21:14:35 Done.
2116 # Success.
2117 return code, out
2118
2119 return code, out
2120
2121
2055 @subcommand.usage('[upstream branch to apply against]') 2122 @subcommand.usage('[upstream branch to apply against]')
2056 def CMDdcommit(parser, args): 2123 def CMDdcommit(parser, args):
2057 """Commits the current changelist via git-svn.""" 2124 """Commits the current changelist via git-svn."""
2058 if not settings.GetIsGitSvn(): 2125 if not settings.GetIsGitSvn():
2059 message = """This doesn't appear to be an SVN repository. 2126 message = """This doesn't appear to be an SVN repository.
2060 If your project has a git mirror with an upstream SVN master, you probably need 2127 If your project has a git mirror with an upstream SVN master, you probably need
2061 to run 'git svn init', see your project's git mirror documentation. 2128 to run 'git svn init', see your project's git mirror documentation.
2062 If your project has a true writeable upstream repository, you probably want 2129 If your project has a true writeable upstream repository, you probably want
2063 to run 'git cl land' instead. 2130 to run 'git cl land' instead.
2064 Choose wisely, if you get this wrong, your commit might appear to succeed but 2131 Choose wisely, if you get this wrong, your commit might appear to succeed but
2065 will instead be silently ignored.""" 2132 will instead be silently ignored."""
2066 print(message) 2133 print(message)
2067 ask_for_data('[Press enter to dcommit or ctrl-C to quit]') 2134 ask_for_data('[Press enter to dcommit or ctrl-C to quit]')
2068 return SendUpstream(parser, args, 'dcommit') 2135 return SendUpstream(parser, args, 'dcommit')
2069 2136
2070 2137
2071 @subcommand.usage('[upstream branch to apply against]') 2138 @subcommand.usage('[upstream branch to apply against]')
2072 def CMDland(parser, args): 2139 def CMDland(parser, args):
2073 """Commits the current changelist via git.""" 2140 """Commits the current changelist via git."""
2074 if settings.GetIsGitSvn(): 2141 if settings.GetIsGitSvn():
2075 print('This appears to be an SVN repository.') 2142 print('This appears to be an SVN repository.')
2076 print('Are you sure you didn\'t mean \'git cl dcommit\'?') 2143 print('Are you sure you didn\'t mean \'git cl dcommit\'?')
2077 ask_for_data('[Press enter to push or ctrl-C to quit]') 2144 ask_for_data('[Press enter to push or ctrl-C to quit]')
2078 return SendUpstream(parser, args, 'push') 2145 return SendUpstream(parser, args, 'land')
2079 2146
2080 2147
2081 @subcommand.usage('<patch url or issue id>') 2148 @subcommand.usage('<patch url or issue id>')
2082 def CMDpatch(parser, args): 2149 def CMDpatch(parser, args):
2083 """Patches in a code review.""" 2150 """Patches in a code review."""
2084 parser.add_option('-b', dest='newbranch', 2151 parser.add_option('-b', dest='newbranch',
2085 help='create a new branch off trunk for the patch') 2152 help='create a new branch off trunk for the patch')
2086 parser.add_option('-f', '--force', action='store_true', 2153 parser.add_option('-f', '--force', action='store_true',
2087 help='with -b, clobber any existing branch') 2154 help='with -b, clobber any existing branch')
2088 parser.add_option('-d', '--directory', action='store', metavar='DIR', 2155 parser.add_option('-d', '--directory', action='store', metavar='DIR',
(...skipping 584 matching lines...) Expand 10 before | Expand all | Expand 10 after
2673 ('AppEngine is misbehaving and returned HTTP %d, again. Keep faith ' 2740 ('AppEngine is misbehaving and returned HTTP %d, again. Keep faith '
2674 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) 2741 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e)))
2675 2742
2676 2743
2677 if __name__ == '__main__': 2744 if __name__ == '__main__':
2678 # These affect sys.stdout so do it outside of main() to simplify mocks in 2745 # These affect sys.stdout so do it outside of main() to simplify mocks in
2679 # unit testing. 2746 # unit testing.
2680 fix_encoding.fix_encoding() 2747 fix_encoding.fix_encoding()
2681 colorama.init() 2748 colorama.init()
2682 sys.exit(main(sys.argv[1:])) 2749 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