| Index: git_cl.py
|
| diff --git a/git_cl.py b/git_cl.py
|
| index f1a450973db18f773e76f21c55c722b5edcb0a63..1ffbb308cba36b84bcc5c418a3e2b40ed295913f 100755
|
| --- a/git_cl.py
|
| +++ b/git_cl.py
|
| @@ -881,17 +881,17 @@ class Changelist(object):
|
| self._remote = None
|
|
|
| self._codereview_impl = None
|
| + self._codereview = None
|
| self._load_codereview_impl(codereview, **kwargs)
|
| + assert self._codereview_impl
|
| + assert self._codereview in _CODEREVIEW_IMPLEMENTATIONS
|
|
|
| def _load_codereview_impl(self, codereview=None, **kwargs):
|
| if codereview:
|
| - codereview = codereview.lower()
|
| - if codereview == 'gerrit':
|
| - self._codereview_impl = _GerritChangelistImpl(self, **kwargs)
|
| - elif codereview == 'rietveld':
|
| - self._codereview_impl = _RietveldChangelistImpl(self, **kwargs)
|
| - else:
|
| - assert codereview in ('rietveld', 'gerrit')
|
| + assert codereview in _CODEREVIEW_IMPLEMENTATIONS
|
| + cls = _CODEREVIEW_IMPLEMENTATIONS[codereview]
|
| + self._codereview = codereview
|
| + self._codereview_impl = cls(self, **kwargs)
|
| return
|
|
|
| # Automatic selection based on issue number set for a current branch.
|
| @@ -899,10 +899,11 @@ class Changelist(object):
|
| assert not self.issue
|
| # Whether we find issue or not, we are doing the lookup.
|
| self.lookedup_issue = True
|
| - for cls in [_RietveldChangelistImpl, _GerritChangelistImpl]:
|
| + for codereview, cls in _CODEREVIEW_IMPLEMENTATIONS.iteritems():
|
| setting = cls.IssueSetting(self.GetBranch())
|
| issue = RunGit(['config', setting], error_ok=True).strip()
|
| if issue:
|
| + self._codereview = codereview
|
| self._codereview_impl = cls(self, **kwargs)
|
| self.issue = int(issue)
|
| return
|
| @@ -912,6 +913,8 @@ class Changelist(object):
|
| codereview='gerrit' if settings.GetIsGerrit() else 'rietveld',
|
| **kwargs)
|
|
|
| + def IsGerrit(self):
|
| + return self._codereview == 'gerrit'
|
|
|
| def GetCCList(self):
|
| """Return the users cc'd on this CL.
|
| @@ -1650,11 +1653,55 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
|
| def CloseIssue(self):
|
| gerrit_util.AbandonChange(self._GetGerritHost(), self.GetIssue(), msg='')
|
|
|
| + def SubmitIssue(self, wait_for_merge=True):
|
| + gerrit_util.SubmitChange(self._GetGerritHost(), self.GetIssue(),
|
| + wait_for_merge=wait_for_merge)
|
|
|
| def _GetChangeDetail(self, options):
|
| return gerrit_util.GetChangeDetail(self._GetGerritHost(), self.GetIssue(),
|
| options)
|
|
|
| + def CMDLand(self, force, bypass_hooks, verbose):
|
| + if git_common.is_dirty_git_tree('land'):
|
| + return 1
|
| + differs = True
|
| + last_upload = RunGit(['config',
|
| + 'branch.%s.gerritsquashhash' % self.GetBranch()],
|
| + error_ok=True).strip()
|
| + # Note: git diff outputs nothing if there is no diff.
|
| + if not last_upload or RunGit(['diff', last_upload]).strip():
|
| + print('WARNING: some changes from local branch haven\'t been uploaded')
|
| + else:
|
| + detail = self._GetChangeDetail(['CURRENT_REVISION'])
|
| + if detail['current_revision'] == last_upload:
|
| + differs = False
|
| + else:
|
| + print('WARNING: local branch contents differ from latest uploaded '
|
| + 'patchset')
|
| + if differs:
|
| + if not force:
|
| + ask_for_data(
|
| + 'Do you want to submit latest Gerrit patchset and bypass hooks?')
|
| + print('WARNING: bypassing hooks and submitting latest uploaded patchset')
|
| + elif not bypass_hooks:
|
| + hook_results = self.RunHook(
|
| + committing=True,
|
| + may_prompt=not force,
|
| + verbose=verbose,
|
| + change=self.GetChange(self.GetCommonAncestorWithUpstream(), None))
|
| + if not hook_results.should_continue():
|
| + return 1
|
| +
|
| + self.SubmitIssue(wait_for_merge=True)
|
| + print('Issue %s has been submitted.' % self.GetIssueURL())
|
| + return 0
|
| +
|
| +
|
| +_CODEREVIEW_IMPLEMENTATIONS = {
|
| + 'rietveld': _RietveldChangelistImpl,
|
| + 'gerrit': _GerritChangelistImpl,
|
| +}
|
| +
|
|
|
| class ChangeDescription(object):
|
| """Contains a parsed form of the change description."""
|
| @@ -3110,10 +3157,14 @@ def IsSubmoduleMergeCommit(ref):
|
| def SendUpstream(parser, args, cmd):
|
| """Common code for CMDland and CmdDCommit
|
|
|
| - Squashes branch into a single commit.
|
| - Updates changelog with metadata (e.g. pointer to review).
|
| - Pushes/dcommits the code upstream.
|
| - Updates review and closes.
|
| + In case of Gerrit, uses Gerrit REST api to "submit" the issue, which pushes
|
| + upstream and closes the issue automatically and atomically.
|
| +
|
| + Otherwise (in case of Rietveld):
|
| + Squashes branch into a single commit.
|
| + Updates changelog with metadata (e.g. pointer to review).
|
| + Pushes/dcommits the code upstream.
|
| + Updates review and closes.
|
| """
|
| parser.add_option('--bypass-hooks', action='store_true', dest='bypass_hooks',
|
| help='bypass upload presubmit hook')
|
| @@ -3132,6 +3183,24 @@ def SendUpstream(parser, args, cmd):
|
|
|
| cl = Changelist(auth_config=auth_config)
|
|
|
| + # TODO(tandrii): refactor this into _RietveldChangelistImpl method.
|
| + if cl.IsGerrit():
|
| + if options.message:
|
| + # This could be implemented, but it requires sending a new patch to
|
| + # Gerrit, as Gerrit unlike Rietveld versions messages with patchsets.
|
| + # Besides, Gerrit has the ability to change the commit message on submit
|
| + # automatically, thus there is no need to support this option (so far?).
|
| + parser.error('-m MESSAGE option is not supported for Gerrit.')
|
| + if options.contributor:
|
| + parser.error(
|
| + '-c CONTRIBUTOR option is not supported for Gerrit.\n'
|
| + 'Before uploading a commit to Gerrit, ensure it\'s author field is '
|
| + 'the contributor\'s "name <email>". If you can\'t upload such a '
|
| + 'commit for review, contact your repository admin and request'
|
| + '"Forge-Author" permission.')
|
| + return cl._codereview_impl.CMDLand(options.force, options.bypass_hooks,
|
| + options.verbose)
|
| +
|
| current = cl.GetBranch()
|
| remote, upstream_branch = cl.FetchUpstreamTuple(cl.GetBranch())
|
| if not settings.GetIsGitSvn() and remote == '.':
|
|
|