Don't reset buildset when cycle dependency merged
In case a live change depends on a cycle and the cycle is merged while the item is still active the scheduler will detect the cycle as changed and re-enqueue the dependent change. The reason for this behavior is that we don't consider dependencies of merged changes when building the dependency graph. Change-Id: Ibc952886b56655c0705882497511b120e5a731cd
This commit is contained in:
parent
3bcd923a68
commit
349c6a029d
|
@ -381,6 +381,44 @@ class TestGerritCircularDependencies(ZuulTestCase):
|
||||||
self.assertEqual(B.data["status"], "MERGED")
|
self.assertEqual(B.data["status"], "MERGED")
|
||||||
self.assertEqual(C.data["status"], "MERGED")
|
self.assertEqual(C.data["status"], "MERGED")
|
||||||
|
|
||||||
|
def test_dependency_on_merged_cycle(self):
|
||||||
|
self.executor_server.hold_jobs_in_build = True
|
||||||
|
A = self.fake_gerrit.addFakeChange("org/project", "master", "A")
|
||||||
|
B = self.fake_gerrit.addFakeChange("org/project1", "master", "B")
|
||||||
|
C = self.fake_gerrit.addFakeChange("org/project2", "master", "C")
|
||||||
|
|
||||||
|
# A -> B -> C -> B (via commit-depends)
|
||||||
|
A.data["commitMessage"] = "{}\n\nDepends-On: {}\n".format(
|
||||||
|
A.subject, B.data["url"]
|
||||||
|
)
|
||||||
|
B.data["commitMessage"] = "{}\n\nDepends-On: {}\n".format(
|
||||||
|
B.subject, C.data["url"]
|
||||||
|
)
|
||||||
|
C.data["commitMessage"] = "{}\n\nDepends-On: {}\n".format(
|
||||||
|
C.subject, B.data["url"]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Start jobs for A while B + C are still open so they get
|
||||||
|
# enqueued as a non-live item ahead of A.
|
||||||
|
self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
|
||||||
|
self.waitUntilSettled()
|
||||||
|
|
||||||
|
# Fake merge of change B + C while those changes are
|
||||||
|
# still part of a non-live item as dependency for A.
|
||||||
|
B.setMerged()
|
||||||
|
C.setMerged()
|
||||||
|
self.fake_gerrit.addEvent(B.getChangeMergedEvent())
|
||||||
|
self.fake_gerrit.addEvent(C.getChangeMergedEvent())
|
||||||
|
self.waitUntilSettled()
|
||||||
|
|
||||||
|
self.executor_server.hold_jobs_in_build = False
|
||||||
|
self.executor_server.release()
|
||||||
|
self.waitUntilSettled()
|
||||||
|
|
||||||
|
self.assertHistory([
|
||||||
|
dict(name="project-job", result="SUCCESS", changes="3,1 2,1 1,1"),
|
||||||
|
], ordered=False)
|
||||||
|
|
||||||
def test_dependent_change_on_cycle(self):
|
def test_dependent_change_on_cycle(self):
|
||||||
self.executor_server.hold_jobs_in_build = True
|
self.executor_server.hold_jobs_in_build = True
|
||||||
|
|
||||||
|
|
|
@ -1633,11 +1633,18 @@ class PipelineManager(metaclass=ABCMeta):
|
||||||
# Verify that the cycle dependency graph is correct
|
# Verify that the cycle dependency graph is correct
|
||||||
cycle = self.cycleForChange(
|
cycle = self.cycleForChange(
|
||||||
item.changes[0], dependency_graph, item.event, debug=False)
|
item.changes[0], dependency_graph, item.event, debug=False)
|
||||||
cycle = cycle or [item.changes[0]]
|
cycle = set(cycle or [item.changes[0]])
|
||||||
item_cycle = set(item.changes)
|
item_cycle = set(item.changes)
|
||||||
if set(cycle) != item_cycle:
|
# We don't consider merged dependencies when building the
|
||||||
|
# dependency graph, so we need to ignore differences resulting
|
||||||
|
# from changes that have been merged in the meantime. Put any
|
||||||
|
# missing merged changes back in the cycle for comparison
|
||||||
|
# purposes.
|
||||||
|
merged_changes = set(c for c in (item_cycle - cycle) if c.is_merged)
|
||||||
|
cycle |= merged_changes
|
||||||
|
if cycle != item_cycle:
|
||||||
log.info("Item cycle has changed: %s, now: %s, was: %s", item,
|
log.info("Item cycle has changed: %s, now: %s, was: %s", item,
|
||||||
set(cycle), item_cycle)
|
cycle, item_cycle)
|
||||||
self.removeItem(item)
|
self.removeItem(item)
|
||||||
if item.live:
|
if item.live:
|
||||||
self.reEnqueueChanges(item, item.changes)
|
self.reEnqueueChanges(item, item.changes)
|
||||||
|
|
Loading…
Reference in New Issue