Fixed #31402 -- Added migrate --check option.
Command exits with non-zero status if unapplied migrations exist.
This commit is contained in:
parent
4216225480
commit
d0da2820ca
|
@ -1,3 +1,4 @@
|
||||||
|
import sys
|
||||||
import time
|
import time
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
|
|
||||||
|
@ -62,6 +63,10 @@ class Command(BaseCommand):
|
||||||
'--run-syncdb', action='store_true',
|
'--run-syncdb', action='store_true',
|
||||||
help='Creates tables for apps without migrations.',
|
help='Creates tables for apps without migrations.',
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--check', action='store_true', dest='check_unapplied',
|
||||||
|
help='Exits with a non-zero status if unapplied migrations exist.',
|
||||||
|
)
|
||||||
|
|
||||||
@no_translations
|
@no_translations
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
|
@ -143,6 +148,7 @@ class Command(BaseCommand):
|
||||||
targets = executor.loader.graph.leaf_nodes()
|
targets = executor.loader.graph.leaf_nodes()
|
||||||
|
|
||||||
plan = executor.migration_plan(targets)
|
plan = executor.migration_plan(targets)
|
||||||
|
exit_dry = plan and options['check_unapplied']
|
||||||
|
|
||||||
if options['plan']:
|
if options['plan']:
|
||||||
self.stdout.write('Planned operations:', self.style.MIGRATE_LABEL)
|
self.stdout.write('Planned operations:', self.style.MIGRATE_LABEL)
|
||||||
|
@ -154,7 +160,11 @@ class Command(BaseCommand):
|
||||||
message, is_error = self.describe_operation(operation, backwards)
|
message, is_error = self.describe_operation(operation, backwards)
|
||||||
style = self.style.WARNING if is_error else None
|
style = self.style.WARNING if is_error else None
|
||||||
self.stdout.write(' ' + message, style)
|
self.stdout.write(' ' + message, style)
|
||||||
|
if exit_dry:
|
||||||
|
sys.exit(1)
|
||||||
return
|
return
|
||||||
|
if exit_dry:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
# At this point, ignore run_syncdb if there aren't any apps to sync.
|
# At this point, ignore run_syncdb if there aren't any apps to sync.
|
||||||
run_syncdb = options['run_syncdb'] and executor.loader.unmigrated_apps
|
run_syncdb = options['run_syncdb'] and executor.loader.unmigrated_apps
|
||||||
|
|
|
@ -865,6 +865,13 @@ with hundreds of models.
|
||||||
Suppresses all user prompts. An example prompt is asking about removing stale
|
Suppresses all user prompts. An example prompt is asking about removing stale
|
||||||
content types.
|
content types.
|
||||||
|
|
||||||
|
.. django-admin-option:: --check
|
||||||
|
|
||||||
|
.. versionadded:: 3.1
|
||||||
|
|
||||||
|
Makes ``migrate`` exit with a non-zero status when unapplied migrations are
|
||||||
|
detected.
|
||||||
|
|
||||||
``runserver``
|
``runserver``
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
|
|
@ -300,6 +300,9 @@ Management Commands
|
||||||
enabled for all configured :setting:`DATABASES` by passing the ``database``
|
enabled for all configured :setting:`DATABASES` by passing the ``database``
|
||||||
tag to the command.
|
tag to the command.
|
||||||
|
|
||||||
|
* The new :option:`migrate --check` option makes the command exit with a
|
||||||
|
non-zero status when unapplied migrations are detected.
|
||||||
|
|
||||||
Migrations
|
Migrations
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -249,6 +249,39 @@ class MigrateTests(MigrationTestBase):
|
||||||
with self.assertRaisesMessage(CommandError, "Conflicting migrations detected"):
|
with self.assertRaisesMessage(CommandError, "Conflicting migrations detected"):
|
||||||
call_command("migrate", "migrations")
|
call_command("migrate", "migrations")
|
||||||
|
|
||||||
|
@override_settings(MIGRATION_MODULES={
|
||||||
|
'migrations': 'migrations.test_migrations',
|
||||||
|
})
|
||||||
|
def test_migrate_check(self):
|
||||||
|
with self.assertRaises(SystemExit):
|
||||||
|
call_command('migrate', 'migrations', '0001', check_unapplied=True, verbosity=0)
|
||||||
|
self.assertTableNotExists('migrations_author')
|
||||||
|
self.assertTableNotExists('migrations_tribble')
|
||||||
|
self.assertTableNotExists('migrations_book')
|
||||||
|
|
||||||
|
@override_settings(MIGRATION_MODULES={
|
||||||
|
'migrations': 'migrations.test_migrations_plan',
|
||||||
|
})
|
||||||
|
def test_migrate_check_plan(self):
|
||||||
|
out = io.StringIO()
|
||||||
|
with self.assertRaises(SystemExit):
|
||||||
|
call_command(
|
||||||
|
'migrate',
|
||||||
|
'migrations',
|
||||||
|
'0001',
|
||||||
|
check_unapplied=True,
|
||||||
|
plan=True,
|
||||||
|
stdout=out,
|
||||||
|
no_color=True,
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
'Planned operations:\n'
|
||||||
|
'migrations.0001_initial\n'
|
||||||
|
' Create model Salamander\n'
|
||||||
|
' Raw Python operation -> Grow salamander tail.\n',
|
||||||
|
out.getvalue(),
|
||||||
|
)
|
||||||
|
|
||||||
@override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations"})
|
@override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations"})
|
||||||
def test_showmigrations_list(self):
|
def test_showmigrations_list(self):
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in New Issue