Fixed #24755 -- Hid operations from dependency apps when merging migrations
Thanks Carl Meyer for the report and Tim Graham for the review.
This commit is contained in:
parent
75b5de8d5f
commit
0271a11ba5
|
@ -194,13 +194,17 @@ class Command(BaseCommand):
|
||||||
questioner = InteractiveMigrationQuestioner()
|
questioner = InteractiveMigrationQuestioner()
|
||||||
else:
|
else:
|
||||||
questioner = MigrationQuestioner(defaults={'ask_merge': True})
|
questioner = MigrationQuestioner(defaults={'ask_merge': True})
|
||||||
|
|
||||||
for app_label, migration_names in conflicts.items():
|
for app_label, migration_names in conflicts.items():
|
||||||
# Grab out the migrations in question, and work out their
|
# Grab out the migrations in question, and work out their
|
||||||
# common ancestor.
|
# common ancestor.
|
||||||
merge_migrations = []
|
merge_migrations = []
|
||||||
for migration_name in migration_names:
|
for migration_name in migration_names:
|
||||||
migration = loader.get_migration(app_label, migration_name)
|
migration = loader.get_migration(app_label, migration_name)
|
||||||
migration.ancestry = loader.graph.forwards_plan((app_label, migration_name))
|
migration.ancestry = [
|
||||||
|
mig for mig in loader.graph.forwards_plan((app_label, migration_name))
|
||||||
|
if mig[0] == migration.app_label
|
||||||
|
]
|
||||||
merge_migrations.append(migration)
|
merge_migrations.append(migration)
|
||||||
all_items_equal = lambda seq: all(item == seq[0] for item in seq[1:])
|
all_items_equal = lambda seq: all(item == seq[0] for item in seq[1:])
|
||||||
merge_migrations_generations = zip(*[m.ancestry for m in merge_migrations])
|
merge_migrations_generations = zip(*[m.ancestry for m in merge_migrations])
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
"Author",
|
||||||
|
[
|
||||||
|
("id", models.AutoField(primary_key=True)),
|
||||||
|
("name", models.CharField(max_length=255)),
|
||||||
|
("slug", models.SlugField(null=True)),
|
||||||
|
("age", models.IntegerField(default=0)),
|
||||||
|
("silly_field", models.BooleanField(default=False)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
"Tribble",
|
||||||
|
[
|
||||||
|
("id", models.AutoField(primary_key=True)),
|
||||||
|
("fluffy", models.BooleanField(default=True)),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
]
|
|
@ -0,0 +1,20 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("conflicting_app_with_dependencies", "0001_initial"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
"Something",
|
||||||
|
[
|
||||||
|
("id", models.AutoField(primary_key=True)),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
]
|
|
@ -0,0 +1,24 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("conflicting_app_with_dependencies", "0001_initial"),
|
||||||
|
("migrated_app", "0001_initial"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.DeleteModel("Tribble"),
|
||||||
|
migrations.RemoveField("Author", "silly_field"),
|
||||||
|
migrations.AddField("Author", "rating", models.IntegerField(default=0)),
|
||||||
|
migrations.CreateModel(
|
||||||
|
"Book",
|
||||||
|
[
|
||||||
|
("id", models.AutoField(primary_key=True)),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
]
|
|
@ -920,6 +920,39 @@ class MakeMigrationsTests(MigrationTestBase):
|
||||||
except CommandError:
|
except CommandError:
|
||||||
self.fail("Makemigrations fails resolving conflicts in an unspecified app")
|
self.fail("Makemigrations fails resolving conflicts in an unspecified app")
|
||||||
|
|
||||||
|
@override_settings(
|
||||||
|
INSTALLED_APPS=[
|
||||||
|
"migrations.migrations_test_apps.migrated_app",
|
||||||
|
"migrations.migrations_test_apps.conflicting_app_with_dependencies"])
|
||||||
|
def test_makemigrations_merge_dont_output_dependency_operations(self):
|
||||||
|
"""
|
||||||
|
Makes sure that makemigrations --merge does not output any operations
|
||||||
|
from apps that don't belong to a given app.
|
||||||
|
"""
|
||||||
|
# Monkeypatch interactive questioner to auto accept
|
||||||
|
with mock.patch('django.db.migrations.questioner.input', mock.Mock(return_value='N')):
|
||||||
|
out = six.StringIO()
|
||||||
|
with mock.patch('django.core.management.color.supports_color', lambda *args: False):
|
||||||
|
call_command(
|
||||||
|
"makemigrations", "conflicting_app_with_dependencies",
|
||||||
|
merge=True, interactive=True, stdout=out
|
||||||
|
)
|
||||||
|
val = out.getvalue().lower()
|
||||||
|
self.assertIn('merging conflicting_app_with_dependencies\n', val)
|
||||||
|
self.assertIn(
|
||||||
|
' branch 0002_conflicting_second\n'
|
||||||
|
' - create model something\n',
|
||||||
|
val
|
||||||
|
)
|
||||||
|
self.assertIn(
|
||||||
|
' branch 0002_second\n'
|
||||||
|
' - delete model tribble\n'
|
||||||
|
' - remove field silly_field from author\n'
|
||||||
|
' - add field rating to author\n'
|
||||||
|
' - create model book\n',
|
||||||
|
val
|
||||||
|
)
|
||||||
|
|
||||||
def test_makemigrations_with_custom_name(self):
|
def test_makemigrations_with_custom_name(self):
|
||||||
"""
|
"""
|
||||||
Makes sure that makemigrations generate a custom migration.
|
Makes sure that makemigrations generate a custom migration.
|
||||||
|
|
Loading…
Reference in New Issue