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

Side by Side Diff: git_cl.py

Issue 1889483002: git cl set-commit: for Gerrit + dry-run support. (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@master
Patch Set: review Created 4 years, 8 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') | tests/git_cl_test.py » ('J')
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 distutils.version import LooseVersion 10 from distutils.version import LooseVersion
(...skipping 817 matching lines...) Expand 10 before | Expand all | Expand 10 after
828 """Returns current branch or None. 828 """Returns current branch or None.
829 829
830 For refs/heads/* branches, returns just last part. For others, full ref. 830 For refs/heads/* branches, returns just last part. For others, full ref.
831 """ 831 """
832 branchref = GetCurrentBranchRef() 832 branchref = GetCurrentBranchRef()
833 if branchref: 833 if branchref:
834 return ShortBranchName(branchref) 834 return ShortBranchName(branchref)
835 return None 835 return None
836 836
837 837
838 class _CQState(object):
839 """Enum for states of CL with respect to Commit Queue."""
840 NONE = 'none'
841 DRY_RUN = 'dry_run'
842 COMMIT = 'commit'
843
844 ALL_STATES = [NONE, DRY_RUN, COMMIT]
845
846
838 class _ParsedIssueNumberArgument(object): 847 class _ParsedIssueNumberArgument(object):
839 def __init__(self, issue=None, patchset=None, hostname=None): 848 def __init__(self, issue=None, patchset=None, hostname=None):
840 self.issue = issue 849 self.issue = issue
841 self.patchset = patchset 850 self.patchset = patchset
842 self.hostname = hostname 851 self.hostname = hostname
843 852
844 @property 853 @property
845 def valid(self): 854 def valid(self):
846 return self.issue is not None 855 return self.issue is not None
847 856
(...skipping 542 matching lines...) Expand 10 before | Expand all | Expand 10 after
1390 print 1399 print
1391 print '--dependencies has been specified.' 1400 print '--dependencies has been specified.'
1392 print 'All dependent local branches will be re-uploaded.' 1401 print 'All dependent local branches will be re-uploaded.'
1393 print 1402 print
1394 # Remove the dependencies flag from args so that we do not end up in a 1403 # Remove the dependencies flag from args so that we do not end up in a
1395 # loop. 1404 # loop.
1396 orig_args.remove('--dependencies') 1405 orig_args.remove('--dependencies')
1397 ret = upload_branch_deps(self, orig_args) 1406 ret = upload_branch_deps(self, orig_args)
1398 return ret 1407 return ret
1399 1408
1409 def SetCQState(self, new_state):
1410 """Update the CQ state for latest patchset.
1411
1412 Issue must have been already uploaded and known.
1413 """
1414 assert new_state in _CQState.ALL_STATES
1415 assert self.GetIssue()
1416 return self._codereview_impl.SetCQState(new_state)
1417
1400 # Forward methods to codereview specific implementation. 1418 # Forward methods to codereview specific implementation.
1401 1419
1402 def CloseIssue(self): 1420 def CloseIssue(self):
1403 return self._codereview_impl.CloseIssue() 1421 return self._codereview_impl.CloseIssue()
1404 1422
1405 def GetStatus(self): 1423 def GetStatus(self):
1406 return self._codereview_impl.GetStatus() 1424 return self._codereview_impl.GetStatus()
1407 1425
1408 def GetCodereviewServer(self): 1426 def GetCodereviewServer(self):
1409 return self._codereview_impl.GetCodereviewServer() 1427 return self._codereview_impl.GetCodereviewServer()
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
1515 1533
1516 Arguments: 1534 Arguments:
1517 force: whether to skip confirmation questions. 1535 force: whether to skip confirmation questions.
1518 """ 1536 """
1519 raise NotImplementedError() 1537 raise NotImplementedError()
1520 1538
1521 def CMDUploadChange(self, options, args, change): 1539 def CMDUploadChange(self, options, args, change):
1522 """Uploads a change to codereview.""" 1540 """Uploads a change to codereview."""
1523 raise NotImplementedError() 1541 raise NotImplementedError()
1524 1542
1543 def SetCQState(self, new_state):
1544 """Update the CQ state for latest patchset.
1545
1546 Issue must have been already uploaded and known.
1547 """
1548 raise NotImplementedError()
1549
1525 1550
1526 class _RietveldChangelistImpl(_ChangelistCodereviewBase): 1551 class _RietveldChangelistImpl(_ChangelistCodereviewBase):
1527 def __init__(self, changelist, auth_config=None, rietveld_server=None): 1552 def __init__(self, changelist, auth_config=None, rietveld_server=None):
1528 super(_RietveldChangelistImpl, self).__init__(changelist) 1553 super(_RietveldChangelistImpl, self).__init__(changelist)
1529 assert settings, 'must be initialized in _ChangelistCodereviewBase' 1554 assert settings, 'must be initialized in _ChangelistCodereviewBase'
1530 settings.GetDefaultServerUrl() 1555 settings.GetDefaultServerUrl()
1531 1556
1532 self._rietveld_server = rietveld_server 1557 self._rietveld_server = rietveld_server
1533 self._auth_config = auth_config 1558 self._auth_config = auth_config
1534 self._props = None 1559 self._props = None
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
1692 def GetCodereviewServerSetting(self): 1717 def GetCodereviewServerSetting(self):
1693 """Returns the git setting that stores this change's rietveld server.""" 1718 """Returns the git setting that stores this change's rietveld server."""
1694 branch = self.GetBranch() 1719 branch = self.GetBranch()
1695 if branch: 1720 if branch:
1696 return 'branch.%s.rietveldserver' % branch 1721 return 'branch.%s.rietveldserver' % branch
1697 return None 1722 return None
1698 1723
1699 def GetRieveldObjForPresubmit(self): 1724 def GetRieveldObjForPresubmit(self):
1700 return self.RpcServer() 1725 return self.RpcServer()
1701 1726
1727 def SetCQState(self, new_state):
1728 props = self.GetIssueProperties()
1729 if props.get('private'):
1730 DieWithError('Cannot set-commit on private issue')
1731
1732 if new_state == _CQState.COMMIT:
1733 self.SetFlag('commit', '1')
1734 elif new_state == _CQState.NONE:
1735 self.SetFlag('commit', '0')
1736 else:
1737 raise NotImplementedError()
Sergiy Byelozyorov 2016/04/13 17:15:02 What about DRY_RUN?
tandrii(chromium) 2016/04/13 17:17:16 wasn't supported before, so whatever.
1738
1739
1702 def CMDPatchWithParsedIssue(self, parsed_issue_arg, reject, nocommit, 1740 def CMDPatchWithParsedIssue(self, parsed_issue_arg, reject, nocommit,
1703 directory): 1741 directory):
1704 # TODO(maruel): Use apply_issue.py 1742 # TODO(maruel): Use apply_issue.py
1705 1743
1706 # PatchIssue should never be called with a dirty tree. It is up to the 1744 # PatchIssue should never be called with a dirty tree. It is up to the
1707 # caller to check this, but just in case we assert here since the 1745 # caller to check this, but just in case we assert here since the
1708 # consequences of the caller not checking this could be dire. 1746 # consequences of the caller not checking this could be dire.
1709 assert(not git_common.is_dirty_git_tree('apply')) 1747 assert(not git_common.is_dirty_git_tree('apply'))
1710 assert(parsed_issue_arg.valid) 1748 assert(parsed_issue_arg.valid)
1711 self._changelist.issue = parsed_issue_arg.issue 1749 self._changelist.issue = parsed_issue_arg.issue
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after
1929 backup_file = open(backup_path, 'w') 1967 backup_file = open(backup_path, 'w')
1930 backup_file.write(change_desc.description) 1968 backup_file.write(change_desc.description)
1931 backup_file.close() 1969 backup_file.close()
1932 raise 1970 raise
1933 1971
1934 if not self.GetIssue(): 1972 if not self.GetIssue():
1935 self.SetIssue(issue) 1973 self.SetIssue(issue)
1936 self.SetPatchset(patchset) 1974 self.SetPatchset(patchset)
1937 1975
1938 if options.use_commit_queue: 1976 if options.use_commit_queue:
1939 self.SetFlag('commit', '1') 1977 self.SetCQState(_CQState.COMMIT)
1940 return 0 1978 return 0
1941 1979
1942 1980
1943 class _GerritChangelistImpl(_ChangelistCodereviewBase): 1981 class _GerritChangelistImpl(_ChangelistCodereviewBase):
1944 def __init__(self, changelist, auth_config=None): 1982 def __init__(self, changelist, auth_config=None):
1945 # auth_config is Rietveld thing, kept here to preserve interface only. 1983 # auth_config is Rietveld thing, kept here to preserve interface only.
1946 super(_GerritChangelistImpl, self).__init__(changelist) 1984 super(_GerritChangelistImpl, self).__init__(changelist)
1947 self._change_id = None 1985 self._change_id = None
1948 # Lazily cached values. 1986 # Lazily cached values.
1949 self._gerrit_server = None # e.g. https://chromium-review.googlesource.com 1987 self._gerrit_server = None # e.g. https://chromium-review.googlesource.com
(...skipping 493 matching lines...) Expand 10 before | Expand all | Expand 10 after
2443 log_desc = options.message or CreateDescriptionFromLog(args) 2481 log_desc = options.message or CreateDescriptionFromLog(args)
2444 git_command = ['commit', '--amend', '-m', log_desc] 2482 git_command = ['commit', '--amend', '-m', log_desc]
2445 RunGit(git_command) 2483 RunGit(git_command)
2446 new_log_desc = CreateDescriptionFromLog(args) 2484 new_log_desc = CreateDescriptionFromLog(args)
2447 if git_footers.get_footer_change_id(new_log_desc): 2485 if git_footers.get_footer_change_id(new_log_desc):
2448 print 'git-cl: Added Change-Id to commit message.' 2486 print 'git-cl: Added Change-Id to commit message.'
2449 return new_log_desc 2487 return new_log_desc
2450 else: 2488 else:
2451 print >> sys.stderr, 'ERROR: Gerrit commit-msg hook not available.' 2489 print >> sys.stderr, 'ERROR: Gerrit commit-msg hook not available.'
2452 2490
2491 def SetCQState(self, new_state):
2492 """Sets the Commit-Queue label assuming canonical CQ config for Gerrit."""
2493 # TODO(tandrii): maybe allow configurability in codereview.settings or by
2494 # self-discovery of label config for this CL using REST API.
2495 vote_map = {
2496 _CQState.NONE: 0,
2497 _CQState.DRY_RUN: 1,
2498 _CQState.COMMIT : 2,
2499 }
2500 gerrit_util.SetReview(self._GetGerritHost(), self.GetIssue(),
2501 labels={'Commit-Queue': vote_map[new_state]})
2502
2453 2503
2454 _CODEREVIEW_IMPLEMENTATIONS = { 2504 _CODEREVIEW_IMPLEMENTATIONS = {
2455 'rietveld': _RietveldChangelistImpl, 2505 'rietveld': _RietveldChangelistImpl,
2456 'gerrit': _GerritChangelistImpl, 2506 'gerrit': _GerritChangelistImpl,
2457 } 2507 }
2458 2508
2459 2509
2460 class ChangeDescription(object): 2510 class ChangeDescription(object):
2461 """Contains a parsed form of the change description.""" 2511 """Contains a parsed form of the change description."""
2462 R_LINE = r'^[ \t]*(TBR|R)[ \t]*=[ \t]*(.*?)[ \t]*$' 2512 R_LINE = r'^[ \t]*(TBR|R)[ \t]*=[ \t]*(.*?)[ \t]*$'
(...skipping 1596 matching lines...) Expand 10 before | Expand all | Expand 10 after
4059 4109
4060 print "The tree is %s" % status 4110 print "The tree is %s" % status
4061 print 4111 print
4062 print GetTreeStatusReason() 4112 print GetTreeStatusReason()
4063 if status != 'open': 4113 if status != 'open':
4064 return 1 4114 return 1
4065 return 0 4115 return 0
4066 4116
4067 4117
4068 def CMDtry(parser, args): 4118 def CMDtry(parser, args):
4069 """Triggers a try job through BuildBucket.""" 4119 """Triggers try jobs through BuildBucket."""
4070 group = optparse.OptionGroup(parser, "Try job options") 4120 group = optparse.OptionGroup(parser, "Try job options")
4071 group.add_option( 4121 group.add_option(
4072 "-b", "--bot", action="append", 4122 "-b", "--bot", action="append",
4073 help=("IMPORTANT: specify ONE builder per --bot flag. Use it multiple " 4123 help=("IMPORTANT: specify ONE builder per --bot flag. Use it multiple "
4074 "times to specify multiple builders. ex: " 4124 "times to specify multiple builders. ex: "
4075 "'-b win_rel -b win_layout'. See " 4125 "'-b win_rel -b win_layout'. See "
4076 "the try server waterfall for the builders name and the tests " 4126 "the try server waterfall for the builders name and the tests "
4077 "available.")) 4127 "available."))
4078 group.add_option( 4128 group.add_option(
4079 "-m", "--master", default='', 4129 "-m", "--master", default='',
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
4118 if bad_params: 4168 if bad_params:
4119 parser.error('Got properties with missing "=": %s' % bad_params) 4169 parser.error('Got properties with missing "=": %s' % bad_params)
4120 4170
4121 if args: 4171 if args:
4122 parser.error('Unknown arguments: %s' % args) 4172 parser.error('Unknown arguments: %s' % args)
4123 4173
4124 cl = Changelist(auth_config=auth_config) 4174 cl = Changelist(auth_config=auth_config)
4125 if not cl.GetIssue(): 4175 if not cl.GetIssue():
4126 parser.error('Need to upload first') 4176 parser.error('Need to upload first')
4127 4177
4178 if cl.IsGerrit():
4179 parser.error(
4180 'Not yet supported for Gerrit (http://crbug.com/599931).\n'
4181 'If your project has Commit Queue, dry run is a workaround:\n'
4182 ' git cl set-commit --dry-run')
4183 # Code below assumes Rietveld issue.
4184 # TODO(tandrii): actually implement for Gerrit http://crbug.com/599931.
4185
4128 props = cl.GetIssueProperties() 4186 props = cl.GetIssueProperties()
4129 if props.get('closed'): 4187 if props.get('closed'):
4130 parser.error('Cannot send tryjobs for a closed CL') 4188 parser.error('Cannot send tryjobs for a closed CL')
4131 4189
4132 if props.get('private'): 4190 if props.get('private'):
4133 parser.error('Cannot use trybots with private issue') 4191 parser.error('Cannot use trybots with private issue')
4134 4192
4135 if not options.name: 4193 if not options.name:
4136 options.name = cl.GetBranch() 4194 options.name = cl.GetBranch()
4137 4195
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after
4339 if not issue_url: 4397 if not issue_url:
4340 print >> sys.stderr, 'ERROR No issue to open' 4398 print >> sys.stderr, 'ERROR No issue to open'
4341 return 1 4399 return 1
4342 4400
4343 webbrowser.open(issue_url) 4401 webbrowser.open(issue_url)
4344 return 0 4402 return 0
4345 4403
4346 4404
4347 def CMDset_commit(parser, args): 4405 def CMDset_commit(parser, args):
4348 """Sets the commit bit to trigger the Commit Queue.""" 4406 """Sets the commit bit to trigger the Commit Queue."""
4407 parser.add_option('-d', '--dry-run', action='store_true',
4408 help='trigger in dry run mode')
4409 parser.add_option('-c', '--clear', action='store_true',
4410 help='stop CQ run, if any')
4349 auth.add_auth_options(parser) 4411 auth.add_auth_options(parser)
4350 options, args = parser.parse_args(args) 4412 options, args = parser.parse_args(args)
4351 auth_config = auth.extract_auth_config_from_options(options) 4413 auth_config = auth.extract_auth_config_from_options(options)
4352 if args: 4414 if args:
4353 parser.error('Unrecognized args: %s' % ' '.join(args)) 4415 parser.error('Unrecognized args: %s' % ' '.join(args))
4416 if options.dry_run and options.clear:
4417 parser.error('Make up your mind: both --dry-run and --clear not allowed')
4418
4354 cl = Changelist(auth_config=auth_config) 4419 cl = Changelist(auth_config=auth_config)
4355 props = cl.GetIssueProperties() 4420 if options.clear:
4356 if props.get('private'): 4421 state = _CQState.CLEAR
4357 parser.error('Cannot set commit on private issue') 4422 elif options.dry_run:
4358 cl.SetFlag('commit', '1') 4423 state = _CQState.DRY_RUN
4424 else:
4425 state = _CQState.COMMIT
4426 if not cl.GetIssue():
4427 parser.error('Must upload the issue first')
4428 cl.SetCQState(state)
4359 return 0 4429 return 0
4360 4430
4361 4431
4362 def CMDset_close(parser, args): 4432 def CMDset_close(parser, args):
4363 """Closes the issue.""" 4433 """Closes the issue."""
4364 auth.add_auth_options(parser) 4434 auth.add_auth_options(parser)
4365 options, args = parser.parse_args(args) 4435 options, args = parser.parse_args(args)
4366 auth_config = auth.extract_auth_config_from_options(options) 4436 auth_config = auth.extract_auth_config_from_options(options)
4367 if args: 4437 if args:
4368 parser.error('Unrecognized args: %s' % ' '.join(args)) 4438 parser.error('Unrecognized args: %s' % ' '.join(args))
(...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after
4708 if __name__ == '__main__': 4778 if __name__ == '__main__':
4709 # These affect sys.stdout so do it outside of main() to simplify mocks in 4779 # These affect sys.stdout so do it outside of main() to simplify mocks in
4710 # unit testing. 4780 # unit testing.
4711 fix_encoding.fix_encoding() 4781 fix_encoding.fix_encoding()
4712 setup_color.init() 4782 setup_color.init()
4713 try: 4783 try:
4714 sys.exit(main(sys.argv[1:])) 4784 sys.exit(main(sys.argv[1:]))
4715 except KeyboardInterrupt: 4785 except KeyboardInterrupt:
4716 sys.stderr.write('interrupted\n') 4786 sys.stderr.write('interrupted\n')
4717 sys.exit(1) 4787 sys.exit(1)
OLDNEW
« no previous file with comments | « no previous file | tests/git_cl_test.py » ('j') | tests/git_cl_test.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698