Merge "Don't update protected flag for missing project"
This commit is contained in:
@@ -1716,6 +1716,24 @@ class TestGithubDriver(ZuulTestCase):
|
||||
self.assertIn("can not be merged due to: draft state",
|
||||
B.comments[0])
|
||||
|
||||
@simple_layout('layouts/basic-github.yaml', driver='github')
|
||||
def test_pr_event_branch_protection(self):
|
||||
# Test that we do not try to update the protected status of a
|
||||
# project when we don't have exclude_unprotected_branches set.
|
||||
github = self.fake_github.getGithubClient()
|
||||
github.addProjectByName('org/project')
|
||||
repo = github.repo_from_project('org/project')
|
||||
repo._set_branch_protection('master', True)
|
||||
|
||||
with (mock.patch(
|
||||
"zuul.zk.branch_cache_new.BranchCacheNew.setProtected")
|
||||
as cache_mock):
|
||||
A = self.fake_github.openFakePullRequest(
|
||||
'org/project', 'master', 'A')
|
||||
self.fake_github.emitEvent(A.getPullRequestOpenedEvent())
|
||||
self.waitUntilSettled()
|
||||
cache_mock.assert_not_called()
|
||||
|
||||
|
||||
class TestMultiGithubDriver(ZuulTestCase):
|
||||
config_file = 'zuul-multi-github.conf'
|
||||
@@ -2029,6 +2047,28 @@ class TestGithubUnprotectedBranches(ZuulTestCase):
|
||||
|
||||
self.assertEqual(1, len(self.history))
|
||||
|
||||
def test_pr_event_foreign_project(self):
|
||||
# Test that we do not try to update the protected status of a
|
||||
# project that is not in any tenant config.
|
||||
self.init_repo("org/new-project")
|
||||
files = {'README': ''}
|
||||
self.addCommitToRepo("org/new-project", 'Initial commit',
|
||||
files=files, tag='init')
|
||||
|
||||
github = self.fake_github.getGithubClient()
|
||||
github.addProjectByName('org/new-project')
|
||||
repo = github.repo_from_project('org/new-project')
|
||||
repo._set_branch_protection('master', True)
|
||||
|
||||
with (mock.patch(
|
||||
"zuul.zk.branch_cache_new.BranchCacheNew.setProtected")
|
||||
as cache_mock):
|
||||
A = self.fake_github.openFakePullRequest(
|
||||
'org/new-project', 'master', 'A')
|
||||
self.fake_github.emitEvent(A.getPullRequestOpenedEvent())
|
||||
self.waitUntilSettled()
|
||||
cache_mock.assert_not_called()
|
||||
|
||||
def _test_push_event_reconfigure(self, project, branch,
|
||||
expect_reconfigure=False,
|
||||
old_sha=None, new_sha=None,
|
||||
@@ -2159,6 +2199,29 @@ class TestGithubUnprotectedBranches(ZuulTestCase):
|
||||
self.assertNotEqual(new_layout, prev_layout)
|
||||
prev_layout = new_layout
|
||||
|
||||
@okay_tracebacks('No branches for project')
|
||||
def test_branch_protection_rule_update_foreign_project(self):
|
||||
# Test the branch_protection_rule event from a project not in
|
||||
# any tenant config
|
||||
self.init_repo("org/new-project")
|
||||
files = {'README': ''}
|
||||
self.addCommitToRepo("org/new-project", 'Initial commit',
|
||||
files=files, tag='init')
|
||||
|
||||
github = self.fake_github.getGithubClient()
|
||||
github.addProjectByName('org/new-project')
|
||||
repo = github.repo_from_project('org/new-project')
|
||||
repo._set_branch_protection('master', True)
|
||||
|
||||
with (mock.patch(
|
||||
"zuul.zk.branch_cache_new.BranchCacheNew.setProtected")
|
||||
as cache_mock):
|
||||
self.fake_github.emitEvent(
|
||||
self.fake_github.getBranchProtectionRuleEvent(
|
||||
'org/new-project', 'created'))
|
||||
self.waitUntilSettled()
|
||||
cache_mock.assert_not_called()
|
||||
|
||||
|
||||
class TestGithubLockedBranches(ZuulTestCase):
|
||||
config_file = 'zuul-github-driver.conf'
|
||||
|
||||
+23
-11
@@ -2442,12 +2442,13 @@ class TestBranchCache(ZooKeeperBaseTestCase):
|
||||
self.assertEqual(
|
||||
sorted([bi.name for bi in
|
||||
cache.getProjectBranches('project1', protected_flags)
|
||||
.values()
|
||||
if bi.protected is True]),
|
||||
[bi.name for bi in test_data['project1']['protected']]
|
||||
)
|
||||
self.assertRaises(
|
||||
LookupError,
|
||||
lambda: cache.getProjectBranches('project1', all_flags),
|
||||
lambda: cache.getProjectBranches('project1', all_flags).values(),
|
||||
)
|
||||
|
||||
cache.setProjectBranches('project1', all_flags,
|
||||
@@ -2455,12 +2456,15 @@ class TestBranchCache(ZooKeeperBaseTestCase):
|
||||
self.assertEqual(
|
||||
sorted([bi.name for bi in
|
||||
cache.getProjectBranches('project1', protected_flags)
|
||||
.values()
|
||||
if bi.protected is True]),
|
||||
[bi.name for bi in test_data['project1']['protected']]
|
||||
)
|
||||
self.assertEqual(
|
||||
sorted([bi.name for bi in
|
||||
cache.getProjectBranches('project1', all_flags)]),
|
||||
cache.getProjectBranches('project1', all_flags)
|
||||
.values()
|
||||
]),
|
||||
[bi.name for bi in test_data['project1']['all']]
|
||||
)
|
||||
|
||||
@@ -2494,11 +2498,13 @@ class TestBranchCache(ZooKeeperBaseTestCase):
|
||||
|
||||
self.assertRaises(
|
||||
LookupError,
|
||||
lambda: cache.getProjectBranches('project1', protected_flags)
|
||||
lambda: cache.getProjectBranches(
|
||||
'project1', protected_flags).values()
|
||||
)
|
||||
self.assertRaises(
|
||||
LookupError,
|
||||
lambda: cache.getProjectBranches('project1', all_flags)
|
||||
lambda: cache.getProjectBranches(
|
||||
'project1', all_flags).values()
|
||||
)
|
||||
|
||||
# Test the other order; all followed by protected-only
|
||||
@@ -2506,11 +2512,13 @@ class TestBranchCache(ZooKeeperBaseTestCase):
|
||||
test_data['project1']['all'])
|
||||
self.assertRaises(
|
||||
LookupError,
|
||||
lambda: cache.getProjectBranches('project1', protected_flags)
|
||||
lambda: cache.getProjectBranches(
|
||||
'project1', protected_flags).values()
|
||||
)
|
||||
self.assertEqual(
|
||||
sorted([bi.name for bi in
|
||||
cache.getProjectBranches('project1', all_flags)]),
|
||||
cache.getProjectBranches(
|
||||
'project1', all_flags).values()]),
|
||||
[bi.name for bi in test_data['project1']['all']]
|
||||
)
|
||||
|
||||
@@ -2519,12 +2527,13 @@ class TestBranchCache(ZooKeeperBaseTestCase):
|
||||
self.assertEqual(
|
||||
sorted([bi.name for bi in
|
||||
cache.getProjectBranches('project1', protected_flags)
|
||||
.values()
|
||||
if bi.protected is True]),
|
||||
[bi.name for bi in test_data['project1']['protected']]
|
||||
)
|
||||
self.assertEqual(
|
||||
sorted([bi.name for bi in
|
||||
cache.getProjectBranches('project1', all_flags)]),
|
||||
cache.getProjectBranches('project1', all_flags).values()]),
|
||||
[bi.name for bi in test_data['project1']['all']]
|
||||
)
|
||||
|
||||
@@ -2573,12 +2582,13 @@ class TestBranchCache(ZooKeeperBaseTestCase):
|
||||
self.assertEqual(
|
||||
sorted([bi.name for bi in
|
||||
cache.getProjectBranches('project1', protected_flags)
|
||||
.values()
|
||||
if bi.protected is True]),
|
||||
[bi.name for bi in data1['project1']['protected']]
|
||||
)
|
||||
self.assertEqual(
|
||||
sorted([bi.name for bi in
|
||||
cache.getProjectBranches('project1', all_flags)]),
|
||||
cache.getProjectBranches('project1', all_flags).values()]),
|
||||
[bi.name for bi in data1['project1']['all']]
|
||||
)
|
||||
|
||||
@@ -2587,12 +2597,13 @@ class TestBranchCache(ZooKeeperBaseTestCase):
|
||||
self.assertEqual(
|
||||
sorted([bi.name for bi in
|
||||
cache.getProjectBranches('project1', protected_flags)
|
||||
.values()
|
||||
if bi.protected is True]),
|
||||
[bi.name for bi in data2['project1']['protected']]
|
||||
)
|
||||
self.assertEqual(
|
||||
sorted([bi.name for bi in
|
||||
cache.getProjectBranches('project1', all_flags)]),
|
||||
cache.getProjectBranches('project1', all_flags).values()]),
|
||||
[bi.name for bi in data2['project1']['all']]
|
||||
)
|
||||
|
||||
@@ -2601,12 +2612,13 @@ class TestBranchCache(ZooKeeperBaseTestCase):
|
||||
self.assertEqual(
|
||||
sorted([bi.name for bi in
|
||||
cache.getProjectBranches('project1', protected_flags)
|
||||
.values()
|
||||
if bi.protected is True]),
|
||||
[bi.name for bi in data1['project1']['protected']]
|
||||
)
|
||||
self.assertEqual(
|
||||
sorted([bi.name for bi in
|
||||
cache.getProjectBranches('project1', all_flags)]),
|
||||
cache.getProjectBranches('project1', all_flags).values()]),
|
||||
[bi.name for bi in data1['project1']['all']]
|
||||
)
|
||||
|
||||
@@ -2616,7 +2628,7 @@ class TestBranchCache(ZooKeeperBaseTestCase):
|
||||
cache = BranchCache(self.zk_client, conn, self.component_registry)
|
||||
self.assertRaises(
|
||||
LookupError,
|
||||
lambda: cache.getProjectBranches('project1', True)
|
||||
lambda: cache.getProjectBranches('project1', True).values()
|
||||
)
|
||||
self.assertIsNone(
|
||||
cache.getProjectBranches('project1', True, default=None)
|
||||
|
||||
+14
-19
@@ -335,8 +335,10 @@ class ZKBranchCacheMixin:
|
||||
branches = self._branch_cache.getProjectBranches(
|
||||
project.name, required_flags, min_ltime)
|
||||
if branches is not None:
|
||||
branches = [b.name for b in self._filterProjectBranches(
|
||||
branches, exclude_unprotected, exclude_locked)]
|
||||
branches = [b.name for b in
|
||||
self._filterProjectBranches(
|
||||
branches.values(), exclude_unprotected,
|
||||
exclude_locked)]
|
||||
except LookupError:
|
||||
if self.read_only:
|
||||
# A scheduler hasn't attempted to fetch them yet
|
||||
@@ -523,23 +525,16 @@ class ZKBranchCacheMixin:
|
||||
branches = self._branch_cache.getProjectBranches(
|
||||
project_name, required_flags, default=None)
|
||||
|
||||
if not branches:
|
||||
branches = []
|
||||
|
||||
branches = [b.name for b in branches]
|
||||
|
||||
update = False
|
||||
if (event.branch in branches) and (not protected):
|
||||
update = True
|
||||
if (event.branch not in branches) and (protected):
|
||||
update = True
|
||||
if update:
|
||||
self.log.info("Project %s branch %s protected state "
|
||||
"changed to %s",
|
||||
project_name, event.branch, protected)
|
||||
self._branch_cache.setProtected(
|
||||
project_name, event.branch, protected)
|
||||
event.branch_cache_ltime = self._branch_cache.ltime
|
||||
if branches is not None:
|
||||
if ((branch_info := branches.get(event.branch)) is None or
|
||||
branch_info.protected != protected):
|
||||
log = get_annotated_logger(self.log, event)
|
||||
log.info("Project %s branch %s protected state "
|
||||
"changed to %s",
|
||||
project_name, event.branch, protected)
|
||||
self._branch_cache.setProtected(
|
||||
project_name, event.branch, protected)
|
||||
event.branch_cache_ltime = self._branch_cache.ltime
|
||||
|
||||
event.branch_protected = protected
|
||||
else:
|
||||
|
||||
@@ -680,7 +680,7 @@ class GithubEventProcessor(object):
|
||||
if cached_branches is None:
|
||||
raise RuntimeError(f"No branches for project {project_name}")
|
||||
else:
|
||||
cached_branches = [b.name for b in cached_branches
|
||||
cached_branches = [b.name for b in cached_branches.values()
|
||||
if b.protected is True]
|
||||
old_protected_branches = set(cached_branches)
|
||||
|
||||
@@ -697,7 +697,8 @@ class GithubEventProcessor(object):
|
||||
self.connection._branch_cache.getProjectBranches(
|
||||
project_name, BranchFlag.PROTECTED)
|
||||
new_protected_branches = set(
|
||||
[b.name for b in new_protected_branches if b.protected is True])
|
||||
[b.name for b in new_protected_branches.values()
|
||||
if b.protected is True])
|
||||
|
||||
newly_protected = new_protected_branches - old_protected_branches
|
||||
newly_unprotected = old_protected_branches - new_protected_branches
|
||||
|
||||
@@ -239,8 +239,9 @@ class BranchCacheNew:
|
||||
:param any default:
|
||||
Optional default value to return if no cache entry exits.
|
||||
|
||||
:returns: The list of branch names, or None if there was
|
||||
an error when fetching the branches.
|
||||
:returns: A dictionary of {branch_name: BranchInfo} objects,
|
||||
or None if there was an error when fetching the branches.
|
||||
|
||||
"""
|
||||
project_info = self._getProjectInfoForRead(project_name, min_ltime)
|
||||
if project_info is None:
|
||||
@@ -258,7 +259,7 @@ class BranchCacheNew:
|
||||
return return_default(default, project_name)
|
||||
|
||||
# We have the necessary info for this filtering.
|
||||
return list(project_info.branches.values())
|
||||
return project_info.branches
|
||||
|
||||
def setProjectBranches(self, project_name,
|
||||
valid_flags, branch_infos):
|
||||
|
||||
@@ -202,8 +202,9 @@ class BranchCacheOld:
|
||||
:param any default:
|
||||
Optional default value to return if no cache entry exits.
|
||||
|
||||
:returns: The list of branch names, or None if there was
|
||||
an error when fetching the branches.
|
||||
:returns: A dictionary of {branch_name: BranchInfo} objects,
|
||||
or None if there was an error when fetching the branches.
|
||||
|
||||
"""
|
||||
if self.ltime < min_ltime:
|
||||
with (zk_locked(self.rlock),
|
||||
@@ -232,7 +233,7 @@ class BranchCacheOld:
|
||||
return return_default(default, project_name)
|
||||
|
||||
# We have the necessary info for this filtering.
|
||||
return list(project_info.branches.values())
|
||||
return project_info.branches
|
||||
|
||||
def setProjectBranches(self, project_name,
|
||||
valid_flags, branch_infos):
|
||||
|
||||
Reference in New Issue
Block a user