kopia lustrzana https://github.com/wagtail/wagtail
Add a test that checks for missing migrations
If there are any outstanding model changes that have no migrations, the tests will fail. Migrations *must* be up-to-date before any code changes are accepted, or before a new version is released. If they are not, it causes havoc for all users. The bulk of the test code is taken from the Django 1.7 `makemigrations` command, and the South `schemamigration` command.pull/809/head
rodzic
c22e2e2914
commit
4fe5b30005
|
@ -0,0 +1,121 @@
|
|||
"""
|
||||
Check that all changes to Wagtail models have had migrations created. If there
|
||||
are outstanding model changes that need migrations, fail the tests.
|
||||
"""
|
||||
|
||||
from django import VERSION
|
||||
from django.test import TransactionTestCase
|
||||
|
||||
from django.utils.six import iteritems
|
||||
import south.management.commands.schemamigration
|
||||
|
||||
try:
|
||||
from unittest import skipIf, skipUnless
|
||||
except ImportError:
|
||||
from django.utils.unittest import skipIf, skipUnless
|
||||
|
||||
|
||||
class TestForMigrations(TransactionTestCase):
|
||||
|
||||
@skipIf(VERSION < (1, 7), "Migrations introduced in Django 1.7")
|
||||
def test_django_17_migrations(self):
|
||||
|
||||
from django.apps import apps
|
||||
from django.db.migrations.loader import MigrationLoader
|
||||
from django.db.migrations.autodetector import MigrationAutodetector
|
||||
from django.db.migrations.state import ProjectState
|
||||
from django.db.migrations.questioner import MigrationQuestioner
|
||||
app_labels = set(app.label for app in apps.get_app_configs()
|
||||
if app.name.startswith('wagtail.'))
|
||||
for app_label in app_labels:
|
||||
apps.get_app_config(app_label.split('.')[-1])
|
||||
loader = MigrationLoader(None, ignore_no_migrations=True)
|
||||
|
||||
conflicts = dict(
|
||||
(app_label, conflict)
|
||||
for app_label, conflict in iteritems(loader.detect_conflicts())
|
||||
if app_label in app_labels
|
||||
)
|
||||
|
||||
if conflicts:
|
||||
name_str = "; ".join("%s in %s" % (", ".join(names), app)
|
||||
for app, names in conflicts.items())
|
||||
self.fail("Conflicting migrations detected (%s)." % name_str)
|
||||
|
||||
autodetector = MigrationAutodetector(
|
||||
loader.project_state(),
|
||||
ProjectState.from_apps(apps),
|
||||
MigrationQuestioner(specified_apps=app_labels, dry_run=True),
|
||||
)
|
||||
|
||||
changes = autodetector.changes(
|
||||
graph=loader.graph,
|
||||
trim_to_apps=app_labels or None,
|
||||
convert_apps=app_labels or None,
|
||||
)
|
||||
|
||||
if changes:
|
||||
apps = ', '.join(apps.get_app_config(label).name
|
||||
for label in changes.keys())
|
||||
self.fail('Model changes with no migrations detected in apps: %s' % (apps,))
|
||||
|
||||
@skipUnless(VERSION < (1, 7), "South migrations used for Django < 1.7")
|
||||
def test_south_migrations(self):
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
|
||||
from south.migration import Migrations, migrate_app
|
||||
from south.models import MigrationHistory
|
||||
from south.exceptions import NoMigrations
|
||||
from south.creator import changes, actions, freezer
|
||||
from south.management.commands.datamigration import Command as DataCommand
|
||||
|
||||
apps = [app for app in settings.INSTALLED_APPS
|
||||
if app.startswith('wagtail.')]
|
||||
failing_apps = []
|
||||
for app_name in apps:
|
||||
app = app_name.split('.')[-1]
|
||||
try:
|
||||
models.get_app(app)
|
||||
except ImproperlyConfigured:
|
||||
# This module fails to load, probably because it has no
|
||||
# models.py. Ignore it and move on
|
||||
continue
|
||||
|
||||
try:
|
||||
migrations = Migrations(app, force_creation=False, verbose_creation=False)
|
||||
last_migration = migrations[-1]
|
||||
except (NoMigrations, IndexError):
|
||||
# No migrations for this app, probably doesnt have models
|
||||
continue
|
||||
|
||||
if migrations.app_label() not in getattr(last_migration.migration_class(), "complete_apps", []):
|
||||
self.fail("Automatic migrations checking failed, since the previous migration does not have this whole app frozen.\nEither make migrations using '--freeze %s' or set 'SOUTH_AUTO_FREEZE_APP = True' in your settings.py." % migrations.app_label())
|
||||
|
||||
# Alright, construct two model dicts to run the differ on.
|
||||
old_defs = dict(
|
||||
(k, v) for k, v in last_migration.migration_class().models.items()
|
||||
if k.split(".")[0] == migrations.app_label()
|
||||
)
|
||||
new_defs = dict(
|
||||
(k, v) for k, v in freezer.freeze_apps([migrations.app_label()]).items()
|
||||
if k.split(".")[0] == migrations.app_label()
|
||||
)
|
||||
change_source = changes.AutoChanges(
|
||||
migrations = migrations,
|
||||
old_defs = old_defs,
|
||||
old_orm = last_migration.orm(),
|
||||
new_defs = new_defs,
|
||||
)
|
||||
|
||||
name = 'test'
|
||||
|
||||
# Get the actions, and then insert them into the actions lists
|
||||
if list(change_source.get_changes()):
|
||||
failing_apps.append(app_name)
|
||||
|
||||
if failing_apps:
|
||||
self.fail('Model changes with no South migration detected in apps: %s' % (
|
||||
', '.join(failing_apps)))
|
Ładowanie…
Reference in New Issue