django-migraid 0.1.0b1__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.
Files changed (60) hide show
  1. django_migraid-0.1.0b1/.claude/settings.local.json +11 -0
  2. django_migraid-0.1.0b1/.editorconfig +21 -0
  3. django_migraid-0.1.0b1/.github/workflows/ci.yml +55 -0
  4. django_migraid-0.1.0b1/.gitignore +55 -0
  5. django_migraid-0.1.0b1/.pre-commit-config.yaml +16 -0
  6. django_migraid-0.1.0b1/CHANGELOG.md +32 -0
  7. django_migraid-0.1.0b1/CODE_OF_CONDUCT.md +26 -0
  8. django_migraid-0.1.0b1/CONTRIBUTING.md +45 -0
  9. django_migraid-0.1.0b1/LICENSE +174 -0
  10. django_migraid-0.1.0b1/NOTICE +6 -0
  11. django_migraid-0.1.0b1/PKG-INFO +192 -0
  12. django_migraid-0.1.0b1/README.md +154 -0
  13. django_migraid-0.1.0b1/docs/index.md +26 -0
  14. django_migraid-0.1.0b1/docs/known-issues.md +129 -0
  15. django_migraid-0.1.0b1/docs/mkdocs.yml +36 -0
  16. django_migraid-0.1.0b1/pyproject.toml +87 -0
  17. django_migraid-0.1.0b1/src/migraid/__init__.py +3 -0
  18. django_migraid-0.1.0b1/src/migraid/analysis/__init__.py +0 -0
  19. django_migraid-0.1.0b1/src/migraid/analysis/graph.py +146 -0
  20. django_migraid-0.1.0b1/src/migraid/analysis/issues.py +344 -0
  21. django_migraid-0.1.0b1/src/migraid/analysis/loader.py +60 -0
  22. django_migraid-0.1.0b1/src/migraid/analysis/scanner.py +212 -0
  23. django_migraid-0.1.0b1/src/migraid/apps.py +7 -0
  24. django_migraid-0.1.0b1/src/migraid/management/__init__.py +0 -0
  25. django_migraid-0.1.0b1/src/migraid/management/commands/__init__.py +0 -0
  26. django_migraid-0.1.0b1/src/migraid/management/commands/migraid.py +494 -0
  27. django_migraid-0.1.0b1/src/migraid/operations/__init__.py +0 -0
  28. django_migraid-0.1.0b1/src/migraid/operations/backup.py +111 -0
  29. django_migraid-0.1.0b1/src/migraid/operations/plan.py +323 -0
  30. django_migraid-0.1.0b1/src/migraid/operations/rewriter.py +136 -0
  31. django_migraid-0.1.0b1/src/migraid/output/__init__.py +0 -0
  32. django_migraid-0.1.0b1/src/migraid/output/console.py +95 -0
  33. django_migraid-0.1.0b1/tests/__init__.py +0 -0
  34. django_migraid-0.1.0b1/tests/conftest.py +166 -0
  35. django_migraid-0.1.0b1/tests/fixtures/__init__.py +0 -0
  36. django_migraid-0.1.0b1/tests/settings.py +16 -0
  37. django_migraid-0.1.0b1/tests/test_analysis/__init__.py +0 -0
  38. django_migraid-0.1.0b1/tests/test_analysis/test_graph.py +198 -0
  39. django_migraid-0.1.0b1/tests/test_analysis/test_issues.py +173 -0
  40. django_migraid-0.1.0b1/tests/test_analysis/test_loader.py +72 -0
  41. django_migraid-0.1.0b1/tests/test_analysis/test_scanner.py +222 -0
  42. django_migraid-0.1.0b1/tests/test_commands/__init__.py +0 -0
  43. django_migraid-0.1.0b1/tests/test_commands/test_doctor.py +76 -0
  44. django_migraid-0.1.0b1/tests/test_commands/test_fix_conflicts.py +68 -0
  45. django_migraid-0.1.0b1/tests/test_commands/test_graph_cmd.py +56 -0
  46. django_migraid-0.1.0b1/tests/test_commands/test_internals.py +182 -0
  47. django_migraid-0.1.0b1/tests/test_commands/test_prune.py +47 -0
  48. django_migraid-0.1.0b1/tests/test_commands/test_renumber.py +68 -0
  49. django_migraid-0.1.0b1/tests/test_operations/__init__.py +0 -0
  50. django_migraid-0.1.0b1/tests/test_operations/test_backup.py +236 -0
  51. django_migraid-0.1.0b1/tests/test_operations/test_plan.py +304 -0
  52. django_migraid-0.1.0b1/tests/test_operations/test_rewriter.py +154 -0
  53. django_migraid-0.1.0b1/tests/test_output/__init__.py +0 -0
  54. django_migraid-0.1.0b1/tests/test_output/test_console.py +174 -0
  55. django_migraid-0.1.0b1/tests/testapp/__init__.py +0 -0
  56. django_migraid-0.1.0b1/tests/testapp/apps.py +6 -0
  57. django_migraid-0.1.0b1/tests/testapp/migrations/0001_initial.py +15 -0
  58. django_migraid-0.1.0b1/tests/testapp/migrations/__init__.py +0 -0
  59. django_migraid-0.1.0b1/tests/testapp/models.py +8 -0
  60. django_migraid-0.1.0b1/tox.ini +28 -0
@@ -0,0 +1,11 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "WebSearch",
5
+ "Bash(python3 *)",
6
+ "Bash(grep -E \"\\\\.py$\")",
7
+ "Bash(cat)",
8
+ "Read(//tmp/**)"
9
+ ]
10
+ }
11
+ }
@@ -0,0 +1,21 @@
1
+ root = true
2
+
3
+ [*]
4
+ indent_style = space
5
+ indent_size = 4
6
+ end_of_line = lf
7
+ charset = utf-8
8
+ trim_trailing_whitespace = true
9
+ insert_final_newline = true
10
+
11
+ [*.yml]
12
+ indent_size = 2
13
+
14
+ [*.toml]
15
+ indent_size = 4
16
+
17
+ [Makefile]
18
+ indent_style = tab
19
+
20
+ [*.md]
21
+ trim_trailing_whitespace = false
@@ -0,0 +1,55 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ lint:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+ - uses: actions/setup-python@v5
14
+ with:
15
+ python-version: "3.12"
16
+ - name: Install lint deps
17
+ run: pip install ruff mypy "django-stubs[compatible-mypy]>=4.2" Django>=4.2 libcst>=1.1 rich>=13.0 gitpython>=3.1
18
+ - run: ruff check src tests
19
+ - run: ruff format --check src tests
20
+ - run: mypy src/migraid
21
+
22
+ test:
23
+ runs-on: ubuntu-latest
24
+ strategy:
25
+ fail-fast: false
26
+ matrix:
27
+ python-version: ["3.10", "3.11", "3.12"]
28
+ django-version: ["4.2", "5.0", "5.1"]
29
+ steps:
30
+ - uses: actions/checkout@v4
31
+ - uses: actions/setup-python@v5
32
+ with:
33
+ python-version: ${{ matrix.python-version }}
34
+ - name: Install dependencies
35
+ run: |
36
+ pip install "Django~=${{ matrix.django-version }}.0" -e ".[dev]"
37
+ - name: Run tests with coverage
38
+ run: pytest --cov=migraid --cov-report=xml --cov-report=term
39
+ - uses: codecov/codecov-action@v4
40
+ if: matrix.python-version == '3.12' && matrix.django-version == '5.1'
41
+ with:
42
+ files: ./coverage.xml
43
+ fail_ci_if_error: false
44
+
45
+ docs:
46
+ runs-on: ubuntu-latest
47
+ if: github.ref == 'refs/heads/main'
48
+ needs: [lint, test]
49
+ steps:
50
+ - uses: actions/checkout@v4
51
+ - uses: actions/setup-python@v5
52
+ with:
53
+ python-version: "3.12"
54
+ - run: pip install mkdocs-material
55
+ - run: mkdocs build --strict
@@ -0,0 +1,55 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *$py.class
4
+ *.so
5
+ .Python
6
+ build/
7
+ dist/
8
+ *.egg-info/
9
+ .eggs/
10
+ *.egg
11
+ MANIFEST
12
+
13
+ .venv/
14
+ env/
15
+ venv/
16
+ ENV/
17
+
18
+ .pytest_cache/
19
+ .mypy_cache/
20
+ .ruff_cache/
21
+ .coverage
22
+ coverage.xml
23
+ htmlcov/
24
+
25
+ .tox/
26
+ .nox/
27
+
28
+ *.mo
29
+ *.pot
30
+ local_settings.py
31
+ db.sqlite3
32
+ db.sqlite3-journal
33
+
34
+ instance/
35
+ .webassets-cache
36
+
37
+ .scrapy
38
+
39
+ docs/_build/
40
+ docs/site/
41
+
42
+ .DS_Store
43
+ .env
44
+ .env.*
45
+
46
+ *.log
47
+ *.pid
48
+
49
+ dist/
50
+ node_modules/
51
+
52
+ .idea/
53
+ .vscode/
54
+ *.swp
55
+ *.swo
@@ -0,0 +1,16 @@
1
+ repos:
2
+ - repo: https://github.com/astral-sh/ruff-pre-commit
3
+ rev: v0.3.0
4
+ hooks:
5
+ - id: ruff
6
+ args: [--fix]
7
+ - id: ruff-format
8
+
9
+ - repo: https://github.com/pre-commit/mirrors-mypy
10
+ rev: v1.8.0
11
+ hooks:
12
+ - id: mypy
13
+ additional_dependencies:
14
+ - django-stubs[compatible-mypy]
15
+ - types-gitpython
16
+ args: [--strict]
@@ -0,0 +1,32 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.0b1] - 2024-05-26
11
+
12
+ ### Added
13
+ - Beta release with initial feature set.
14
+ - All features from 0.1.0-alpha.
15
+
16
+ ## [0.1.0] - 2024-01-01
17
+
18
+ ### Added
19
+ - `doctor` command: read-only diagnostic with 11 issue detectors (E001–E004, W001–W005, I001–I002)
20
+ - `rebase` command: renumber branch-local migrations onto a target branch
21
+ - `fix-conflicts` command: linearize conflicting leaf migrations
22
+ - `renumber` command: fix gap/duplicate numbering for an app
23
+ - `prune` command: remove stale `django_migrations` rows
24
+ - `graph` command: visualize migration DAG in ASCII, Mermaid, or Graphviz dot format
25
+ - Static-first analysis (Tier 1) using libcst — works on broken/mid-rebase repos
26
+ - Live Django loader integration (Tier 2) for DB-dependent checks
27
+ - Safety pipeline: dirty-tree guard, applied-migration guard, backup ref, undo log, post-apply validation
28
+ - Apache 2.0 license
29
+
30
+ [Unreleased]: https://github.com/AhmedShehab/django-migraid/compare/v0.1.0b1...HEAD
31
+ [0.1.0b1]: https://github.com/AhmedShehab/django-migraid/releases/tag/v0.1.0b1
32
+ [0.1.0]: https://github.com/AhmedShehab/django-migraid/releases/tag/v0.1.0
@@ -0,0 +1,26 @@
1
+ # Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We pledge to make participation in our community a harassment-free experience for everyone.
6
+
7
+ ## Our Standards
8
+
9
+ Examples of behavior that contributes to a positive environment:
10
+ - Using welcoming and inclusive language
11
+ - Being respectful of differing viewpoints
12
+ - Gracefully accepting constructive criticism
13
+ - Focusing on what is best for the community
14
+
15
+ Examples of unacceptable behavior:
16
+ - Harassment in any form
17
+ - Trolling or insulting comments
18
+ - Publishing others' private information without consent
19
+
20
+ ## Enforcement
21
+
22
+ Instances of abusive behavior may be reported to the project maintainers. All complaints will be reviewed and investigated.
23
+
24
+ ## Attribution
25
+
26
+ This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.1.
@@ -0,0 +1,45 @@
1
+ # Contributing to django-migraid
2
+
3
+ Thank you for contributing!
4
+
5
+ ## Development Setup
6
+
7
+ ```bash
8
+ git clone https://github.com/yourusername/django-migraid
9
+ cd django-migraid
10
+ python -m venv .venv
11
+ source .venv/bin/activate
12
+ pip install -e ".[dev]"
13
+ pre-commit install
14
+ ```
15
+
16
+ ## Running Tests
17
+
18
+ ```bash
19
+ pytest # run all tests
20
+ pytest --cov=migraid # with coverage
21
+ pytest tests/test_analysis/ # specific module
22
+ tox # full matrix (Python 3.10-3.12 × Django 4.2/5.0/5.1)
23
+ ```
24
+
25
+ ## Adding a New Issue Detector
26
+
27
+ 1. Add an issue code and description to the table in `docs/known-issues.md`
28
+ 2. Add the code to `src/migraid/analysis/issues.py` — write a detector function following the `Callable[[MigrationAnalyzer], list[Issue]]` signature
29
+ 3. Register it in `ALL_DETECTORS` at the bottom of `issues.py`
30
+ 4. Write a test in `tests/test_analysis/test_issues.py` with a fixture from `tests/fixtures/`
31
+
32
+ ## Code Style
33
+
34
+ - `ruff check src tests` — zero issues
35
+ - `ruff format src tests` — consistent formatting
36
+ - `mypy src/migraid` — strict, clean
37
+ - Type hints on every public function
38
+
39
+ ## Pull Request Checklist
40
+
41
+ - [ ] Tests added / updated
42
+ - [ ] `pytest --cov=migraid` ≥ 85%
43
+ - [ ] `ruff check src tests` passes
44
+ - [ ] `mypy src/migraid` passes
45
+ - [ ] `CHANGELOG.md` updated under `[Unreleased]`
@@ -0,0 +1,174 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship made available under
36
+ the License, as indicated by a copyright notice that is included in
37
+ or attached to the work (an example is provided in the Appendix below).
38
+
39
+ "Derivative Works" shall mean any work, whether in Source or Object
40
+ form, that is based on (or derived from) the Work and for which the
41
+ editorial revisions, annotations, elaborations, or other transformations
42
+ represent, as a whole, an original work of authorship. For the purposes
43
+ of this License, Derivative Works shall not include works that remain
44
+ separable from, or merely link (or bind by name) to the interfaces of,
45
+ the Work and Derivative Works thereof.
46
+
47
+ "Contribution" shall mean, as submitted to the Licensor for inclusion
48
+ in the Work by the copyright owner or by an individual or Legal Entity
49
+ authorized to submit on behalf of the copyright owner. For the purposes
50
+ of this definition, "submit" means any form of electronic, verbal, or
51
+ written communication sent to the Licensor or its representatives,
52
+ including but not limited to communication on electronic mailing lists,
53
+ source code control systems, and issue tracking systems that are managed
54
+ by, or on behalf of, the Licensor for the purpose of contributing to
55
+ the Work.
56
+
57
+ "Contributor" shall mean Licensor and any Legal Entity on behalf of
58
+ whom a Contribution has been received by the Licensor and included
59
+ within the Work.
60
+
61
+ 2. Grant of Copyright License. Subject to the terms and conditions of
62
+ this License, each Contributor hereby grants to You a perpetual,
63
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
64
+ copyright license to reproduce, prepare Derivative Works of,
65
+ publicly display, publicly perform, sublicense, and distribute the
66
+ Work and such Derivative Works in Source or Object form.
67
+
68
+ 3. Grant of Patent License. Subject to the terms and conditions of
69
+ this License, each Contributor hereby grants to You a perpetual,
70
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
71
+ (except as stated in this section) patent license to make, have made,
72
+ use, offer to sell, sell, import, and otherwise transfer the Work,
73
+ where such license applies only to those patent claims licensable
74
+ by such Contributor that are necessarily infringed by their
75
+ Contribution(s) alone or by the combination of their Contributions
76
+ with the Work to which such Contributions were submitted. If You
77
+ institute patent litigation against any entity (including a cross-claim
78
+ or counterclaim in a lawsuit) alleging that the Work or any patent
79
+ claim (s) embodied in the Work constitute direct or contributory patent
80
+ infringement, then any patent rights granted to You under this License
81
+ for that Work shall terminate as of the date such litigation is filed.
82
+
83
+ 4. Redistribution. You may reproduce and distribute copies of the
84
+ Work or Derivative Works thereof in any medium, with or without
85
+ modifications, and in Source or Object form, provided that You
86
+ meet the following conditions:
87
+
88
+ (a) You must give any other recipients of the Work or Derivative Works
89
+ a copy of this License; and
90
+
91
+ (b) You must cause any modified files to carry prominent notices
92
+ stating that You changed the files; and
93
+
94
+ (c) You must retain, in all Source forms of the Work and Derivative
95
+ Works that You distribute, all copyright, patent, trademark, and
96
+ attribution notices from the Source form of the Work, excluding
97
+ those notices that do not pertain to any part of the Derivative
98
+ Works; and
99
+
100
+ (d) If the Work includes a "NOTICE" text file as part of its
101
+ distribution, You must include a readable copy of the attribution
102
+ notices contained within such NOTICE file, in at least one of the
103
+ following places: within a NOTICE text file distributed as part of
104
+ the Derivative Works; within the Source form or documentation, if
105
+ provided along with the Derivative Works; or, within a display
106
+ generated by the Derivative Works, if and wherever such third-party
107
+ notices normally appear. The contents of the NOTICE file are for
108
+ informational purposes only and do not modify the License.
109
+
110
+ (e) You may add Your own attribution notices within Derivative Works
111
+ that You distribute, alongside or in addition to the NOTICE text
112
+ from the Work, provided that such additional attribution notices
113
+ cannot be construed as modifying the License.
114
+
115
+ You may add Your own license statement for Your modifications and
116
+ may provide additional grant of rights to use, copy, modify, merge,
117
+ publish, distribute, sublicense, and/or sell copies of the Work.
118
+
119
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
120
+ any Contribution intentionally submitted for inclusion in the Work
121
+ by You to the Licensor shall be under the terms and conditions of
122
+ this License, without any additional terms or conditions.
123
+
124
+ 6. Trademarks. This License does not grant permission to use the trade
125
+ names, trademarks, service marks, or product names of the Licensor,
126
+ except as required for reasonable and customary use in describing the
127
+ origin of the Work and reproducing the content of the NOTICE file.
128
+
129
+ 7. Disclaimer of Warranty. Unless required by applicable law or
130
+ agreed to in writing, Licensor provides the Work (and each
131
+ Contributor provides its Contributions) on an "AS IS" BASIS,
132
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
133
+ implied, including, without limitation, any warranties or conditions
134
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
135
+ PARTICULAR PURPOSE. You are solely responsible for determining the
136
+ appropriateness of using or reproducing the Work and assume any
137
+ risks associated with Your exercise of permissions under this License.
138
+
139
+ 8. Limitation of Liability. In no event and under no legal theory,
140
+ whether in tort (including negligence), contract, or otherwise,
141
+ unless required by applicable law (such as deliberate and grossly
142
+ negligent acts) or agreed to in writing, shall any Contributor be
143
+ liable to You for damages, including any direct, indirect, special,
144
+ incidental, or exemplary damages of any character arising as a
145
+ result of this License or out of the use or inability to use the
146
+ Work (even if such Contributor has been advised of the possibility
147
+ of such damages).
148
+
149
+ 9. Accepting Warranty or Liability. While redistributing the Work or
150
+ Derivative Works thereof, You may choose to offer, and charge a fee
151
+ for, acceptance of support, warranty, indemnity, or other liability
152
+ obligations and/or rights consistent with this License. However, in
153
+ accepting such obligations, You may offer only on your own behalf and
154
+ on your sole responsibility, not on behalf of any other Contributor,
155
+ and only if You agree to indemnify, defend, and hold each Contributor
156
+ harmless for any liability incurred by, or claims asserted against,
157
+ such Contributor by reason of your accepting any warranty or
158
+ additional liability.
159
+
160
+ END OF TERMS AND CONDITIONS
161
+
162
+ Copyright 2024 django-migraid contributors
163
+
164
+ Licensed under the Apache License, Version 2.0 (the "License");
165
+ you may not use this file except in compliance with the License.
166
+ You may obtain a copy of the License at
167
+
168
+ http://www.apache.org/licenses/LICENSE-2.0
169
+
170
+ Unless required by applicable law or agreed to in writing, software
171
+ distributed under the License is distributed on an "AS IS" BASIS,
172
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
173
+ See the License for the specific language governing permissions and
174
+ limitations under the License.
@@ -0,0 +1,6 @@
1
+ django-migraid
2
+ Copyright 2024 django-migraid contributors
3
+
4
+ This product includes software developed by the django-migraid contributors.
5
+
6
+ Licensed under the Apache License, Version 2.0.
@@ -0,0 +1,192 @@
1
+ Metadata-Version: 2.4
2
+ Name: django-migraid
3
+ Version: 0.1.0b1
4
+ Summary: Detect, diagnose, and auto-fix Django migration problems in Git workflows
5
+ Project-URL: Homepage, https://github.com/AhmedShehab/django-migraid
6
+ Project-URL: Repository, https://github.com/AhmedShehab/django-migraid
7
+ Project-URL: Documentation, https://AhmedShehab.github.io/django-migraid
8
+ Project-URL: Changelog, https://github.com/AhmedShehab/django-migraid/blob/main/CHANGELOG.md
9
+ License-Expression: Apache-2.0
10
+ License-File: LICENSE
11
+ License-File: NOTICE
12
+ Keywords: devtools,django,git,migrations,rebase
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Framework :: Django
15
+ Classifier: Framework :: Django :: 4.2
16
+ Classifier: Framework :: Django :: 5.0
17
+ Classifier: Framework :: Django :: 5.1
18
+ Classifier: Intended Audience :: Developers
19
+ Classifier: License :: OSI Approved :: Apache Software License
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Requires-Python: >=3.10
25
+ Requires-Dist: django>=4.2
26
+ Requires-Dist: gitpython>=3.1
27
+ Requires-Dist: libcst>=1.1
28
+ Requires-Dist: rich>=13.0
29
+ Provides-Extra: dev
30
+ Requires-Dist: coverage[toml]>=7.3; extra == 'dev'
31
+ Requires-Dist: django-stubs[compatible-mypy]>=4.2; extra == 'dev'
32
+ Requires-Dist: mkdocs-material>=9.0; extra == 'dev'
33
+ Requires-Dist: mypy>=1.8; extra == 'dev'
34
+ Requires-Dist: pytest-django>=4.7; extra == 'dev'
35
+ Requires-Dist: pytest>=7.4; extra == 'dev'
36
+ Requires-Dist: ruff>=0.3; extra == 'dev'
37
+ Description-Content-Type: text/markdown
38
+
39
+ # django-migraid
40
+
41
+ **Detect, diagnose, and auto-fix Django migration problems in Git workflows.**
42
+
43
+ [![CI](https://github.com/AhmedShehab/django-migraid/actions/workflows/ci.yml/badge.svg)](https://github.com/AhmedShehab/django-migraid/actions)
44
+ [![PyPI](https://img.shields.io/pypi/v/django-migraid.svg)](https://pypi.org/project/django-migraid/)
45
+ [![Python](https://img.shields.io/pypi/pyversions/django-migraid.svg)](https://pypi.org/project/django-migraid/)
46
+ [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
47
+
48
+ ---
49
+
50
+ ## The Problem
51
+
52
+ Two developers branch from `main` at migration `0004`. Both generate `0005_*.py`. Main merges one. The second developer's rebase leaves them with a conflict that `makemigrations --merge` doesn't cleanly handle in rebase-based workflows. django-migraid fixes this — and ten other common migration pain points.
53
+
54
+ ## Installation
55
+
56
+ ```bash
57
+ pip install django-migraid
58
+ ```
59
+
60
+ Add to `INSTALLED_APPS`:
61
+
62
+ ```python
63
+ INSTALLED_APPS = [
64
+ ...
65
+ "migraid",
66
+ ]
67
+ ```
68
+
69
+ ## Quick Start
70
+
71
+ ```bash
72
+ # Diagnose all migration issues in your project
73
+ python manage.py migraid doctor
74
+
75
+ # Rebase your branch's migrations onto main
76
+ python manage.py migraid rebase --base main --dry-run
77
+
78
+ # Fix conflicting leaf migrations
79
+ python manage.py migraid fix-conflicts --dry-run
80
+
81
+ # Fix out-of-order numbering
82
+ python manage.py migraid renumber myapp --dry-run
83
+
84
+ # Remove stale django_migrations rows
85
+ python manage.py migraid prune
86
+
87
+ # Visualize the migration DAG
88
+ python manage.py migraid graph myapp --format mermaid
89
+ ```
90
+
91
+ ## Problems This Solves
92
+
93
+ | Issue | Code | Command |
94
+ |-------|------|---------|
95
+ | Conflicting leaf migrations (parallel development) | E001 | `fix-conflicts` |
96
+ | Circular migration dependencies | E002 | — (reports) |
97
+ | Out-of-order / gap numbering after rebase | E003 | `renumber` |
98
+ | Dependency on a deleted migration | E004 | — (reports) |
99
+ | Stale `django_migrations` rows | W001 | `prune` |
100
+ | `RunPython` without `reverse_code` | W002 | — (reports) |
101
+ | Squashed migration with old files still present | W003 | — (reports) |
102
+ | Merge migrations in a rebase-workflow repo | W004 | `rebase` |
103
+ | Non-deterministic dependency ordering | W005 | — (reports) |
104
+ | Cross-app dependency risks | I001 | — (reports) |
105
+ | `--fake` / `--fake-initial` footgun patterns | I002 | — (reports) |
106
+
107
+ ## Command Reference
108
+
109
+ ### `doctor`
110
+
111
+ Read-only diagnostic. Reports every detected issue with severity.
112
+
113
+ ```bash
114
+ python manage.py migraid doctor [--app LABEL] [--format text|json]
115
+ ```
116
+
117
+ ### `rebase`
118
+
119
+ Renumber local branch migrations to follow the latest from a target branch.
120
+
121
+ ```bash
122
+ python manage.py migraid rebase [--base BRANCH] [--app LABEL] [--dry-run] [--yes] [--force] [--allow-applied]
123
+ ```
124
+
125
+ ### `fix-conflicts`
126
+
127
+ Resolve multiple-leaf conflicts by linearizing the fork.
128
+
129
+ ```bash
130
+ python manage.py migraid fix-conflicts [--app LABEL] [--dry-run] [--yes] [--force] [--allow-applied]
131
+ ```
132
+
133
+ ### `renumber`
134
+
135
+ Fix gap or duplicate numbering in a single app's migrations.
136
+
137
+ ```bash
138
+ python manage.py migraid renumber <app> [--dry-run] [--yes] [--force] [--allow-applied]
139
+ ```
140
+
141
+ ### `prune`
142
+
143
+ Remove orphaned `django_migrations` rows for migrations no longer on disk.
144
+
145
+ ```bash
146
+ python manage.py migraid prune [--dry-run] [--yes] [--allow-applied]
147
+ ```
148
+
149
+ ### `graph`
150
+
151
+ Print or export the migration DAG.
152
+
153
+ ```bash
154
+ python manage.py migraid graph [app] [--format mermaid|dot|ascii] [--output FILE]
155
+ ```
156
+
157
+ ## Safety Model
158
+
159
+ Every mutation command:
160
+ 1. Checks for uncommitted git changes (bypass with `--force`)
161
+ 2. Guards against rewriting already-applied migrations (bypass with `--allow-applied`)
162
+ 3. Creates a `migraid-backup-<timestamp>` git ref before any writes
163
+ 4. Shows a diff-style preview before making changes
164
+ 5. Asks for confirmation (bypass with `--yes`)
165
+ 6. Maintains an undo log — reverses all file ops automatically if anything fails
166
+ 7. Self-validates after apply: if the migration graph gets worse, auto-reverts
167
+
168
+ `--dry-run` on any mutation command prints the full preview without writing.
169
+
170
+ ## CI Integration
171
+
172
+ Add to your pre-push hook or CI pipeline:
173
+
174
+ ```bash
175
+ python manage.py migraid doctor --format json | jq '.[] | select(.severity == "error")'
176
+ ```
177
+
178
+ Or fail CI on any ERROR-level issue:
179
+
180
+ ```bash
181
+ python manage.py migraid doctor
182
+ ```
183
+
184
+ (exits non-zero if any E0xx issues are found)
185
+
186
+ ## Contributing
187
+
188
+ See [CONTRIBUTING.md](CONTRIBUTING.md).
189
+
190
+ ## License
191
+
192
+ Apache 2.0 — see [LICENSE](LICENSE).