- Fixed bug where the case of multiple mergepoints that all

have the identical set of ancestor revisions would fail to be
upgradable, producing an assertion failure.   Merge points were
previously assumed to always require at least an UPDATE in
alembic_revision from one of the previous revs to the new one,
however in this case, if one of the mergepoints has already
been reached, the remaining mergepoints have no row to UPDATE therefore
they must do an INSERT of their target version.
fixes #297
This commit is contained in:
Mike Bayer
2015-05-03 20:17:19 -04:00
parent b35dbff602
commit c75be37640
3 changed files with 170 additions and 7 deletions

View File

@@ -670,14 +670,15 @@ class RevisionStep(MigrationStep):
if not downrevs:
# is a base
return True
elif len(downrevs) == 1:
if downrevs[0] in heads:
return False
else:
return True
else:
# is a merge point
return False
# none of our downrevs are present, so...
# we have to insert our version. This is true whether
# or not there is only one downrev, or multiple (in the latter
# case, we're a merge point.)
if not heads.intersection(downrevs):
return True
else:
return False
def should_merge_branches(self, heads):
if not self.is_upgrade:

View File

@@ -6,6 +6,19 @@ Changelog
.. changelog::
:version: 0.7.6
.. change::
:tags: feature, versioning
:tickets: 297
Fixed bug where the case of multiple mergepoints that all
have the identical set of ancestor revisions would fail to be
upgradable, producing an assertion failure. Merge points were
previously assumed to always require at least an UPDATE in
alembic_revision from one of the previous revs to the new one,
however in this case, if one of the mergepoints has already
been reached, the remaining mergepoints have no row to UPDATE therefore
they must do an INSERT of their target version.
.. change::
:tags: feature, autogenerate
:tickets: 296

View File

@@ -434,6 +434,155 @@ class BranchFrom3WayMergepointTest(MigrationTest):
)
class TwinMergeTest(MigrationTest):
"""Test #297, where we have two mergepoints from the same set of
originating branches.
"""
@classmethod
def setup_class(cls):
"""
33e21c000cfe -> 178d4e761bbd (head),
2bef33cb3a58, 3904558db1c6, 968330f320d -> 33e21c000cfe (mergepoint)
46c99f866004 -> 18f46b42410d (head),
2bef33cb3a58, 3904558db1c6, 968330f320d -> 46c99f866004 (mergepoint)
f0fa4315825 -> 3904558db1c6 (branchpoint),
--------------------------
A -> B2 (branchpoint),
B1, B2, B3 -> C1 (mergepoint)
B1, B2, B3 -> C2 (mergepoint)
C1 -> D1 (head),
C2 -> D2 (head),
"""
cls.env = env = staging_env()
cls.a = env.generate_revision(
'a', 'a'
)
cls.b1 = env.generate_revision('b1', 'b1',
head=cls.a.revision)
cls.b2 = env.generate_revision('b2', 'b2',
splice=True,
head=cls.a.revision)
cls.b3 = env.generate_revision('b3', 'b3',
splice=True,
head=cls.a.revision)
cls.c1 = env.generate_revision(
'c1', 'c1',
head=(cls.b1.revision, cls.b2.revision, cls.b3.revision))
cls.c2 = env.generate_revision(
'c2', 'c2',
splice=True,
head=(cls.b1.revision, cls.b2.revision, cls.b3.revision))
cls.d1 = env.generate_revision(
'd1', 'd1', head=cls.c1.revision)
cls.d2 = env.generate_revision(
'd2', 'd2', head=cls.c2.revision)
def test_upgrade(self):
head = HeadMaintainer(mock.Mock(), [self.a.revision])
steps = [
(self.up_(self.b3), ('b3',)),
(self.up_(self.b1), ('b1', 'b3',)),
(self.up_(self.b2), ('b1', 'b2', 'b3',)),
(self.up_(self.c2), ('c2',)),
(self.up_(self.d2), ('d2',)),
(self.up_(self.c1), ('c1', 'd2')),
(self.up_(self.d1), ('d1', 'd2')),
]
for step, assert_ in steps:
head.update_to_step(step)
eq_(head.heads, set(assert_))
class NotQuiteTwinMergeTest(MigrationTest):
"""Test a variant of #297.
"""
@classmethod
def setup_class(cls):
"""
A -> B2 (branchpoint),
B1, B2 -> C1 (mergepoint)
B2, B3 -> C2 (mergepoint)
C1 -> D1 (head),
C2 -> D2 (head),
"""
cls.env = env = staging_env()
cls.a = env.generate_revision(
'a', 'a'
)
cls.b1 = env.generate_revision('b1', 'b1',
head=cls.a.revision)
cls.b2 = env.generate_revision('b2', 'b2',
splice=True,
head=cls.a.revision)
cls.b3 = env.generate_revision('b3', 'b3',
splice=True,
head=cls.a.revision)
cls.c1 = env.generate_revision(
'c1', 'c1',
head=(cls.b1.revision, cls.b2.revision))
cls.c2 = env.generate_revision(
'c2', 'c2',
splice=True,
head=(cls.b2.revision, cls.b3.revision))
cls.d1 = env.generate_revision(
'd1', 'd1', head=cls.c1.revision)
cls.d2 = env.generate_revision(
'd2', 'd2', head=cls.c2.revision)
def test_upgrade(self):
head = HeadMaintainer(mock.Mock(), [self.a.revision])
"""
upgrade a -> b2, b2
upgrade a -> b3, b3
upgrade b2, b3 -> c2, c2
upgrade c2 -> d2, d2
upgrade a -> b1, b1
upgrade b1, b2 -> c1, c1
upgrade c1 -> d1, d1
"""
steps = [
(self.up_(self.b2), ('b2',)),
(self.up_(self.b3), ('b2', 'b3',)),
(self.up_(self.c2), ('c2',)),
(self.up_(self.d2), ('d2',)),
(self.up_(self.b1), ('b1', 'd2',)),
(self.up_(self.c1), ('c1', 'd2')),
(self.up_(self.d1), ('d1', 'd2')),
]
for step, assert_ in steps:
head.update_to_step(step)
eq_(head.heads, set(assert_))
class DependsOnBranchTestOne(MigrationTest):
@classmethod