Fixed #29783 -- Added app label validation to showmigrations command.
This commit is contained in:
parent
817c6cdf0e
commit
df448bfd02
1
AUTHORS
1
AUTHORS
|
@ -449,6 +449,7 @@ answer newbie questions, and generally made Django that much better:
|
||||||
Julia Matsieva <julia.matsieva@gmail.com>
|
Julia Matsieva <julia.matsieva@gmail.com>
|
||||||
Julian Bez
|
Julian Bez
|
||||||
Julien Phalip <jphalip@gmail.com>
|
Julien Phalip <jphalip@gmail.com>
|
||||||
|
Junyoung Choi <cupjoo@gmail.com>
|
||||||
junzhang.jn@gmail.com
|
junzhang.jn@gmail.com
|
||||||
Jure Cuhalev <gandalf@owca.info>
|
Jure Cuhalev <gandalf@owca.info>
|
||||||
Justin Bronn <jbronn@gmail.com>
|
Justin Bronn <jbronn@gmail.com>
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
from django.core.management.base import BaseCommand, CommandError
|
import sys
|
||||||
|
|
||||||
|
from django.apps import apps
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
from django.db import DEFAULT_DB_ALIAS, connections
|
from django.db import DEFAULT_DB_ALIAS, connections
|
||||||
from django.db.migrations.loader import MigrationLoader
|
from django.db.migrations.loader import MigrationLoader
|
||||||
|
|
||||||
|
@ -45,12 +48,15 @@ class Command(BaseCommand):
|
||||||
return self.show_list(connection, options['app_label'])
|
return self.show_list(connection, options['app_label'])
|
||||||
|
|
||||||
def _validate_app_names(self, loader, app_names):
|
def _validate_app_names(self, loader, app_names):
|
||||||
invalid_apps = []
|
has_bad_names = False
|
||||||
for app_name in app_names:
|
for app_name in app_names:
|
||||||
if app_name not in loader.migrated_apps:
|
try:
|
||||||
invalid_apps.append(app_name)
|
apps.get_app_config(app_name)
|
||||||
if invalid_apps:
|
except LookupError as err:
|
||||||
raise CommandError('No migrations present for: %s' % (', '.join(sorted(invalid_apps))))
|
self.stderr.write(str(err))
|
||||||
|
has_bad_names = True
|
||||||
|
if has_bad_names:
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
def show_list(self, connection, app_names=None):
|
def show_list(self, connection, app_names=None):
|
||||||
"""
|
"""
|
||||||
|
@ -129,3 +135,5 @@ class Command(BaseCommand):
|
||||||
self.stdout.write("[X] %s.%s%s" % (node.key[0], node.key[1], deps))
|
self.stdout.write("[X] %s.%s%s" % (node.key[0], node.key[1], deps))
|
||||||
else:
|
else:
|
||||||
self.stdout.write("[ ] %s.%s%s" % (node.key[0], node.key[1], deps))
|
self.stdout.write("[ ] %s.%s%s" % (node.key[0], node.key[1], deps))
|
||||||
|
if not plan:
|
||||||
|
self.stdout.write('(no migrations)', self.style.ERROR)
|
||||||
|
|
|
@ -381,8 +381,9 @@ class MigrateTests(MigrationTestBase):
|
||||||
|
|
||||||
@override_settings(INSTALLED_APPS=['migrations.migrations_test_apps.unmigrated_app'])
|
@override_settings(INSTALLED_APPS=['migrations.migrations_test_apps.unmigrated_app'])
|
||||||
def test_showmigrations_unmigrated_app(self):
|
def test_showmigrations_unmigrated_app(self):
|
||||||
with self.assertRaisesMessage(CommandError, 'No migrations present for: unmigrated_app'):
|
out = io.StringIO()
|
||||||
call_command('showmigrations', 'unmigrated_app')
|
call_command('showmigrations', 'unmigrated_app', stdout=out, no_color=True)
|
||||||
|
self.assertEqual('unmigrated_app\n (no migrations)\n', out.getvalue().lower())
|
||||||
|
|
||||||
@override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_empty"})
|
@override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_empty"})
|
||||||
def test_showmigrations_plan_no_migrations(self):
|
def test_showmigrations_plan_no_migrations(self):
|
||||||
|
@ -390,12 +391,12 @@ class MigrateTests(MigrationTestBase):
|
||||||
Tests --plan output of showmigrations command without migrations
|
Tests --plan output of showmigrations command without migrations
|
||||||
"""
|
"""
|
||||||
out = io.StringIO()
|
out = io.StringIO()
|
||||||
call_command("showmigrations", format='plan', stdout=out)
|
call_command('showmigrations', format='plan', stdout=out, no_color=True)
|
||||||
self.assertEqual("", out.getvalue().lower())
|
self.assertEqual('(no migrations)\n', out.getvalue().lower())
|
||||||
|
|
||||||
out = io.StringIO()
|
out = io.StringIO()
|
||||||
call_command("showmigrations", format='plan', stdout=out, verbosity=2)
|
call_command('showmigrations', format='plan', stdout=out, verbosity=2, no_color=True)
|
||||||
self.assertEqual("", out.getvalue().lower())
|
self.assertEqual('(no migrations)\n', out.getvalue().lower())
|
||||||
|
|
||||||
@override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed_complex"})
|
@override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed_complex"})
|
||||||
def test_showmigrations_plan_squashed(self):
|
def test_showmigrations_plan_squashed(self):
|
||||||
|
@ -522,22 +523,10 @@ class MigrateTests(MigrationTestBase):
|
||||||
)
|
)
|
||||||
|
|
||||||
@override_settings(INSTALLED_APPS=['migrations.migrations_test_apps.unmigrated_app'])
|
@override_settings(INSTALLED_APPS=['migrations.migrations_test_apps.unmigrated_app'])
|
||||||
def test_showmigrations_plan_app_label_error(self):
|
def test_showmigrations_plan_app_label_no_migrations(self):
|
||||||
"""
|
out = io.StringIO()
|
||||||
`showmigrations --plan app_label` raises an error when no app or
|
call_command('showmigrations', 'unmigrated_app', format='plan', stdout=out, no_color=True)
|
||||||
no migrations are present in provided app labels.
|
self.assertEqual('(no migrations)\n', out.getvalue())
|
||||||
"""
|
|
||||||
# App with no migrations.
|
|
||||||
with self.assertRaisesMessage(CommandError, 'No migrations present for: unmigrated_app'):
|
|
||||||
call_command('showmigrations', 'unmigrated_app', format='plan')
|
|
||||||
# Nonexistent app (wrong app label).
|
|
||||||
with self.assertRaisesMessage(CommandError, 'No migrations present for: nonexistent_app'):
|
|
||||||
call_command('showmigrations', 'nonexistent_app', format='plan')
|
|
||||||
# Multiple nonexistent apps; input order shouldn't matter.
|
|
||||||
with self.assertRaisesMessage(CommandError, 'No migrations present for: nonexistent_app1, nonexistent_app2'):
|
|
||||||
call_command('showmigrations', 'nonexistent_app1', 'nonexistent_app2', format='plan')
|
|
||||||
with self.assertRaisesMessage(CommandError, 'No migrations present for: nonexistent_app1, nonexistent_app2'):
|
|
||||||
call_command('showmigrations', 'nonexistent_app2', 'nonexistent_app1', format='plan')
|
|
||||||
|
|
||||||
@override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations"})
|
@override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations"})
|
||||||
def test_sqlmigrate_forwards(self):
|
def test_sqlmigrate_forwards(self):
|
||||||
|
@ -1561,6 +1550,18 @@ class AppLabelErrorTests(TestCase):
|
||||||
with self.assertRaisesMessage(CommandError, self.did_you_mean_auth_error):
|
with self.assertRaisesMessage(CommandError, self.did_you_mean_auth_error):
|
||||||
call_command('migrate', 'django.contrib.auth')
|
call_command('migrate', 'django.contrib.auth')
|
||||||
|
|
||||||
|
def test_showmigrations_nonexistent_app_label(self):
|
||||||
|
err = io.StringIO()
|
||||||
|
with self.assertRaises(SystemExit):
|
||||||
|
call_command('showmigrations', 'nonexistent_app', stderr=err)
|
||||||
|
self.assertIn(self.nonexistent_app_error, err.getvalue())
|
||||||
|
|
||||||
|
def test_showmigrations_app_name_specified_as_label(self):
|
||||||
|
err = io.StringIO()
|
||||||
|
with self.assertRaises(SystemExit):
|
||||||
|
call_command('showmigrations', 'django.contrib.auth', stderr=err)
|
||||||
|
self.assertIn(self.did_you_mean_auth_error, err.getvalue())
|
||||||
|
|
||||||
def test_sqlmigrate_nonexistent_app_label(self):
|
def test_sqlmigrate_nonexistent_app_label(self):
|
||||||
with self.assertRaisesMessage(CommandError, self.nonexistent_app_error):
|
with self.assertRaisesMessage(CommandError, self.nonexistent_app_error):
|
||||||
call_command('sqlmigrate', 'nonexistent_app', '0002')
|
call_command('sqlmigrate', 'nonexistent_app', '0002')
|
||||||
|
|
Loading…
Reference in New Issue