git-cl: Set Code-Review label as a git push argument.

Bug: 877717
Change-Id: I6541a971068aae662b086eba84448bd0769f1a09
Reviewed-on: https://chromium-review.googlesource.com/c/1362405
Reviewed-by: Andrii Shyshkalov <tandrii@chromium.org>
Reviewed-by: Edward Lesmes <ehmaldonado@chromium.org>
Commit-Queue: Edward Lesmes <ehmaldonado@chromium.org>
This commit is contained in:
Edward Lemur
2018-12-05 02:30:30 +00:00
committed by Commit Bot
parent 2413f5b0f7
commit 687ca907fd
4 changed files with 42 additions and 112 deletions

View File

@@ -613,6 +613,18 @@ def GetGerritFetchUrl(host):
return '%s://%s/' % (GERRIT_PROTOCOL, host) return '%s://%s/' % (GERRIT_PROTOCOL, host)
def GetCodeReviewTbrScore(host, project):
"""Given a gerrit host name and project, return the Code-Review score for TBR.
"""
conn = CreateHttpConn(host, '/projects/%s' % urllib.quote(project, safe=''))
project = ReadHttpJsonResponse(conn)
if ('labels' not in project
or 'Code-Review' not in project['labels']
or 'values' not in project['labels']['Code-Review']):
return 1
return max([int(x) for x in project['labels']['Code-Review']['values']])
def GetChangePageUrl(host, change_number): def GetChangePageUrl(host, change_number):
"""Given a gerrit host name and change number, return change page url.""" """Given a gerrit host name and change number, return change page url."""
return '%s://%s/#/c/%d/' % (GERRIT_PROTOCOL, host, change_number) return '%s://%s/#/c/%d/' % (GERRIT_PROTOCOL, host, change_number)
@@ -976,7 +988,7 @@ def tempdir():
def ChangeIdentifier(project, change_number): def ChangeIdentifier(project, change_number):
"""Returns change identifier "project~number" suitable for |chagne| arg of """Returns change identifier "project~number" suitable for |change| arg of
this module API. this module API.
Such format is allows for more efficient Gerrit routing of HTTP requests, Such format is allows for more efficient Gerrit routing of HTTP requests,

View File

@@ -1613,41 +1613,6 @@ class Changelist(object):
ret = upload_branch_deps(self, orig_args) ret = upload_branch_deps(self, orig_args)
return ret return ret
def SetLabels(self, enable_auto_submit, use_commit_queue, cq_dry_run):
"""Sets labels on the change based on the provided flags.
Sets labels if issue is already uploaded and known, else returns without
doing anything.
Args:
enable_auto_submit: Sets Auto-Submit+1 on the change.
use_commit_queue: Sets Commit-Queue+2 on the change.
cq_dry_run: Sets Commit-Queue+1 on the change. Overrides Commit-Queue+2 if
both use_commit_queue and cq_dry_run are true.
"""
if not self.GetIssue():
return
try:
self._codereview_impl.SetLabels(enable_auto_submit, use_commit_queue,
cq_dry_run)
return 0
except KeyboardInterrupt:
raise
except:
labels = []
if enable_auto_submit:
labels.append('Auto-Submit')
if use_commit_queue or cq_dry_run:
labels.append('Commit-Queue')
print('WARNING: Failed to set label(s) on your change: %s\n'
'Either:\n'
' * Your project does not have the above label(s),\n'
' * You don\'t have permission to set the above label(s),\n'
' * There\'s a bug in this code (see stack trace below).\n' %
(', '.join(labels)))
# Still raise exception so that stack trace is printed.
raise
def SetCQState(self, new_state): def SetCQState(self, new_state):
"""Updates the CQ state for the latest patchset. """Updates the CQ state for the latest patchset.
@@ -1841,13 +1806,6 @@ class _ChangelistCodereviewBase(object):
"""Uploads a change to codereview.""" """Uploads a change to codereview."""
raise NotImplementedError() raise NotImplementedError()
def SetLabels(self, enable_auto_submit, use_commit_queue, cq_dry_run):
"""Sets labels on the change based on the provided flags.
Issue must have been already uploaded and known.
"""
raise NotImplementedError()
def SetCQState(self, new_state): def SetCQState(self, new_state):
"""Updates the CQ state for the latest patchset. """Updates the CQ state for the latest patchset.
@@ -2670,16 +2628,18 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
# https://gerrit-review.googlesource.com/Documentation/user-upload.html#topic # https://gerrit-review.googlesource.com/Documentation/user-upload.html#topic
refspec_opts.append('topic=%s' % options.topic) refspec_opts.append('topic=%s' % options.topic)
if not change_desc.get_reviewers(tbr_only=True): if options.enable_auto_submit:
# Change is not TBR, so we can inline setting other labels, too. refspec_opts.append('l=Auto-Submit+1')
# TODO(crbug.com/877717): make this working for TBR, too, by figuring out if options.use_commit_queue:
# max score for CR label somehow. refspec_opts.append('l=Commit-Queue+2')
if options.enable_auto_submit: elif options.cq_dry_run:
refspec_opts.append('l=Auto-Submit+1') refspec_opts.append('l=Commit-Queue+1')
if options.use_commit_queue:
refspec_opts.append('l=Commit-Queue+2') if change_desc.get_reviewers(tbr_only=True):
elif options.cq_dry_run: score = gerrit_util.GetCodeReviewTbrScore(
refspec_opts.append('l=Commit-Queue+1') self._GetGerritHost(),
self._GetGerritProject())
refspec_opts.append('l=Code-Review+%s' % score)
# Gerrit sorts hashtags, so order is not important. # Gerrit sorts hashtags, so order is not important.
hashtags = {change_desc.sanitize_hash_tag(t) for t in options.hashtags} hashtags = {change_desc.sanitize_hash_tag(t) for t in options.hashtags}
@@ -2740,20 +2700,6 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
reviewers, cc, reviewers, cc,
notify=bool(options.send_mail)) notify=bool(options.send_mail))
if change_desc.get_reviewers(tbr_only=True):
labels = self._GetChangeDetail(['LABELS']).get('labels', {})
score = 1
if 'Code-Review' in labels and 'values' in labels['Code-Review']:
score = max([int(x) for x in labels['Code-Review']['values'].keys()])
print('Adding self-LGTM (Code-Review +%d) because of TBRs.' % score)
gerrit_util.SetReview(
self._GetGerritHost(),
self._GerritChangeIdentifier(),
msg='Self-approving for TBR',
labels={'Code-Review': score})
# Labels aren't set through refspec only if tbr is set (see check above).
self.SetLabels(options.enable_auto_submit, options.use_commit_queue,
options.cq_dry_run)
return 0 return 0
def _ComputeParent(self, remote, upstream_branch, custom_cl_base, force, def _ComputeParent(self, remote, upstream_branch, custom_cl_base, force,
@@ -2830,23 +2776,6 @@ class _GerritChangelistImpl(_ChangelistCodereviewBase):
else: else:
DieWithError('ERROR: Gerrit commit-msg hook not installed.') DieWithError('ERROR: Gerrit commit-msg hook not installed.')
def SetLabels(self, enable_auto_submit, use_commit_queue, cq_dry_run):
"""Sets labels on the change based on the provided flags."""
labels = {}
notify = None;
if enable_auto_submit:
labels['Auto-Submit'] = 1
if use_commit_queue:
labels['Commit-Queue'] = 2
elif cq_dry_run:
labels['Commit-Queue'] = 1
notify = False
if labels:
gerrit_util.SetReview(
self._GetGerritHost(),
self._GerritChangeIdentifier(),
labels=labels, notify=notify)
def SetCQState(self, new_state): def SetCQState(self, new_state):
"""Sets the Commit-Queue label assuming canonical CQ config for Gerrit.""" """Sets the Commit-Queue label assuming canonical CQ config for Gerrit."""
vote_map = { vote_map = {

View File

@@ -147,6 +147,8 @@ KNOWN_SUBCOMMAND_ARGS = {
'cc', 'cc',
'hashtag', 'hashtag',
'l=Auto-Submit+1', 'l=Auto-Submit+1',
'l=Code-Review+1',
'l=Code-Review+2',
'l=Commit-Queue+1', 'l=Commit-Queue+1',
'l=Commit-Queue+2', 'l=Commit-Queue+2',
'label', 'label',

View File

@@ -1059,10 +1059,17 @@ class TestGitCl(TestCase):
if c in cc: if c in cc:
cc.remove(c) cc.remove(c)
if not tbr: for k, v in sorted((labels or {}).items()):
for k, v in sorted((labels or {}).items()): ref_suffix += ',l=%s+%d' % (k, v)
ref_suffix += ',l=%s+%d' % (k, v) metrics_arguments.append('l=%s+%d' % (k, v))
metrics_arguments.append('l=%s+%d' % (k, v))
if tbr:
calls += [
(('GetCodeReviewTbrScore',
'%s-review.googlesource.com' % short_hostname,
'my/repo'),
2,),
]
calls += [ calls += [
(('time.time',), 1000,), (('time.time',), 1000,),
@@ -1115,29 +1122,6 @@ class TestGitCl(TestCase):
notify), notify),
''), ''),
] ]
if tbr:
calls += [
(('GetChangeDetail', 'chromium-review.googlesource.com',
'my%2Frepo~123456', ['LABELS']), {
'labels': {
'Code-Review': {
'default_value': 0,
'all': [],
'values': {
'+2': 'lgtm, approved',
'+1': 'lgtm, but someone else must approve',
' 0': 'No score',
'-1': 'Don\'t submit as-is',
}
}
}
}),
(('SetReview',
'chromium-review.googlesource.com',
'my%2Frepo~123456',
'Self-approving for TBR',
{'Code-Review': 2}, None), ''),
]
calls += cls._git_post_upload_calls() calls += cls._git_post_upload_calls()
return calls return calls
@@ -1261,6 +1245,8 @@ class TestGitCl(TestCase):
notify=True) notify=True)
def test_gerrit_reviewer_multiple(self): def test_gerrit_reviewer_multiple(self):
self.mock(git_cl.gerrit_util, 'GetCodeReviewTbrScore',
lambda *a: self._mocked_call('GetCodeReviewTbrScore', *a))
self._run_gerrit_upload_test( self._run_gerrit_upload_test(
[], [],
'desc\nTBR=reviewer@example.com\nBUG=\nR=another@example.com\n' 'desc\nTBR=reviewer@example.com\nBUG=\nR=another@example.com\n'
@@ -1269,7 +1255,8 @@ class TestGitCl(TestCase):
['reviewer@example.com', 'another@example.com'], ['reviewer@example.com', 'another@example.com'],
expected_upstream_ref='origin/master', expected_upstream_ref='origin/master',
cc=['more@example.com', 'people@example.com'], cc=['more@example.com', 'people@example.com'],
tbr='reviewer@example.com') tbr='reviewer@example.com',
labels={'Code-Review': 2})
def test_gerrit_upload_squash_first_is_default(self): def test_gerrit_upload_squash_first_is_default(self):
self._run_gerrit_upload_test( self._run_gerrit_upload_test(