django-migration-zero 2.1.0__tar.gz → 2.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/.ambient-package-update/metadata.py +6 -3
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/.github/workflows/ci.yml +10 -9
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/.pre-commit-config.yaml +5 -5
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/CHANGES.md +18 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/PKG-INFO +7 -6
- django_migration_zero-2.3.2/SECURITY.md +18 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/django_migration_zero/__init__.py +1 -1
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/django_migration_zero/helpers/file_system.py +2 -3
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/django_migration_zero/managers.py +7 -16
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/django_migration_zero/services/deployment.py +4 -3
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/docs/conf.py +0 -2
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/pyproject.toml +25 -17
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/tests/services/test_deployment.py +56 -1
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/tests/test_managers.py +2 -1
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/.ambient-package-update/templates/snippets/content.tpl +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/.ambient-package-update/templates/snippets/installation.tpl +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/.ambient-package-update/templates/snippets/tagline.tpl +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/.coveragerc +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/.editorconfig +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/.gitignore +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/.readthedocs.yaml +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/LICENSE.md +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/MANIFEST.in +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/README.md +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/django_migration_zero/admin.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/django_migration_zero/apps.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/django_migration_zero/exceptions.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/django_migration_zero/helpers/__init__.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/django_migration_zero/helpers/logger.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/django_migration_zero/locale/de/LC_MESSAGES/django.mo +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/django_migration_zero/locale/de/LC_MESSAGES/django.po +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/django_migration_zero/management/__init__.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/django_migration_zero/management/commands/__init__.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/django_migration_zero/management/commands/handle_migration_zero_reset.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/django_migration_zero/management/commands/reset_local_migration_files.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/django_migration_zero/migrations/0001_initial.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/django_migration_zero/migrations/__init__.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/django_migration_zero/models.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/django_migration_zero/services/__init__.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/django_migration_zero/services/local.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/docs/Makefile +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/docs/features/01_introduction.md +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/docs/features/02_configuration.md +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/docs/features/03_workflow.md +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/docs/features/04_common_issues_and_solutions.md +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/docs/features/05_architecture.md +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/docs/features/06_management_commands.md +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/docs/features/07_changelog.rst +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/docs/index.rst +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/docs/make.bat +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/manage.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/scripts/unix/install_requirements.sh +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/scripts/unix/publish_to_pypi.sh +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/scripts/windows/install_requirements.ps1 +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/scripts/windows/publish_to_pypi.ps1 +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/settings.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/setup.cfg +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/testapp/__init__.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/testapp/nested_app/__init__.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/testapp/nested_app/migrations/__init__.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/testapp/urls.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/tests/__init__.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/tests/helpers/__init__.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/tests/helpers/test_file_system.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/tests/helpers/test_logger.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/tests/management/__init__.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/tests/management/commands/__init__.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/tests/management/commands/test_handle_migration_zero_reset.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/tests/management/commands/test_reset_local_migration_files.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/tests/services/__init__.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/tests/services/test_local.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/tests/test_admin.py +0 -0
- {django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/tests/test_models.py +0 -0
{django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/.ambient-package-update/metadata.py
RENAMED
|
@@ -8,10 +8,11 @@ from ambient_package_update.metadata.constants import (
|
|
|
8
8
|
from ambient_package_update.metadata.maintainer import PackageMaintainer
|
|
9
9
|
from ambient_package_update.metadata.package import PackageMetadata
|
|
10
10
|
from ambient_package_update.metadata.readme import ReadmeContent
|
|
11
|
+
from ambient_package_update.metadata.ruff_ignored_inspection import RuffIgnoredInspection
|
|
11
12
|
|
|
12
13
|
METADATA = PackageMetadata(
|
|
13
14
|
package_name="django_migration_zero",
|
|
14
|
-
|
|
15
|
+
github_package_group="ambient-innovation",
|
|
15
16
|
authors=[
|
|
16
17
|
PackageAuthor(
|
|
17
18
|
name="Ambient Digital",
|
|
@@ -26,12 +27,14 @@ METADATA = PackageMetadata(
|
|
|
26
27
|
has_migrations=True,
|
|
27
28
|
readme_content=ReadmeContent(uses_internationalisation=True),
|
|
28
29
|
dependencies=[
|
|
29
|
-
"Django>=
|
|
30
|
+
f"Django>={SUPPORTED_DJANGO_VERSIONS[0]}",
|
|
30
31
|
],
|
|
31
32
|
supported_django_versions=SUPPORTED_DJANGO_VERSIONS,
|
|
32
33
|
supported_python_versions=SUPPORTED_PYTHON_VERSIONS,
|
|
33
34
|
optional_dependencies={
|
|
34
35
|
"dev": [*DEV_DEPENDENCIES, "unittest-parametrize~=1.3"],
|
|
35
36
|
},
|
|
36
|
-
ruff_ignore_list=[
|
|
37
|
+
ruff_ignore_list=[
|
|
38
|
+
RuffIgnoredInspection(key="TRY003", comment="Avoid specifying long messages outside the exception class"),
|
|
39
|
+
],
|
|
37
40
|
)
|
|
@@ -42,14 +42,14 @@ jobs:
|
|
|
42
42
|
runs-on: ubuntu-22.04
|
|
43
43
|
strategy:
|
|
44
44
|
matrix:
|
|
45
|
-
python-version: ['3.
|
|
46
|
-
django-version: ['42', '50', ]
|
|
45
|
+
python-version: ['3.9', '3.10', '3.11', '3.12', ]
|
|
46
|
+
django-version: ['42', '50', '51', ]
|
|
47
47
|
|
|
48
48
|
exclude:
|
|
49
|
-
- python-version: '3.8'
|
|
50
|
-
django-version: 50
|
|
51
49
|
- python-version: '3.9'
|
|
52
50
|
django-version: 50
|
|
51
|
+
- python-version: '3.9'
|
|
52
|
+
django-version: 51
|
|
53
53
|
|
|
54
54
|
steps:
|
|
55
55
|
- uses: actions/checkout@v4
|
|
@@ -64,9 +64,9 @@ jobs:
|
|
|
64
64
|
TOXENV: django${{ matrix.django-version }}
|
|
65
65
|
run: tox
|
|
66
66
|
- name: Upload coverage data
|
|
67
|
-
uses: actions/upload-artifact@
|
|
67
|
+
uses: actions/upload-artifact@v4
|
|
68
68
|
with:
|
|
69
|
-
name: coverage-data
|
|
69
|
+
name: coverage-data-${{ matrix.python-version }}-${{ matrix.django-version }}
|
|
70
70
|
path: '.coverage*'
|
|
71
71
|
|
|
72
72
|
coverage:
|
|
@@ -84,11 +84,12 @@ jobs:
|
|
|
84
84
|
run: python -m pip install --upgrade coverage[toml]
|
|
85
85
|
|
|
86
86
|
- name: Download data
|
|
87
|
-
uses: actions/download-artifact@
|
|
87
|
+
uses: actions/download-artifact@v4
|
|
88
88
|
with:
|
|
89
|
-
|
|
89
|
+
pattern: coverage-data*
|
|
90
|
+
merge-multiple: true
|
|
90
91
|
|
|
91
|
-
- name: Combine coverage and fail if it's <100%
|
|
92
|
+
- name: Combine coverage and fail if it's <100.0%
|
|
92
93
|
run: |
|
|
93
94
|
python -m coverage html --skip-covered --skip-empty
|
|
94
95
|
python -m coverage report --fail-under=100.0
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
repos:
|
|
5
5
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
6
|
-
rev: v0.4
|
|
6
|
+
rev: v0.6.4
|
|
7
7
|
hooks:
|
|
8
8
|
# Run the Ruff linter.
|
|
9
9
|
- id: ruff
|
|
@@ -12,7 +12,7 @@ repos:
|
|
|
12
12
|
- id: ruff-format
|
|
13
13
|
|
|
14
14
|
- repo: https://github.com/adamchainz/blacken-docs
|
|
15
|
-
rev: 1.
|
|
15
|
+
rev: 1.18.0
|
|
16
16
|
hooks:
|
|
17
17
|
- id: blacken-docs
|
|
18
18
|
additional_dependencies:
|
|
@@ -20,14 +20,14 @@ repos:
|
|
|
20
20
|
files: '(?:README\.md|docs\/.*\.(?:md|rst))'
|
|
21
21
|
|
|
22
22
|
- repo: https://github.com/asottile/pyupgrade
|
|
23
|
-
rev: v3.
|
|
23
|
+
rev: v3.17.0
|
|
24
24
|
hooks:
|
|
25
25
|
- id: pyupgrade
|
|
26
|
-
args: [ --
|
|
26
|
+
args: [ --py39-plus ]
|
|
27
27
|
stages: [ push ]
|
|
28
28
|
|
|
29
29
|
- repo: https://github.com/adamchainz/django-upgrade
|
|
30
|
-
rev: 1.
|
|
30
|
+
rev: 1.21.0
|
|
31
31
|
hooks:
|
|
32
32
|
- id: django-upgrade
|
|
33
33
|
args: [--target-version, "4.2"]
|
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
* *2.3.2* (2024-09-11)
|
|
4
|
+
* Fixed package name
|
|
5
|
+
|
|
6
|
+
* *2.3.1* (2024-08-12)
|
|
7
|
+
* Fixed test matrix
|
|
8
|
+
|
|
9
|
+
* *2.3.0* (2024-08-12)
|
|
10
|
+
* Added Django 5.1 support
|
|
11
|
+
|
|
12
|
+
* *2.2.0* (2024-07-18)
|
|
13
|
+
* Use ORM to reset `django_migrations` table
|
|
14
|
+
* Lock rows to enable parallel deployments
|
|
15
|
+
* Dropped Python 3.8 support
|
|
16
|
+
* Added multiple ruff linters and updated packages
|
|
17
|
+
* Updated GitHub actions
|
|
18
|
+
* Added SECURITY.md
|
|
19
|
+
* Internal updates via `ambient-package-update`
|
|
20
|
+
|
|
3
21
|
* *2.1.0* (2024-07-09)
|
|
4
22
|
* Discover apps in nested directories
|
|
5
23
|
* Use `BASE_DIR` instead of `MIGRATION_ZERO_APPS_DIR`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: django-migration-zero
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.2
|
|
4
4
|
Summary: Holistic implementation of "migration zero" pattern for Django covering local changes and in-production database adjustments.
|
|
5
5
|
Author-email: Ambient Digital <hello@ambient.digital>
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -9,32 +9,33 @@ Classifier: Environment :: Web Environment
|
|
|
9
9
|
Classifier: Framework :: Django
|
|
10
10
|
Classifier: Framework :: Django :: 4.2
|
|
11
11
|
Classifier: Framework :: Django :: 5.0
|
|
12
|
+
Classifier: Framework :: Django :: 5.1
|
|
12
13
|
Classifier: Intended Audience :: Developers
|
|
13
14
|
Classifier: License :: OSI Approved :: MIT License
|
|
14
15
|
Classifier: Natural Language :: English
|
|
15
16
|
Classifier: Operating System :: OS Independent
|
|
16
17
|
Classifier: Programming Language :: Python
|
|
17
18
|
Classifier: Programming Language :: Python :: 3
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.9
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.10
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.11
|
|
22
22
|
Classifier: Programming Language :: Python :: 3.12
|
|
23
23
|
Classifier: Topic :: Utilities
|
|
24
|
-
Requires-Dist: Django>=
|
|
24
|
+
Requires-Dist: Django>=4.2
|
|
25
25
|
Requires-Dist: typer~=0.9 ; extra == "dev"
|
|
26
26
|
Requires-Dist: freezegun~=1.3 ; extra == "dev"
|
|
27
27
|
Requires-Dist: pytest-django~=4.7 ; extra == "dev"
|
|
28
28
|
Requires-Dist: pytest-mock~=3.12 ; extra == "dev"
|
|
29
29
|
Requires-Dist: coverage~=7.3 ; extra == "dev"
|
|
30
|
-
Requires-Dist: pre-commit~=3.
|
|
31
|
-
Requires-Dist: ruff~=0.
|
|
30
|
+
Requires-Dist: pre-commit~=3.7 ; extra == "dev"
|
|
31
|
+
Requires-Dist: ruff~=0.4 ; extra == "dev"
|
|
32
32
|
Requires-Dist: sphinx~=7.1 ; extra == "dev"
|
|
33
33
|
Requires-Dist: sphinx-rtd-theme~=2.0 ; extra == "dev"
|
|
34
34
|
Requires-Dist: m2r2==0.3.3.post2 ; extra == "dev"
|
|
35
35
|
Requires-Dist: mistune<2.0.0 ; extra == "dev"
|
|
36
36
|
Requires-Dist: flit~=3.9 ; extra == "dev"
|
|
37
|
-
Requires-Dist:
|
|
37
|
+
Requires-Dist: keyring~=25.2 ; extra == "dev"
|
|
38
|
+
Requires-Dist: ambient-package-update ; extra == "dev"
|
|
38
39
|
Requires-Dist: unittest-parametrize~=1.3 ; extra == "dev"
|
|
39
40
|
Project-URL: Bugtracker, https://github.com/ambient-innovation/django-migration-zero/issues
|
|
40
41
|
Project-URL: Changelog, https://django-migration-zero.readthedocs.io/en/latest/features/changelog.html
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Reporting Security Issues
|
|
2
|
+
|
|
3
|
+
The maintainers of this package take security bugs seriously. We appreciate your efforts to responsibly
|
|
4
|
+
disclose your findings, and will make every effort to acknowledge your contributions.
|
|
5
|
+
|
|
6
|
+
To report a security issue, please use the GitHub Security
|
|
7
|
+
Advisory ["Report a Vulnerability"](https://github.com/ambient-innovation/django-migration-zero/security/advisories/new)
|
|
8
|
+
tab.
|
|
9
|
+
|
|
10
|
+
The maintainers will send a response indicating the next steps in handling your report. After the initial reply to
|
|
11
|
+
your report, the security team will keep you informed of the progress towards a fix and full announcement, and may ask
|
|
12
|
+
for additional information or guidance.
|
|
13
|
+
|
|
14
|
+
Report security bugs in third-party modules to the person or team maintaining the module.
|
|
15
|
+
|
|
16
|
+
## Source
|
|
17
|
+
|
|
18
|
+
This file was inspired by: https://github.com/electron/electron/blob/main/SECURITY.md
|
|
@@ -2,7 +2,6 @@ import os
|
|
|
2
2
|
import re
|
|
3
3
|
from os.path import isdir
|
|
4
4
|
from pathlib import Path
|
|
5
|
-
from typing import List
|
|
6
5
|
|
|
7
6
|
from django.apps import apps
|
|
8
7
|
from django.apps.config import AppConfig
|
|
@@ -20,7 +19,7 @@ def build_migration_directory_path(*, app_path: Path) -> Path:
|
|
|
20
19
|
return app_path / "migrations"
|
|
21
20
|
|
|
22
21
|
|
|
23
|
-
def get_local_django_apps() ->
|
|
22
|
+
def get_local_django_apps() -> list[AppConfig]:
|
|
24
23
|
"""
|
|
25
24
|
Iterate all installed Django apps and detect local ones.
|
|
26
25
|
"""
|
|
@@ -46,7 +45,7 @@ def has_migration_directory(*, app_path: Path) -> bool:
|
|
|
46
45
|
return True if isdir(possible_migration_dir) else False
|
|
47
46
|
|
|
48
47
|
|
|
49
|
-
def get_migration_files(*, app_label: str, app_path: Path, exclude_initials: bool = False) ->
|
|
48
|
+
def get_migration_files(*, app_label: str, app_path: Path, exclude_initials: bool = False) -> list[str]:
|
|
50
49
|
"""
|
|
51
50
|
Returns a list of all migration files detected in the given Django app.
|
|
52
51
|
"""
|
{django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/django_migration_zero/managers.py
RENAMED
|
@@ -1,35 +1,26 @@
|
|
|
1
|
+
from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist
|
|
1
2
|
from django.db import ProgrammingError, models
|
|
2
3
|
|
|
3
4
|
from django_migration_zero.exceptions import MissingMigrationZeroConfigRecordError
|
|
4
5
|
from django_migration_zero.helpers.logger import get_logger
|
|
5
6
|
|
|
6
7
|
|
|
7
|
-
class MigrationZeroConfigurationQuerySet(models.QuerySet):
|
|
8
|
-
pass
|
|
9
|
-
|
|
10
|
-
|
|
11
8
|
class MigrationZeroConfigurationManager(models.Manager):
|
|
12
9
|
def fetch_singleton(self) -> None:
|
|
13
10
|
logger = get_logger()
|
|
14
11
|
try:
|
|
15
|
-
|
|
12
|
+
config_singleton = self.select_for_update().get()
|
|
16
13
|
except ProgrammingError:
|
|
17
14
|
logger.warning(
|
|
18
15
|
"The migration zero table is missing. This might be ok for the first installation of "
|
|
19
16
|
'"django-migration-zero" but if you see this warning after that point, something went sideways.'
|
|
20
17
|
)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if number_records > 1:
|
|
18
|
+
config_singleton = None
|
|
19
|
+
except MultipleObjectsReturned as e:
|
|
24
20
|
raise MissingMigrationZeroConfigRecordError(
|
|
25
21
|
"Too many configuration records detected. There can only be one."
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if not config_singleton:
|
|
30
|
-
raise MissingMigrationZeroConfigRecordError("No configuration record found in the database.")
|
|
22
|
+
) from e
|
|
23
|
+
except ObjectDoesNotExist as e:
|
|
24
|
+
raise MissingMigrationZeroConfigRecordError("No configuration record found in the database.") from e
|
|
31
25
|
|
|
32
26
|
return config_singleton
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
MigrationZeroConfigurationManager = MigrationZeroConfigurationManager.from_queryset(MigrationZeroConfigurationQuerySet)
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
from logging import Logger
|
|
2
2
|
|
|
3
3
|
from django.core.management import call_command
|
|
4
|
-
from django.db import
|
|
4
|
+
from django.db import transaction
|
|
5
|
+
from django.db.migrations.recorder import MigrationRecorder
|
|
5
6
|
|
|
6
7
|
from django_migration_zero.exceptions import InvalidMigrationTreeError
|
|
7
8
|
from django_migration_zero.helpers.logger import get_logger
|
|
@@ -20,6 +21,7 @@ class DatabasePreparationService:
|
|
|
20
21
|
|
|
21
22
|
self.logger = get_logger()
|
|
22
23
|
|
|
24
|
+
@transaction.atomic
|
|
23
25
|
def process(self):
|
|
24
26
|
self.logger.info("Starting migration zero database adjustments...")
|
|
25
27
|
|
|
@@ -34,8 +36,7 @@ class DatabasePreparationService:
|
|
|
34
36
|
# records of the other ones
|
|
35
37
|
self.logger.info("Resetting migration history for all apps...")
|
|
36
38
|
|
|
37
|
-
|
|
38
|
-
cursor.execute("DELETE FROM `django_migrations`")
|
|
39
|
+
MigrationRecorder.Migration.objects.all().delete()
|
|
39
40
|
|
|
40
41
|
# Apply migrations via fake because the database is already up-to-date
|
|
41
42
|
self.logger.info("Populating migration history.")
|
|
@@ -67,8 +67,6 @@ exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
|
|
|
67
67
|
|
|
68
68
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
|
69
69
|
# a list of builtin themes.
|
|
70
|
-
#
|
|
71
|
-
# html_theme = "alabaster"
|
|
72
70
|
html_theme = "sphinx_rtd_theme"
|
|
73
71
|
html_theme_options = {
|
|
74
72
|
"display_version": False,
|
|
@@ -14,13 +14,13 @@ classifiers = [
|
|
|
14
14
|
"Framework :: Django",
|
|
15
15
|
"Framework :: Django :: 4.2",
|
|
16
16
|
"Framework :: Django :: 5.0",
|
|
17
|
+
"Framework :: Django :: 5.1",
|
|
17
18
|
"Intended Audience :: Developers",
|
|
18
19
|
"License :: OSI Approved :: MIT License",
|
|
19
20
|
"Natural Language :: English",
|
|
20
21
|
"Operating System :: OS Independent",
|
|
21
22
|
"Programming Language :: Python",
|
|
22
23
|
"Programming Language :: Python :: 3",
|
|
23
|
-
"Programming Language :: Python :: 3.8",
|
|
24
24
|
"Programming Language :: Python :: 3.9",
|
|
25
25
|
"Programming Language :: Python :: 3.10",
|
|
26
26
|
"Programming Language :: Python :: 3.11",
|
|
@@ -30,7 +30,7 @@ classifiers = [
|
|
|
30
30
|
dynamic = ["version", "description"]
|
|
31
31
|
license = {"file" = "LICENSE.md"}
|
|
32
32
|
dependencies = [
|
|
33
|
-
'Django>=
|
|
33
|
+
'Django>=4.2',
|
|
34
34
|
]
|
|
35
35
|
|
|
36
36
|
|
|
@@ -41,14 +41,15 @@ dev = [
|
|
|
41
41
|
'pytest-django~=4.7',
|
|
42
42
|
'pytest-mock~=3.12',
|
|
43
43
|
'coverage~=7.3',
|
|
44
|
-
'pre-commit~=3.
|
|
45
|
-
'ruff~=0.
|
|
44
|
+
'pre-commit~=3.7',
|
|
45
|
+
'ruff~=0.4',
|
|
46
46
|
'sphinx~=7.1',
|
|
47
47
|
'sphinx-rtd-theme~=2.0',
|
|
48
48
|
'm2r2==0.3.3.post2',
|
|
49
49
|
'mistune<2.0.0',
|
|
50
50
|
'flit~=3.9',
|
|
51
|
-
'
|
|
51
|
+
'keyring~=25.2',
|
|
52
|
+
'ambient-package-update',
|
|
52
53
|
'unittest-parametrize~=1.3',
|
|
53
54
|
]
|
|
54
55
|
|
|
@@ -74,18 +75,24 @@ lint.select = [
|
|
|
74
75
|
"DTZ", # flake8-datetimez
|
|
75
76
|
"DJ", # flake8-django
|
|
76
77
|
"TD", # flake8-to-do
|
|
77
|
-
"
|
|
78
|
+
"RUF", # Ruff-specific rules
|
|
78
79
|
"YTT", # Avoid non-future-prove usages of "sys"
|
|
79
|
-
# "FBT", # Protects you from the "boolean trap bug"
|
|
80
80
|
"C4", # Checks for unnecessary conversions
|
|
81
81
|
"PIE", # Bunch of useful rules
|
|
82
|
-
# "SIM", # Simplifies your code
|
|
83
82
|
"INT", # Validates your gettext translation strings
|
|
84
83
|
"PERF", # PerfLint
|
|
85
84
|
"PGH", # No all-purpose "# noqa" and eval validation
|
|
86
85
|
"PL", # PyLint
|
|
86
|
+
"LOG", # flake8-logging
|
|
87
|
+
"TID", # flake8-tidy-imports
|
|
88
|
+
"PLR2004", # Magic numbers
|
|
89
|
+
"BLE", # Checks for except clauses that catch all exceptions
|
|
90
|
+
"ANN401", # Checks that function arguments are annotated with a more specific type than Any
|
|
91
|
+
"TRY", # Clean try/except
|
|
92
|
+
"ERA", # Commented out code
|
|
87
93
|
]
|
|
88
94
|
lint.ignore = [
|
|
95
|
+
'TRY003', # Avoid specifying long messages outside the exception class
|
|
89
96
|
]
|
|
90
97
|
|
|
91
98
|
# Allow autofix for all enabled rules (when `--fix`) is provided.
|
|
@@ -100,16 +107,21 @@ lint.fixable = [
|
|
|
100
107
|
"DTZ", # flake8-datetimez
|
|
101
108
|
"DJ", # flake8-django
|
|
102
109
|
"TD", # flake8-to-do
|
|
103
|
-
"
|
|
110
|
+
"RUF", # Ruff-specific rules
|
|
104
111
|
"YTT", # Avoid non-future-prove usages of "sys"
|
|
105
|
-
# "FBT", # Protects you from the "boolean trap bug"
|
|
106
112
|
"C4", # Checks for unnecessary conversions
|
|
107
113
|
"PIE", # Bunch of useful rules
|
|
108
|
-
# "SIM", # Simplifies your code
|
|
109
114
|
"INT", # Validates your gettext translation strings
|
|
110
115
|
"PERF", # PerfLint
|
|
111
116
|
"PGH", # No all-purpose "# noqa" and eval validation
|
|
112
117
|
"PL", # PyLint
|
|
118
|
+
"LOG", # flake8-logging
|
|
119
|
+
"TID", # flake8-tidy-imports
|
|
120
|
+
"PLR2004", # Magic numbers
|
|
121
|
+
"BLE", # Checks for except clauses that catch all exceptions
|
|
122
|
+
"ANN401", # Checks that function arguments are annotated with a more specific type than Any
|
|
123
|
+
"TRY", # Clean try/except
|
|
124
|
+
"ERA", # Commented out code
|
|
113
125
|
]
|
|
114
126
|
lint.unfixable = []
|
|
115
127
|
|
|
@@ -141,7 +153,7 @@ exclude = [
|
|
|
141
153
|
line-length = 120
|
|
142
154
|
|
|
143
155
|
# Allow unused variables when underscore-prefixed.
|
|
144
|
-
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
|
|
156
|
+
lint.dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
|
|
145
157
|
|
|
146
158
|
# Assume Python 3.12
|
|
147
159
|
target-version = "py312"
|
|
@@ -161,22 +173,18 @@ line-ending = "auto"
|
|
|
161
173
|
|
|
162
174
|
[tool.tox]
|
|
163
175
|
legacy_tox_ini = """
|
|
164
|
-
[tox]
|
|
165
|
-
envlist = py{38,39,310,311}-django{32,41,42}
|
|
166
|
-
isolated_build = True
|
|
167
|
-
|
|
168
176
|
[testenv]
|
|
169
177
|
# Django deprecation overview: https://www.djangoproject.com/download/
|
|
170
178
|
deps =
|
|
171
179
|
django42: Django==4.2.*
|
|
172
180
|
django50: Django==5.0.*
|
|
181
|
+
django51: Django==5.1.*
|
|
173
182
|
extras = dev,
|
|
174
183
|
commands =
|
|
175
184
|
coverage run -m pytest --ds settings tests
|
|
176
185
|
|
|
177
186
|
[gh-actions]
|
|
178
187
|
python =
|
|
179
|
-
3.8: py38
|
|
180
188
|
3.9: py39
|
|
181
189
|
3.10: py310
|
|
182
190
|
3.11: py311
|
{django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/tests/services/test_deployment.py
RENAMED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
from logging import Logger
|
|
2
|
+
from threading import Thread
|
|
2
3
|
from unittest import mock
|
|
4
|
+
from unittest.mock import Mock, call
|
|
3
5
|
|
|
4
|
-
from django.test import TestCase
|
|
6
|
+
from django.test import TestCase, TransactionTestCase
|
|
5
7
|
from django.utils import timezone
|
|
6
8
|
from freezegun import freeze_time
|
|
7
9
|
|
|
@@ -81,3 +83,56 @@ class DatabasePreparationServiceTest(TestCase):
|
|
|
81
83
|
|
|
82
84
|
self.assertEqual(calls[1].args, ("migrate",))
|
|
83
85
|
self.assertEqual(calls[1].kwargs, {"check": True})
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class DatabasePreparationServiceTestParallelDeployment(TransactionTestCase):
|
|
89
|
+
@mock.patch("django_migration_zero.services.deployment.get_logger")
|
|
90
|
+
def test_process_multiple_threads(self, mock_get_logger):
|
|
91
|
+
"""Test parallel deployments to multiple pods."""
|
|
92
|
+
# Setup
|
|
93
|
+
mock_logger_info = Mock(return_value=None)
|
|
94
|
+
mock_get_logger.return_value = Mock(info=mock_logger_info)
|
|
95
|
+
config, _ = MigrationZeroConfiguration.objects.update_or_create(
|
|
96
|
+
defaults={
|
|
97
|
+
"migration_imminent": True,
|
|
98
|
+
"migration_date": timezone.now().date(),
|
|
99
|
+
}
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# Testable
|
|
103
|
+
number_of_pods = 1
|
|
104
|
+
threads = [Thread(target=DatabasePreparationService().process) for _ in range(number_of_pods)]
|
|
105
|
+
|
|
106
|
+
for thread in threads:
|
|
107
|
+
thread.start()
|
|
108
|
+
|
|
109
|
+
for thread in threads:
|
|
110
|
+
thread.join()
|
|
111
|
+
|
|
112
|
+
# Assertions
|
|
113
|
+
self.assertEqual(mock_logger_info.call_count, 6 + number_of_pods, msg=mock_logger_info.call_args_list)
|
|
114
|
+
mock_logger_info.assert_has_calls(
|
|
115
|
+
[
|
|
116
|
+
call("Starting migration zero database adjustments..."),
|
|
117
|
+
call("Resetting migration history for all apps..."),
|
|
118
|
+
call("Populating migration history."),
|
|
119
|
+
call("Checking migration integrity."),
|
|
120
|
+
call("All good."),
|
|
121
|
+
call("Deactivating migration zero switch in database."),
|
|
122
|
+
call("Process successfully finished."),
|
|
123
|
+
],
|
|
124
|
+
any_order=True,
|
|
125
|
+
)
|
|
126
|
+
self.assertEqual(
|
|
127
|
+
len(
|
|
128
|
+
[
|
|
129
|
+
mock_call
|
|
130
|
+
for mock_call in mock_logger_info.call_args_list
|
|
131
|
+
if mock_call == call("Starting migration zero database adjustments...")
|
|
132
|
+
]
|
|
133
|
+
),
|
|
134
|
+
number_of_pods,
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
config.refresh_from_db()
|
|
138
|
+
self.assertFalse(config.migration_imminent)
|
|
@@ -5,6 +5,7 @@ from django.db import ProgrammingError
|
|
|
5
5
|
from django.test import TestCase
|
|
6
6
|
|
|
7
7
|
from django_migration_zero.exceptions import MissingMigrationZeroConfigRecordError
|
|
8
|
+
from django_migration_zero.managers import MigrationZeroConfigurationManager
|
|
8
9
|
from django_migration_zero.models import MigrationZeroConfiguration
|
|
9
10
|
|
|
10
11
|
|
|
@@ -18,7 +19,7 @@ class MigrationZeroConfigurationManagerTest(TestCase):
|
|
|
18
19
|
def test_fetch_singleton_singleton_exists_via_migration(self):
|
|
19
20
|
self.assertEqual(MigrationZeroConfiguration.objects.all().count(), 1)
|
|
20
21
|
|
|
21
|
-
@mock.patch.object(
|
|
22
|
+
@mock.patch.object(MigrationZeroConfigurationManager, "select_for_update", side_effect=ProgrammingError)
|
|
22
23
|
def test_fetch_singleton_database_error(self, *args):
|
|
23
24
|
self.assertIsNone(MigrationZeroConfiguration.objects.fetch_singleton())
|
|
24
25
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/django_migration_zero/exceptions.py
RENAMED
|
File without changes
|
|
File without changes
|
{django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/django_migration_zero/helpers/logger.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/django_migration_zero/services/local.py
RENAMED
|
File without changes
|
|
File without changes
|
{django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/docs/features/01_introduction.md
RENAMED
|
File without changes
|
{django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/docs/features/02_configuration.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/docs/features/05_architecture.md
RENAMED
|
File without changes
|
{django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/docs/features/06_management_commands.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/scripts/unix/install_requirements.sh
RENAMED
|
File without changes
|
|
File without changes
|
{django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/scripts/windows/install_requirements.ps1
RENAMED
|
File without changes
|
{django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/scripts/windows/publish_to_pypi.ps1
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/tests/helpers/test_file_system.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_migration_zero-2.1.0 → django_migration_zero-2.3.2}/tests/management/commands/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|