From 6f453cd2981525b33925faaadc7a6e51fa90df5c Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Thu, 10 Feb 2022 20:16:33 +0000 Subject: [PATCH] Fixed #33509 -- Added "(no-op)" to sqlmigrate output for operations without SQL statement. --- django/db/migrations/migration.py | 22 +++++----- tests/migrations/test_commands.py | 42 ++++++++++++++++++- .../test_migrations_noop/0001_initial.py | 10 +++++ .../test_migrations_noop/__init__.py | 0 4 files changed, 63 insertions(+), 11 deletions(-) create mode 100644 tests/migrations/test_migrations_noop/0001_initial.py create mode 100644 tests/migrations/test_migrations_noop/__init__.py diff --git a/django/db/migrations/migration.py b/django/db/migrations/migration.py index ccbd2f72e4..ea9d02a94a 100644 --- a/django/db/migrations/migration.py +++ b/django/db/migrations/migration.py @@ -103,15 +103,14 @@ class Migration: # there instead if collect_sql: schema_editor.collected_sql.append("--") - if not operation.reduces_to_sql: - schema_editor.collected_sql.append( - "-- MIGRATION NOW PERFORMS OPERATION THAT CANNOT BE WRITTEN AS " - "SQL:" - ) schema_editor.collected_sql.append("-- %s" % operation.describe()) schema_editor.collected_sql.append("--") if not operation.reduces_to_sql: + schema_editor.collected_sql.append( + "-- THIS OPERATION CANNOT BE WRITTEN AS SQL" + ) continue + collected_sql_before = len(schema_editor.collected_sql) # Save the state before the operation has run old_state = project_state.clone() operation.state_forwards(self.app_label, project_state) @@ -131,6 +130,8 @@ class Migration: operation.database_forwards( self.app_label, schema_editor, old_state, project_state ) + if collect_sql and collected_sql_before == len(schema_editor.collected_sql): + schema_editor.collected_sql.append("-- (no-op)") return project_state def unapply(self, project_state, schema_editor, collect_sql=False): @@ -167,15 +168,14 @@ class Migration: for operation, to_state, from_state in to_run: if collect_sql: schema_editor.collected_sql.append("--") - if not operation.reduces_to_sql: - schema_editor.collected_sql.append( - "-- MIGRATION NOW PERFORMS OPERATION THAT CANNOT BE WRITTEN AS " - "SQL:" - ) schema_editor.collected_sql.append("-- %s" % operation.describe()) schema_editor.collected_sql.append("--") if not operation.reduces_to_sql: + schema_editor.collected_sql.append( + "-- THIS OPERATION CANNOT BE WRITTEN AS SQL" + ) continue + collected_sql_before = len(schema_editor.collected_sql) atomic_operation = operation.atomic or ( self.atomic and operation.atomic is not False ) @@ -191,6 +191,8 @@ class Migration: operation.database_backwards( self.app_label, schema_editor, from_state, to_state ) + if collect_sql and collected_sql_before == len(schema_editor.collected_sql): + schema_editor.collected_sql.append("-- (no-op)") return project_state def suggest_name(self): diff --git a/tests/migrations/test_commands.py b/tests/migrations/test_commands.py index 7ea8267247..a3e1efc924 100644 --- a/tests/migrations/test_commands.py +++ b/tests/migrations/test_commands.py @@ -1021,11 +1021,51 @@ class MigrateTests(MigrationTestBase): @override_settings( MIGRATION_MODULES={"migrations": "migrations.test_migrations_no_operations"} ) - def test_migrations_no_operations(self): + def test_sqlmigrate_no_operations(self): err = io.StringIO() call_command("sqlmigrate", "migrations", "0001_initial", stderr=err) self.assertEqual(err.getvalue(), "No operations found.\n") + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_noop"} + ) + def test_sqlmigrate_noop(self): + out = io.StringIO() + call_command("sqlmigrate", "migrations", "0001", stdout=out) + lines = out.getvalue().splitlines() + + if connection.features.can_rollback_ddl: + lines = lines[1:-1] + self.assertEqual( + lines, + [ + "--", + "-- Raw SQL operation", + "--", + "-- (no-op)", + ], + ) + + @override_settings( + MIGRATION_MODULES={"migrations": "migrations.test_migrations_manual_porting"} + ) + def test_sqlmigrate_unrepresentable(self): + out = io.StringIO() + call_command("sqlmigrate", "migrations", "0002", stdout=out) + lines = out.getvalue().splitlines() + + if connection.features.can_rollback_ddl: + lines = lines[1:-1] + self.assertEqual( + lines, + [ + "--", + "-- Raw Python operation", + "--", + "-- THIS OPERATION CANNOT BE WRITTEN AS SQL", + ], + ) + @override_settings( INSTALLED_APPS=[ "migrations.migrations_test_apps.migrated_app", diff --git a/tests/migrations/test_migrations_noop/0001_initial.py b/tests/migrations/test_migrations_noop/0001_initial.py new file mode 100644 index 0000000000..f06ff893ad --- /dev/null +++ b/tests/migrations/test_migrations_noop/0001_initial.py @@ -0,0 +1,10 @@ +from django.db import migrations + + +class Migration(migrations.Migration): + + initial = True + + operations = [ + migrations.RunSQL(sql="", reverse_sql=""), + ] diff --git a/tests/migrations/test_migrations_noop/__init__.py b/tests/migrations/test_migrations_noop/__init__.py new file mode 100644 index 0000000000..e69de29bb2