diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml
index e8a9942c8d..8fa5d73a17 100644
--- a/.github/workflows/testing.yml
+++ b/.github/workflows/testing.yml
@@ -35,6 +35,38 @@ jobs:
coverage report -m
bash <(curl -s https://codecov.io/bash)
+ test_check_unapplied_migrations_middleware:
+ name: middleware for unapplied migrations
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ python-version: [3.7]
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v1
+ with:
+ python-version: ${{ matrix.python-version }}
+
+ - name: Install Python dependencies
+ run: |
+ sudo apt-get install libkrb5-dev gettext
+ pip install -r requirements/devel.txt
+ pushd tcms/ && npm install && popd
+
+ - name: Run test
+ run: |
+ export LANG=en-us
+ export TEST_CHECK_UNAPPLIED_MIGRATIONS_MIDDLEWARE=1
+ coverage run --source='.' ./manage.py test -v2 --noinput --settings=tcms.settings.test tcms.core.tests.test_middleware.TestCheckUnappliedMigrationsMiddleware
+
+ - name: Send coverage to codecov.io
+ run: |
+ coverage report -m
+ bash <(curl -s https://codecov.io/bash)
+
without_internal_bugtracker:
name: without internal bugtracker
runs-on: ubuntu-latest
diff --git a/tcms/core/middleware.py b/tcms/core/middleware.py
index 2464b96d91..72d238f25d 100644
--- a/tcms/core/middleware.py
+++ b/tcms/core/middleware.py
@@ -7,6 +7,8 @@
from django.utils.deprecation import MiddlewareMixin
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _
+from django.db import DEFAULT_DB_ALIAS, connections
+from django.db.migrations.executor import MigrationExecutor
class CsrfDisableMiddleware(MiddlewareMixin):
@@ -32,3 +34,23 @@ def process_request(self, request):
}
)
)
+
+
+class CheckUnappliedMigrationsMiddleware(MiddlewareMixin):
+ def process_request(self, request):
+ doc_url = """https://kiwitcms.readthedocs.io/en/latest/\
+installing_docker.html#initial-configuration-of-running-container"""
+ executor = MigrationExecutor(connections[DEFAULT_DB_ALIAS])
+ plan = executor.migration_plan(executor.loader.graph.leaf_nodes())
+ if plan:
+ messages.add_message(
+ request,
+ messages.ERROR,
+ mark_safe(
+ _('You have %(unapplied_migration_count)s unapplied migration(s). '
+ 'See documentation') % {
+ "unapplied_migration_count": len(plan),
+ "doc_url": doc_url,
+ }
+ )
+ )
diff --git a/tcms/core/tests/test_middleware.py b/tcms/core/tests/test_middleware.py
new file mode 100644
index 0000000000..f52e62d19a
--- /dev/null
+++ b/tcms/core/tests/test_middleware.py
@@ -0,0 +1,26 @@
+import os
+import unittest
+from django import test
+from django.conf import settings
+from django.apps import apps
+from django.contrib.messages import get_messages
+
+
+@unittest.skipUnless(
+ os.getenv('TEST_CHECK_UNAPPLIED_MIGRATIONS_MIDDLEWARE'),
+ 'CheckUnappliedMigrationsMiddleware testing not enabled')
+class TestCheckUnappliedMigrationsMiddleware(test.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ super().setUpClass()
+ settings.INSTALLED_APPS.append("tcms.core.tests.test_migrations_app")
+ apps.set_installed_apps(settings.INSTALLED_APPS)
+
+ @test.override_settings(MIGRATION_MODULES={
+ "migrations": "tcms.core.tests.test_migrations_app.migrations"})
+ def test_unapplied_migrations(self):
+ unapplied_migration_message = """You have 1 unapplied migration(s).\
+ See documentation"""
+ response = self.client.get('/', follow=True)
+ self.assertContains(response, unapplied_migration_message)
diff --git a/tcms/core/tests/test_migrations_app/__init__.py b/tcms/core/tests/test_migrations_app/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tcms/core/tests/test_migrations_app/migrations/0001_initial.py b/tcms/core/tests/test_migrations_app/migrations/0001_initial.py
new file mode 100644
index 0000000000..da8597c1bd
--- /dev/null
+++ b/tcms/core/tests/test_migrations_app/migrations/0001_initial.py
@@ -0,0 +1,15 @@
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ operations = [
+
+ migrations.CreateModel(
+ "TestPerson",
+ [
+ ("id", models.AutoField(primary_key=True)),
+ ("name", models.CharField(max_length=10)),
+ ],
+ ),
+ ]
diff --git a/tcms/core/tests/test_migrations_app/migrations/__init__.py b/tcms/core/tests/test_migrations_app/migrations/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tcms/core/tests/test_migrations_app/models.py b/tcms/core/tests/test_migrations_app/models.py
new file mode 100644
index 0000000000..ba7c29523d
--- /dev/null
+++ b/tcms/core/tests/test_migrations_app/models.py
@@ -0,0 +1,5 @@
+from django.db import models
+
+
+class TestPerson(models.Model):
+ name = models.CharField(max_length=10)
diff --git a/tcms/settings/common.py b/tcms/settings/common.py
index c9933ccc45..30b7179c2c 100644
--- a/tcms/settings/common.py
+++ b/tcms/settings/common.py
@@ -130,6 +130,7 @@
'global_login_required.GlobalLoginRequiredMiddleware',
'simple_history.middleware.HistoryRequestMiddleware',
'tcms.core.middleware.CheckSettingsMiddleware',
+ 'tcms.core.middleware.CheckUnappliedMigrationsMiddleware',
]