Fixed #31402 -- Added migrate --check option.

Command exits with non-zero status if unapplied migrations exist.
This commit is contained in:
Gordon Pendleton 2020-03-26 05:08:58 -04:00 committed by Mariusz Felisiak
parent 4216225480
commit d0da2820ca
4 changed files with 53 additions and 0 deletions

View File

@ -1,3 +1,4 @@
import sys
import time
from importlib import import_module
@ -62,6 +63,10 @@ class Command(BaseCommand):
'--run-syncdb', action='store_true',
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
def handle(self, *args, **options):
@ -143,6 +148,7 @@ class Command(BaseCommand):
targets = executor.loader.graph.leaf_nodes()
plan = executor.migration_plan(targets)
exit_dry = plan and options['check_unapplied']
if options['plan']:
self.stdout.write('Planned operations:', self.style.MIGRATE_LABEL)
@ -154,7 +160,11 @@ class Command(BaseCommand):
message, is_error = self.describe_operation(operation, backwards)
style = self.style.WARNING if is_error else None
self.stdout.write(' ' + message, style)
if exit_dry:
sys.exit(1)
return
if exit_dry:
sys.exit(1)
# At this point, ignore run_syncdb if there aren't any apps to sync.
run_syncdb = options['run_syncdb'] and executor.loader.unmigrated_apps

View File

@ -865,6 +865,13 @@ with hundreds of models.
Suppresses all user prompts. An example prompt is asking about removing stale
content types.
.. django-admin-option:: --check
.. versionadded:: 3.1
Makes ``migrate`` exit with a non-zero status when unapplied migrations are
detected.
``runserver``
-------------

View File

@ -300,6 +300,9 @@ Management Commands
enabled for all configured :setting:`DATABASES` by passing the ``database``
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
~~~~~~~~~~

View File

@ -249,6 +249,39 @@ class MigrateTests(MigrationTestBase):
with self.assertRaisesMessage(CommandError, "Conflicting migrations detected"):
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"})
def test_showmigrations_list(self):
"""