From 18027e4798ba1eb8d59eaeff5f04eac39dad8afc Mon Sep 17 00:00:00 2001 From: Adam Alton <270255+adamalton@users.noreply.github.com> Date: Tue, 2 Apr 2024 15:09:06 +0100 Subject: [PATCH 1/7] Fix stripping of ".py" from filenames Previous this would strip all/any trailing ./p/y characters from the filename --- massmigration/loader.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/massmigration/loader.py b/massmigration/loader.py index fdd39ca..bfd0535 100644 --- a/massmigration/loader.py +++ b/massmigration/loader.py @@ -39,8 +39,9 @@ def load(self): if os.path.isdir(migrations_path): items = os.listdir(migrations_path) for item in sorted(items): - if is_valid_migration_id(item.rstrip(".py")): - migration = load_migration(app_config, item) + migration_id = migration_id_from_filename(item) + if migration_id: + migration = load_migration(app_config, migration_id) self._all.append(migration) self._by_key[migration.key] = migration self._loaded = True @@ -49,7 +50,16 @@ def load(self): store = MigrationsStore() +def migration_id_from_filename(filename): + if filename.endswith(".py"): + migration_id = re.sub(r"\.py$", "", filename) + if is_valid_migration_id(migration_id): + return migration_id + return None + + def is_valid_migration_name(name): + """ Is the given name (supplied without leading number) a valid name for a migration? """ return bool(re.match(r"^[a-z0-9_]+$", name)) @@ -61,9 +71,9 @@ def load_migration(app_config, filename): """ Return in instance of the migration class from the given filename from the given app_config. """ module_str = app_config.name - migration_name = filename.rstrip(".py") - class_path_str = f"{module_str}.{MIGRATIONS_FOLDER}.{migration_name}.Migration" + migration_id = migration_id_from_filename(filename) + class_path_str = f"{module_str}.{MIGRATIONS_FOLDER}.{migration_id}.Migration" cls = import_string(class_path_str) app_label = app_config.label - instance = cls(app_label, migration_name) + instance = cls(app_label, migration_id) return instance From 9ca796f7af02df787cfb7f26f44bfb53edb984c7 Mon Sep 17 00:00:00 2001 From: Adam Alton <270255+adamalton@users.noreply.github.com> Date: Tue, 2 Apr 2024 15:09:24 +0100 Subject: [PATCH 2/7] Add a github workflow file for running tests --- .github/workflows/test.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..ede61ae --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,13 @@ +name: Test +on: [push] +env: + DJANGO_SETTINGS_MODULE: "testing.test_settings" +jobs: + Test: + runs-on: python:3.12 + steps: + - name: Run tests + run: >- + pip install -e . + cp testing/test_settings.py ./ + django-admin test massmigration From 8ed6b0ac273e04edbb6131f424577c38b859f637 Mon Sep 17 00:00:00 2001 From: Adam Alton <270255+adamalton@users.noreply.github.com> Date: Tue, 2 Apr 2024 15:29:32 +0100 Subject: [PATCH 3/7] Fiddle with test workflow config --- .github/workflows/test.yml | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ede61ae..2b2d43c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,11 +3,19 @@ on: [push] env: DJANGO_SETTINGS_MODULE: "testing.test_settings" jobs: - Test: - runs-on: python:3.12 + test: + runs-on: ubuntu-latest steps: - - name: Run tests - run: >- - pip install -e . - cp testing/test_settings.py ./ - django-admin test massmigration + - uses: actions/checkout@v4 + - name: Set up Python + # This is the version of the action for setting up Python, not the Python version. + uses: actions/setup-python@v5 + with: + # Semantic version range syntax or exact version of a Python version + python-version: '3.11' + - name: Install + run: pip install -e . + - name: Run tests + run: >- + cp testing/test_settings.py ./ + django-admin test massmigration From be2e361fdd877ac1f706f78312f8f7b5782de4bd Mon Sep 17 00:00:00 2001 From: Adam Alton <270255+adamalton@users.noreply.github.com> Date: Tue, 2 Apr 2024 15:39:41 +0100 Subject: [PATCH 4/7] setup.py tweaks * Make dependency on Djangae optional * Make the version number valid when placeholder isn't replaced --- setup.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/setup.py b/setup.py index c1f550f..e493475 100644 --- a/setup.py +++ b/setup.py @@ -8,13 +8,16 @@ URL = "https://github.com/adamalton/django-mass-migration" AUTHOR = "Adam Alton" -# TODO: possibly make the dependency on djangae optional -EXTRAS = {} +# This gets replaced by the publish.yml workflow +VERSION = "{{VERSION_PLACEHOLDER}}" +# If it's not replaced (e.g. when installing for tests) then we still need a valid version number +if "PLACEHOLDER" in VERSION: + VERSION = "99.9.9" setup( name=NAME, - version="{{VERSION_PLACEHOLDER}}", + version=f"{VERSION}", packages=PACKAGES, author=AUTHOR, description=DESCRIPTION, @@ -36,9 +39,11 @@ include_package_data=True, install_requires=[ "django>=3.2,<5.0", - "djangae>=1.1.0", - "django-gcloud-connectors>=0.3.6", ], - extras_require=EXTRAS, - # tests_require=EXTRAS["test"], + extras_require={ + "djangae": [ + "djangae>=1.1.0", + "django-gcloud-connectors>=0.3.6", + ], + }, ) From 09bc55950f8d827f59f880143829b8987df7ac92 Mon Sep 17 00:00:00 2001 From: Adam Alton <270255+adamalton@users.noreply.github.com> Date: Tue, 2 Apr 2024 15:42:28 +0100 Subject: [PATCH 5/7] Fixes for test workflow --- .github/workflows/test.yml | 1 - testing/__init__.py | 0 2 files changed, 1 deletion(-) create mode 100644 testing/__init__.py diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2b2d43c..fd6685e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,5 +17,4 @@ jobs: run: pip install -e . - name: Run tests run: >- - cp testing/test_settings.py ./ django-admin test massmigration diff --git a/testing/__init__.py b/testing/__init__.py new file mode 100644 index 0000000..e69de29 From 8279a96a92264ba3294312783a644205e38dd06a Mon Sep 17 00:00:00 2001 From: Adam Alton <270255+adamalton@users.noreply.github.com> Date: Tue, 2 Apr 2024 15:44:37 +0100 Subject: [PATCH 6/7] Fiddle with setup.py some more --- setup.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/setup.py b/setup.py index e493475..bfcb422 100644 --- a/setup.py +++ b/setup.py @@ -39,11 +39,13 @@ include_package_data=True, install_requires=[ "django>=3.2,<5.0", + "djangae>=1.1.0", + "django-gcloud-connectors>=0.3.6", ], - extras_require={ - "djangae": [ - "djangae>=1.1.0", - "django-gcloud-connectors>=0.3.6", - ], - }, + # TODO: make Djangae dependencies optional + # extras_require={ + # "djangae": [ + + # ], + # }, ) From f0f84bb4209f7860a14c893754daddd12f80b87c Mon Sep 17 00:00:00 2001 From: Adam Alton <270255+adamalton@users.noreply.github.com> Date: Tue, 2 Apr 2024 15:54:03 +0100 Subject: [PATCH 7/7] Add more tests --- massmigration/tests/test_loader.py | 39 ++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 massmigration/tests/test_loader.py diff --git a/massmigration/tests/test_loader.py b/massmigration/tests/test_loader.py new file mode 100644 index 0000000..899be77 --- /dev/null +++ b/massmigration/tests/test_loader.py @@ -0,0 +1,39 @@ +# Third party +from django.test import TestCase + +# Mass Migration +from massmigration.loader import ( + is_valid_migration_id, + is_valid_migration_name, + migration_id_from_filename, +) + +class LoaderTestCase(TestCase): + """ Tests for the 'loader.py' module. """ + + def test_is_valid_migration_id(self): + """ Test the `is_valid_migration_id` function. """ + for migration_id, expect_valid in [ + ("0023_valid_name", True), + ("0023_dots_not_allowed.html", False), + ("no_leading_zeros", False), + ]: + self.assertEqual(is_valid_migration_id(migration_id), expect_valid) + + def test_is_valid_migration_name(self): + """ Test the `is_valid_migration_name` function. """ + for name, expect_valid in [ + ("valid_name_here", True), + ("hyphens-not-allowed", False), + ("dots.not.allowed", False), + ]: + self.assertEqual(is_valid_migration_name(name), expect_valid) + + def test_migration_id_from_filename(self): + """ Test the `migration_id_from_filename` function. """ + for filename, expected_id in [ + ("0001_my_migration.py", "0001_my_migration"), + ("0001_my_migration.html", None), + ("__init__.py", None), + ]: + self.assertEqual(migration_id_from_filename(filename), expected_id)