Commit 968b1fe7 authored by Edward Lesmes's avatar Edward Lesmes Committed by LUCI CQ

[git-cl] Use owners client when processing --[tb]r-owners.

Change-Id: Id094bce2aa731359cd8af16f10ce79ae7e02bd85
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/2572809
Commit-Queue: Edward Lesmes <ehmaldonado@chromium.org>
Auto-Submit: Edward Lesmes <ehmaldonado@chromium.org>
Reviewed-by: 's avatarJosip Sokcevic <sokcevic@google.com>
parent b2c18f2f
...@@ -1372,9 +1372,24 @@ class Changelist(object): ...@@ -1372,9 +1372,24 @@ class Changelist(object):
# Set the reviewer list now so that presubmit checks can access it. # Set the reviewer list now so that presubmit checks can access it.
if options.reviewers or options.tbrs or options.add_owners_to: if options.reviewers or options.tbrs or options.add_owners_to:
add_owners = []
if options.add_owners_to:
# Fill gaps in OWNERS coverage to tbrs/reviewers if requested.
project = self.GetGerritProject()
branch = self.GetCommonAncestorWithUpstream()
client = owners_client.DepotToolsClient(
host=self.GetGerritHost(),
root=settings.GetRoot(),
branch=branch)
status = client.GetFilesApprovalStatus(
project, branch, files, [], options.tbrs + options.reviewers)
missing_files = [
f for f in files
if status[f] == owners_client.INSUFFICIENT_REVIEWERS
]
add_owners = client.SuggestOwners(project, branch, missing_files)
change_description.update_reviewers( change_description.update_reviewers(
options.reviewers, options.tbrs, options.add_owners_to, files, options.reviewers, options.tbrs, options.add_owners_to, add_owners)
self.GetAuthor())
return change_description return change_description
...@@ -2607,8 +2622,7 @@ class ChangeDescription(object): ...@@ -2607,8 +2622,7 @@ class ChangeDescription(object):
description = git_footers.add_footer_change_id(description, change_id) description = git_footers.add_footer_change_id(description, change_id)
self.set_description(description) self.set_description(description)
def update_reviewers( def update_reviewers(self, reviewers, tbrs, add_owners_to, add_owners):
self, reviewers, tbrs, add_owners_to, affected_files, author_email):
"""Rewrites the R=/TBR= line(s) as a single line each. """Rewrites the R=/TBR= line(s) as a single line each.
Args: Args:
...@@ -2616,14 +2630,14 @@ class ChangeDescription(object): ...@@ -2616,14 +2630,14 @@ class ChangeDescription(object):
tbrs (list(str)) - list of additional emails to use for TBRs. tbrs (list(str)) - list of additional emails to use for TBRs.
add_owners_to (None|'R'|'TBR') - Pass to do an OWNERS lookup for files in add_owners_to (None|'R'|'TBR') - Pass to do an OWNERS lookup for files in
the change that are missing OWNER coverage. If this is not None, you the change that are missing OWNER coverage. If this is not None, you
must also pass a value for `change`. must also pass a value for `add_owners`.
change (Change) - The Change that should be used for OWNERS lookups. add_owners (list(str)) - Owners to add to R or TBR if requested.
""" """
assert isinstance(reviewers, list), reviewers assert isinstance(reviewers, list), reviewers
assert isinstance(tbrs, list), tbrs assert isinstance(tbrs, list), tbrs
assert add_owners_to in (None, 'TBR', 'R'), add_owners_to assert add_owners_to in (None, 'TBR', 'R'), add_owners_to
assert not add_owners_to or affected_files, add_owners_to assert not add_owners_to or add_owners, add_owners_to
if not reviewers and not tbrs and not add_owners_to: if not reviewers and not tbrs and not add_owners_to:
return return
...@@ -2652,12 +2666,7 @@ class ChangeDescription(object): ...@@ -2652,12 +2666,7 @@ class ChangeDescription(object):
# Next, maybe fill in OWNERS coverage gaps to either tbrs/reviewers. # Next, maybe fill in OWNERS coverage gaps to either tbrs/reviewers.
if add_owners_to: if add_owners_to:
owners_db = owners.Database(settings.GetRoot(), LOOKUP[add_owners_to].update(add_owners)
fopen=open, os_path=os.path)
missing_files = owners_db.files_not_covered_by(affected_files,
(tbrs | reviewers))
LOOKUP[add_owners_to].update(
owners_db.reviewers_for(missing_files, author_email))
# If any folks ended up in both groups, remove them from tbrs. # If any folks ended up in both groups, remove them from tbrs.
tbrs -= reviewers tbrs -= reviewers
......
...@@ -562,9 +562,6 @@ class TestGitCl(unittest.TestCase): ...@@ -562,9 +562,6 @@ class TestGitCl(unittest.TestCase):
'git_cl.gclient_utils.CheckCallAndFilter', 'git_cl.gclient_utils.CheckCallAndFilter',
self._mocked_call).start() self._mocked_call).start()
mock.patch('git_common.is_dirty_git_tree', lambda x: False).start() mock.patch('git_common.is_dirty_git_tree', lambda x: False).start()
mock.patch(
'git_common.get_or_create_merge_base',
lambda *a: self._mocked_call('get_or_create_merge_base', *a)).start()
mock.patch('git_cl.FindCodereviewSettingsFile', return_value='').start() mock.patch('git_cl.FindCodereviewSettingsFile', return_value='').start()
mock.patch( mock.patch(
'git_cl.SaveDescriptionBackup', 'git_cl.SaveDescriptionBackup',
...@@ -707,17 +704,13 @@ class TestGitCl(unittest.TestCase): ...@@ -707,17 +704,13 @@ class TestGitCl(unittest.TestCase):
def _gerrit_base_calls(cls, issue=None, fetched_description=None, def _gerrit_base_calls(cls, issue=None, fetched_description=None,
fetched_status=None, other_cl_owner=None, fetched_status=None, other_cl_owner=None,
custom_cl_base=None, short_hostname='chromium', custom_cl_base=None, short_hostname='chromium',
change_id=None, new_default=False): change_id=None, default_branch='master'):
calls = [] calls = []
if custom_cl_base: if custom_cl_base:
ancestor_revision = custom_cl_base ancestor_revision = custom_cl_base
else: else:
# Determine ancestor_revision to be merge base. # Determine ancestor_revision to be merge base.
ancestor_revision = 'fake_ancestor_sha' ancestor_revision = 'origin/' + default_branch
calls += [
(('get_or_create_merge_base', 'master',
'refs/remotes/origin/master'), ancestor_revision),
]
if issue: if issue:
gerrit_util.GetChangeDetail.return_value = { gerrit_util.GetChangeDetail.return_value = {
...@@ -744,7 +737,7 @@ class TestGitCl(unittest.TestCase): ...@@ -744,7 +737,7 @@ class TestGitCl(unittest.TestCase):
] ]
calls += [ calls += [
((['git', 'show-branch', 'refs/remotes/origin/main'], ), ((['git', 'show-branch', 'refs/remotes/origin/main'], ),
'1' if new_default else callError(1)), '1' if default_branch == 'main' else callError(1)),
] ]
return calls return calls
...@@ -758,8 +751,7 @@ class TestGitCl(unittest.TestCase): ...@@ -758,8 +751,7 @@ class TestGitCl(unittest.TestCase):
labels=None, change_id=None, labels=None, change_id=None,
final_description=None, gitcookies_exists=True, final_description=None, gitcookies_exists=True,
force=False, edit_description=None, force=False, edit_description=None,
new_default=False): default_branch='master'):
default_branch = 'main' if new_default else 'master';
if post_amend_description is None: if post_amend_description is None:
post_amend_description = description post_amend_description = description
cc = cc or [] cc = cc or []
...@@ -787,11 +779,8 @@ class TestGitCl(unittest.TestCase): ...@@ -787,11 +779,8 @@ class TestGitCl(unittest.TestCase):
ref_to_push = 'abcdef0123456789' ref_to_push = 'abcdef0123456789'
if custom_cl_base is None: if custom_cl_base is None:
calls += [
(('get_or_create_merge_base', 'master',
'refs/remotes/origin/master'), 'origin/' + default_branch),
]
parent = 'origin/' + default_branch parent = 'origin/' + default_branch
git_common.get_or_create_merge_base.return_value = parent
else: else:
calls += [ calls += [
((['git', 'merge-base', '--is-ancestor', custom_cl_base, ((['git', 'merge-base', '--is-ancestor', custom_cl_base,
...@@ -1057,7 +1046,7 @@ class TestGitCl(unittest.TestCase): ...@@ -1057,7 +1046,7 @@ class TestGitCl(unittest.TestCase):
log_description=None, log_description=None,
edit_description=None, edit_description=None,
fetched_description=None, fetched_description=None,
new_default=False): default_branch='master'):
"""Generic gerrit upload test framework.""" """Generic gerrit upload test framework."""
if squash_mode is None: if squash_mode is None:
if '--no-squash' in upload_args: if '--no-squash' in upload_args:
...@@ -1109,6 +1098,9 @@ class TestGitCl(unittest.TestCase): ...@@ -1109,6 +1098,9 @@ class TestGitCl(unittest.TestCase):
return_value=post_amend_description or description).start() return_value=post_amend_description or description).start()
mock.patch( mock.patch(
'git_cl.GenerateGerritChangeId', return_value=change_id).start() 'git_cl.GenerateGerritChangeId', return_value=change_id).start()
mock.patch(
'git_common.get_or_create_merge_base',
return_value='origin/' + default_branch).start()
mock.patch( mock.patch(
'gclient_utils.AskForData', 'gclient_utils.AskForData',
lambda prompt: self._mocked_call('ask_for_data', prompt)).start() lambda prompt: self._mocked_call('ask_for_data', prompt)).start()
...@@ -1128,7 +1120,7 @@ class TestGitCl(unittest.TestCase): ...@@ -1128,7 +1120,7 @@ class TestGitCl(unittest.TestCase):
custom_cl_base=custom_cl_base, custom_cl_base=custom_cl_base,
short_hostname=short_hostname, short_hostname=short_hostname,
change_id=change_id, change_id=change_id,
new_default=new_default) default_branch=default_branch)
if fetched_status != 'ABANDONED': if fetched_status != 'ABANDONED':
mock.patch( mock.patch(
'gclient_utils.temporary_file', TemporaryFileMock()).start() 'gclient_utils.temporary_file', TemporaryFileMock()).start()
...@@ -1147,7 +1139,7 @@ class TestGitCl(unittest.TestCase): ...@@ -1147,7 +1139,7 @@ class TestGitCl(unittest.TestCase):
gitcookies_exists=gitcookies_exists, gitcookies_exists=gitcookies_exists,
force=force, force=force,
edit_description=edit_description, edit_description=edit_description,
new_default=new_default) default_branch=default_branch)
# Uncomment when debugging. # Uncomment when debugging.
# print('\n'.join(map(lambda x: '%2i: %s' % x, enumerate(self.calls)))) # print('\n'.join(map(lambda x: '%2i: %s' % x, enumerate(self.calls))))
git_cl.main(['upload'] + upload_args) git_cl.main(['upload'] + upload_args)
...@@ -1468,47 +1460,53 @@ class TestGitCl(unittest.TestCase): ...@@ -1468,47 +1460,53 @@ class TestGitCl(unittest.TestCase):
def test_update_reviewers(self): def test_update_reviewers(self):
data = [ data = [
('foo', [], [], ('foo', [], [], None, None,
'foo'), 'foo'),
('foo\nR=xx', [], [], ('foo\nR=xx', [], [], None, None,
'foo\nR=xx'), 'foo\nR=xx'),
('foo\nTBR=xx', [], [], ('foo\nTBR=xx', [], [], None, None,
'foo\nTBR=xx'), 'foo\nTBR=xx'),
('foo', ['a@c'], [], ('foo', ['a@c'], [], None, None,
'foo\n\nR=a@c'), 'foo\n\nR=a@c'),
('foo\nR=xx', ['a@c'], [], ('foo\nR=xx', ['a@c'], [], None, None,
'foo\n\nR=a@c, xx'), 'foo\n\nR=a@c, xx'),
('foo\nTBR=xx', ['a@c'], [], ('foo\nTBR=xx', ['a@c'], [], None, None,
'foo\n\nR=a@c\nTBR=xx'), 'foo\n\nR=a@c\nTBR=xx'),
('foo\nTBR=xx\nR=yy', ['a@c'], [], ('foo\nTBR=xx\nR=yy', ['a@c'], [], None, None,
'foo\n\nR=a@c, yy\nTBR=xx'), 'foo\n\nR=a@c, yy\nTBR=xx'),
('foo\nBUG=', ['a@c'], [], ('foo\nBUG=', ['a@c'], [], None, None,
'foo\nBUG=\nR=a@c'), 'foo\nBUG=\nR=a@c'),
('foo\nR=xx\nTBR=yy\nR=bar', ['a@c'], [], ('foo\nR=xx\nTBR=yy\nR=bar', ['a@c'], [], None, None,
'foo\n\nR=a@c, bar, xx\nTBR=yy'), 'foo\n\nR=a@c, bar, xx\nTBR=yy'),
('foo', ['a@c', 'b@c'], [], ('foo', ['a@c', 'b@c'], [], None, None,
'foo\n\nR=a@c, b@c'), 'foo\n\nR=a@c, b@c'),
('foo\nBar\n\nR=\nBUG=', ['c@c'], [], ('foo\nBar\n\nR=\nBUG=', ['c@c'], [], None, None,
'foo\nBar\n\nR=c@c\nBUG='), 'foo\nBar\n\nR=c@c\nBUG='),
('foo\nBar\n\nR=\nBUG=\nR=', ['c@c'], [], ('foo\nBar\n\nR=\nBUG=\nR=', ['c@c'], [], None, None,
'foo\nBar\n\nR=c@c\nBUG='), 'foo\nBar\n\nR=c@c\nBUG='),
# Same as the line before, but full of whitespaces. # Same as the line before, but full of whitespaces.
( (
'foo\nBar\n\n R = \n BUG = \n R = ', ['c@c'], [], 'foo\nBar\n\n R = \n BUG = \n R = ', ['c@c'], [], None, None,
'foo\nBar\n\nR=c@c\n BUG =', 'foo\nBar\n\nR=c@c\n BUG =',
), ),
# Whitespaces aren't interpreted as new lines. # Whitespaces aren't interpreted as new lines.
('foo BUG=allo R=joe ', ['c@c'], [], ('foo BUG=allo R=joe ', ['c@c'], [], None, None,
'foo BUG=allo R=joe\n\nR=c@c'), 'foo BUG=allo R=joe\n\nR=c@c'),
# Redundant TBRs get promoted to Rs # Redundant TBRs get promoted to Rs
('foo\n\nR=a@c\nTBR=t@c', ['b@c', 'a@c'], ['a@c', 't@c'], ('foo\n\nR=a@c\nTBR=t@c', ['b@c', 'a@c'], ['a@c', 't@c'], None, None,
'foo\n\nR=a@c, b@c\nTBR=t@c'), 'foo\n\nR=a@c, b@c\nTBR=t@c'),
# Add to R
('foo', [], [], 'R', ['a@c'],
'foo\n\nR=a@c'),
# Add to TBR
('foo', [], [], 'TBR', ['a@c'],
'foo\n\nTBR=a@c'),
] ]
expected = [i[-1] for i in data] expected = [i[-1] for i in data]
actual = [] actual = []
for orig, reviewers, tbrs, _expected in data: for orig, reviewers, tbrs, add_to, add, _expected in data:
obj = git_cl.ChangeDescription(orig) obj = git_cl.ChangeDescription(orig)
obj.update_reviewers(reviewers, tbrs, None, None, None) obj.update_reviewers(reviewers, tbrs, add_to, add)
actual.append(obj.description) actual.append(obj.description)
self.assertEqual(expected, actual) self.assertEqual(expected, actual)
...@@ -2746,7 +2744,7 @@ class TestGitCl(unittest.TestCase): ...@@ -2746,7 +2744,7 @@ class TestGitCl(unittest.TestCase):
squash=False, squash=False,
squash_mode='override_nosquash', squash_mode='override_nosquash',
change_id='I123456789', change_id='I123456789',
new_default=True) default_branch='main')
class ChangelistTest(unittest.TestCase): class ChangelistTest(unittest.TestCase):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment