Avoid infinite recursion with topic dependencies

When updating topic dependencies we only consider the current patchset.
However, when there are changes that have a git-level dependency to an
outdated patchset and those dependencies are in a different topic we can
run into max. recursion depth issues.

To fix this problem, we will keep a history of topics that we've already
processed and not call `getChangesByTopic()` again when we've already
seen a topic.

Change-Id: I6c15f502cfd593a44d7adda930670692151b6713
This commit is contained in:
Simon Westphahl
2023-09-13 14:54:15 +02:00
parent a7a9083d67
commit f88a69c7b3
2 changed files with 38 additions and 3 deletions

View File

@ -2504,6 +2504,37 @@ class TestGerritCircularDependencies(ZuulTestCase):
self.assertEqual(C.data["status"], "MERGED")
self.assertEqual(D.data["status"], "MERGED")
@simple_layout('layouts/deps-by-topic.yaml')
def test_deps_by_topic_git_needs_outdated_patchset(self):
A = self.fake_gerrit.addFakeChange('org/project1', "master", "A",
topic='test-topic')
B = self.fake_gerrit.addFakeChange('org/project1', "master", "B",
topic='other-topic')
C = self.fake_gerrit.addFakeChange('org/project2', "master", "C",
topic='other-topic')
D = self.fake_gerrit.addFakeChange('org/project2', "master", "D",
topic='test-topic')
B.addPatchset()
D.addPatchset()
# Git level dependency between A and B + C and D on outdated
# patchset.
A.setDependsOn(B, 1)
C.setDependsOn(D, 1)
self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
self.fake_gerrit.addEvent(D.getPatchsetCreatedEvent(2))
self.waitUntilSettled()
self.assertHistory([
dict(name="check-job", result="SUCCESS",
changes="4,2 4,1 3,1 2,2 2,1 1,1"),
dict(name="check-job", result="SUCCESS",
changes="4,2 2,2 2,1 1,1 4,1 3,1"),
], ordered=False)
@simple_layout('layouts/deps-by-topic.yaml')
def test_deps_by_topic_new_patchset(self):
# Make sure that we correctly update the change cache on new

View File

@ -145,13 +145,17 @@ class GerritSource(BaseSource):
changes.append(change)
return changes
def getChangesByTopic(self, topic, changes=None):
def getChangesByTopic(self, topic, changes=None, history=None):
if not topic:
return []
if changes is None:
changes = {}
if history is None:
history = []
history.append(topic)
query = 'status:open topic:%s' % topic
results = self.connection.simpleQuery(query)
for result in results:
@ -173,9 +177,9 @@ class GerritSource(BaseSource):
if change_key in changes:
continue
git_change = self.getChange(change_key)
if not git_change.topic or git_change.topic == topic:
if not git_change.topic or git_change.topic in history:
continue
self.getChangesByTopic(git_change.topic, changes)
self.getChangesByTopic(git_change.topic, changes, history)
return list(changes.values())
def getCachedChanges(self):