Fixed #22791 -- Invoke interactive questioner only for conflicts in specified apps.
Thanks bendavis78 for the report and Tim Graham for the review.
This commit is contained in:
parent
efe87d3e48
commit
f7a78f9bba
|
@ -10,6 +10,7 @@ from django.db.migrations.autodetector import MigrationAutodetector
|
||||||
from django.db.migrations.questioner import MigrationQuestioner, InteractiveMigrationQuestioner
|
from django.db.migrations.questioner import MigrationQuestioner, InteractiveMigrationQuestioner
|
||||||
from django.db.migrations.state import ProjectState
|
from django.db.migrations.state import ProjectState
|
||||||
from django.db.migrations.writer import MigrationWriter
|
from django.db.migrations.writer import MigrationWriter
|
||||||
|
from django.utils.six import iteritems
|
||||||
from django.utils.six.moves import reduce
|
from django.utils.six.moves import reduce
|
||||||
|
|
||||||
|
|
||||||
|
@ -56,6 +57,14 @@ class Command(BaseCommand):
|
||||||
# Before anything else, see if there's conflicting apps and drop out
|
# Before anything else, see if there's conflicting apps and drop out
|
||||||
# hard if there are any and they don't want to merge
|
# hard if there are any and they don't want to merge
|
||||||
conflicts = loader.detect_conflicts()
|
conflicts = loader.detect_conflicts()
|
||||||
|
|
||||||
|
# If app_labels is specified, filter out conflicting migrations for unspecified apps
|
||||||
|
if app_labels:
|
||||||
|
conflicts = dict(
|
||||||
|
(app_label, conflict) for app_label, conflict in iteritems(conflicts)
|
||||||
|
if app_label in app_labels
|
||||||
|
)
|
||||||
|
|
||||||
if conflicts and not self.merge:
|
if conflicts and not self.merge:
|
||||||
name_str = "; ".join(
|
name_str = "; ".join(
|
||||||
"%s in %s" % (", ".join(names), app)
|
"%s in %s" % (", ".join(names), app)
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
# -*- 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 = [("unspecified_app_with_conflict", "0001_initial")]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
|
||||||
|
migrations.CreateModel(
|
||||||
|
"Something",
|
||||||
|
[
|
||||||
|
("id", models.AutoField(primary_key=True)),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
]
|
|
@ -0,0 +1,26 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [("unspecified_app_with_conflict", "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)),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
]
|
|
@ -493,3 +493,49 @@ class MakeMigrationsTests(MigrationTestBase):
|
||||||
if os.path.exists(merge_file):
|
if os.path.exists(merge_file):
|
||||||
os.remove(merge_file)
|
os.remove(merge_file)
|
||||||
self.assertNotIn("Created new merge migration", stdout.getvalue())
|
self.assertNotIn("Created new merge migration", stdout.getvalue())
|
||||||
|
|
||||||
|
@override_system_checks([])
|
||||||
|
@override_settings(
|
||||||
|
MIGRATION_MODULES={"migrations": "migrations.test_migrations_no_changes"},
|
||||||
|
INSTALLED_APPS=[
|
||||||
|
"migrations",
|
||||||
|
"migrations.migrations_test_apps.unspecified_app_with_conflict"])
|
||||||
|
def test_makemigrations_unspecified_app_with_conflict_no_merge(self):
|
||||||
|
"""
|
||||||
|
Makes sure that makemigrations does not raise a CommandError when an
|
||||||
|
unspecified app has conflicting migrations.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
call_command("makemigrations", "migrations", merge=False, verbosity=0)
|
||||||
|
except CommandError:
|
||||||
|
self.fail("Makemigrations fails resolving conflicts in an unspecified app")
|
||||||
|
|
||||||
|
@override_system_checks([])
|
||||||
|
@override_settings(
|
||||||
|
INSTALLED_APPS=[
|
||||||
|
"migrations.migrations_test_apps.migrated_app",
|
||||||
|
"migrations.migrations_test_apps.unspecified_app_with_conflict"])
|
||||||
|
def test_makemigrations_unspecified_app_with_conflict_merge(self):
|
||||||
|
"""
|
||||||
|
Makes sure that makemigrations does not create a merge for an
|
||||||
|
unspecified app even if it has conflicting migrations.
|
||||||
|
"""
|
||||||
|
# Monkeypatch interactive questioner to auto accept
|
||||||
|
old_input = questioner.input
|
||||||
|
questioner.input = lambda _: "y"
|
||||||
|
stdout = six.StringIO()
|
||||||
|
merge_file = os.path.join(self.test_dir,
|
||||||
|
'migrations_test_apps',
|
||||||
|
'unspecified_app_with_conflict',
|
||||||
|
'migrations',
|
||||||
|
'0003_merge.py')
|
||||||
|
try:
|
||||||
|
call_command("makemigrations", "migrated_app", merge=True, interactive=True, stdout=stdout)
|
||||||
|
self.assertFalse(os.path.exists(merge_file))
|
||||||
|
self.assertIn("No conflicts detected to merge.", stdout.getvalue())
|
||||||
|
except CommandError:
|
||||||
|
self.fail("Makemigrations fails resolving conflicts in an unspecified app")
|
||||||
|
finally:
|
||||||
|
questioner.input = old_input
|
||||||
|
if os.path.exists(merge_file):
|
||||||
|
os.remove(merge_file)
|
||||||
|
|
Loading…
Reference in New Issue