[1.7.x] Fixed #22791 -- Invoke interactive questioner only for conflicts in specified apps.

Thanks bendavis78 for the report and Tim Graham for the review.

Backport of f7a78f9bba from master
This commit is contained in:
Huu Nguyen 2014-06-19 12:24:59 -07:00 committed by Tim Graham
parent 4b53bfff37
commit 6d5238f6c8
8 changed files with 131 additions and 0 deletions

View File

@ -11,6 +11,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
@ -58,6 +59,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)

View File

@ -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)),
],
)
]

View File

@ -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)),
],
)
]

View File

@ -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)),
],
)
]

View File

@ -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)