From 0ac13eccebb3d879f79b31585b1e81f655067179 Mon Sep 17 00:00:00 2001
From: mlavin <markdlavin@gmail.com>
Date: Sat, 8 Feb 2014 08:50:01 -0500
Subject: [PATCH 1/2] Remove check_migrations from the runserver command and
 use the new checks framework to check for unapplied migrations. Don't check
 for migrations if the DATABASES setting is empty.

---
 django/core/checks/__init__.py               |  1 +
 django/core/checks/migrations.py             | 31 ++++++++++++++++++++
 django/core/management/commands/runserver.py | 14 ---------
 3 files changed, 32 insertions(+), 14 deletions(-)
 create mode 100644 django/core/checks/migrations.py

diff --git a/django/core/checks/__init__.py b/django/core/checks/__init__.py
index 82a3acf337..691f2f9606 100644
--- a/django/core/checks/__init__.py
+++ b/django/core/checks/__init__.py
@@ -8,6 +8,7 @@ from .registry import register, run_checks, tag_exists
 
 # Import these to force registration of checks
 import django.core.checks.compatibility.django_1_6_0  # NOQA
+import django.core.checks.migrations  # NOQA
 import django.core.checks.model_checks  # NOQA
 
 __all__ = [
diff --git a/django/core/checks/migrations.py b/django/core/checks/migrations.py
new file mode 100644
index 0000000000..c557ad39e7
--- /dev/null
+++ b/django/core/checks/migrations.py
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.conf import settings
+
+from . import Warning, register
+
+
+@register('migrations')
+def check_migrations(app_configs=None, **kwargs):
+    """
+    Checks to see if the set of migrations on disk matches the
+    migrations in the database. Prints a warning if they don't match.
+    """
+    from django.db import connections, DEFAULT_DB_ALIAS
+    from django.db.migrations.executor import MigrationExecutor
+
+    errors = []
+    plan = None
+    if settings.DATABASES:
+        executor = MigrationExecutor(connections[DEFAULT_DB_ALIAS])
+        plan = executor.migration_plan(executor.loader.graph.leaf_nodes())
+    if plan:
+        errors.append(
+            Warning(
+                "You have unapplied migrations; "
+                "your app may not work properly until they are applied.",
+                hint="Run 'python manage.py migrate' to apply them.",
+            )
+        )
+    return errors
diff --git a/django/core/management/commands/runserver.py b/django/core/management/commands/runserver.py
index e85aa88c3e..8320614409 100644
--- a/django/core/management/commands/runserver.py
+++ b/django/core/management/commands/runserver.py
@@ -10,8 +10,6 @@ import socket
 
 from django.core.management.base import BaseCommand, CommandError
 from django.core.servers.basehttp import run, get_internal_wsgi_application
-from django.db import connections, DEFAULT_DB_ALIAS
-from django.db.migrations.executor import MigrationExecutor
 from django.utils import autoreload
 from django.utils import six
 
@@ -101,7 +99,6 @@ class Command(BaseCommand):
 
         self.stdout.write("Performing system checks...\n\n")
         self.validate(display_num_errors=True)
-        self.check_migrations()
         now = datetime.now().strftime('%B %d, %Y - %X')
         if six.PY2:
             now = now.decode('utf-8')
@@ -146,16 +143,5 @@ class Command(BaseCommand):
                 self.stdout.write(shutdown_message)
             sys.exit(0)
 
-    def check_migrations(self):
-        """
-        Checks to see if the set of migrations on disk matches the
-        migrations in the database. Prints a warning if they don't match.
-        """
-        executor = MigrationExecutor(connections[DEFAULT_DB_ALIAS])
-        plan = executor.migration_plan(executor.loader.graph.leaf_nodes())
-        if plan:
-            self.stdout.write(self.style.NOTICE("\nYou have unapplied migrations; your app may not work properly until they are applied."))
-            self.stdout.write(self.style.NOTICE("Run 'python manage.py migrate' to apply them.\n"))
-
 # Kept for backward compatibility
 BaseRunserverCommand = Command

From a3e0d7753d8a3cec7efcc69b9af8160bdf17947b Mon Sep 17 00:00:00 2001
From: mlavin <markdlavin@gmail.com>
Date: Sat, 8 Feb 2014 09:05:27 -0500
Subject: [PATCH 2/2] Adding tests for check_migrations.

---
 tests/migrations/test_checks.py | 43 +++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)
 create mode 100644 tests/migrations/test_checks.py

diff --git a/tests/migrations/test_checks.py b/tests/migrations/test_checks.py
new file mode 100644
index 0000000000..9ba5bb8e25
--- /dev/null
+++ b/tests/migrations/test_checks.py
@@ -0,0 +1,43 @@
+# encoding: utf8
+from django.core import checks
+from django.core.checks.migrations import check_migrations
+from django.test import TestCase, override_settings
+
+from .test_base import MigrationTestBase
+
+
+class CheckMigrationTests(MigrationTestBase):
+    """
+    Test checks for unapplied migrations.
+    """
+
+    @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations"})
+    def test_unapplied(self):
+        """
+        check_migrations should return a warning when there are unapplied migrations.
+        """
+        expected = [
+            checks.Warning(
+                "You have unapplied migrations; "
+                "your app may not work properly until they are applied.",
+                hint="Run 'python manage.py migrate' to apply them.",
+            )
+        ]
+        errors = check_migrations()
+        self.assertEqual(errors, expected)
+
+    @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations"}, DATABASES={})
+    def test_no_databases(self):
+        """
+        Migration checks should not consider unapplied migrations if there is
+        no database configured.
+        """
+        errors = check_migrations()
+        self.assertEqual(errors, [])
+
+    def test_no_unapplied(self):
+        """
+        No warning should be issued if all migrations have been applied.
+        """
+        errors = check_migrations()
+        self.assertEqual(errors, [])