├── .coveragerc ├── .editorconfig ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yaml │ └── feature_request.yaml ├── dependabot.yml └── workflows │ ├── auto-approve.yml │ ├── auto-merge.yml │ ├── codacy-analysis.yml │ ├── deploy.yml │ ├── greetings.yml │ ├── test.yml │ └── update-doc-assets.yml ├── .gitignore ├── .gitmodules ├── .pep8speaks.yml ├── .pre-commit-config.yaml ├── .pyup.yml ├── .whitesource ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.md ├── action.yml ├── conftest.py ├── django_migration_fixer ├── __init__.py └── settings.py ├── docs ├── CHANGELOG.md ├── README.md ├── command-options.md ├── css │ └── custom.css ├── images │ └── logo.png ├── makemigrations.md ├── more-examples.md └── utils.md ├── manage.py ├── migration_fixer ├── __init__.py ├── apps.py ├── management │ ├── __init__.py │ └── commands │ │ ├── __init__.py │ │ └── makemigrations.py ├── tests │ ├── __init__.py │ ├── management │ │ ├── __init__.py │ │ └── commands │ │ │ ├── __init__.py │ │ │ ├── _constants.py │ │ │ ├── _utils.py │ │ │ ├── conftest.py │ │ │ └── test_makemigrations.py │ └── test_utils.py └── utils.py ├── mkdocs.yml ├── mypy.ini ├── renovate.json ├── requirements.txt ├── setup.cfg ├── setup.py └── tox.ini /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | source = migration_fixer 3 | omit = 4 | migration_fixer/test*, 5 | migration_fixer/apps* 6 | 7 | [report] 8 | precision = 1 9 | exclude_lines = 10 | pragma: no cover 11 | pass 12 | def __repr__ 13 | if self.debug: 14 | if settings.DEBUG 15 | # Don't complain if tests don't hit defensive assertion code: 16 | raise AssertionError 17 | raise NotImplementedError 18 | except ImportError 19 | except IntegrityError 20 | # Don't complain if non-runnable code isn't run: 21 | if __name__ == .__main__.: 22 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.{py,rst,ini}] 12 | indent_style = space 13 | indent_size = 4 14 | 15 | [*.{html,css,scss,json,yml}] 16 | indent_style = space 17 | indent_size = 2 18 | 19 | [*.md] 20 | trim_trailing_whitespace = false 21 | 22 | [Makefile] 23 | indent_style = tab 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yaml: -------------------------------------------------------------------------------- 1 | name: 🐞 Bug 2 | description: Create a report to help us improve 3 | title: "[BUG] " 4 | labels: [bug, needs triage] 5 | 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | Thanks for taking the time to fill out this bug report! 11 | - type: checkboxes 12 | attributes: 13 | label: Is there an existing issue for this? 14 | description: Please search to see if an issue already exists for the bug you encountered. 15 | options: 16 | - label: I have searched the existing issues 17 | required: true 18 | - type: checkboxes 19 | attributes: 20 | label: Does this issue exist in the latest version? 21 | description: Please view all releases to confirm that this issue hasn't already been fixed. 22 | options: 23 | - label: I'm using the latest release 24 | required: true 25 | - type: textarea 26 | id: what-happened 27 | attributes: 28 | label: Describe the bug? 29 | description: A clear and concise description of what the bug is 30 | placeholder: Tell us what you see! 31 | validations: 32 | required: true 33 | - type: textarea 34 | id: reproduce 35 | attributes: 36 | label: To Reproduce 37 | description: Steps to reproduce the behavior? 38 | placeholder: | 39 | 1. In this environment... 40 | 2. With this config... 41 | 3. Run '...' 42 | 4. See error... 43 | validations: 44 | required: true 45 | - type: dropdown 46 | id: os 47 | attributes: 48 | label: What OS are you seeing the problem on? 49 | multiple: true 50 | options: 51 | - Ubuntu 52 | - macOS 53 | - Windows 54 | - Other 55 | validations: 56 | required: false 57 | - type: textarea 58 | id: expected 59 | attributes: 60 | label: Expected behavior? 61 | description: A clear and concise description of what you expected to happen. 62 | placeholder: Tell us what you expected! 63 | validations: 64 | required: true 65 | - type: textarea 66 | id: logs 67 | attributes: 68 | label: Relevant log output 69 | description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. 70 | placeholder: | 71 | This can be achieved by: 72 | 1. Re-running the workflow with debug logging enabled. 73 | 2. Copy or download the log archive. 74 | 3. Paste the contents here or upload the file in a subsequent comment. 75 | render: shell 76 | - type: textarea 77 | attributes: 78 | label: Anything else? 79 | description: | 80 | Links? or References? 81 | 82 | Anything that will give us more context about the issue you are encountering! 83 | 84 | Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. 85 | validations: 86 | required: false 87 | - type: checkboxes 88 | id: terms 89 | attributes: 90 | label: Code of Conduct 91 | description: By submitting this issue, you agree to follow our [Code of Conduct](../blob/main/CODE_OF_CONDUCT.md) 92 | options: 93 | - label: I agree to follow this project's Code of Conduct 94 | required: true 95 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yaml: -------------------------------------------------------------------------------- 1 | name: Feature request 2 | description: Suggest an idea for this project 3 | title: "[Feature] <title>" 4 | labels: [enhancement] 5 | 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | Thanks for taking the time to fill out this feature request! 11 | - type: checkboxes 12 | attributes: 13 | label: Is this feature missing in the latest version? 14 | description: Please upgrade to the latest version to verify that this feature is still missing. 15 | options: 16 | - label: I'm using the latest release 17 | required: true 18 | - type: textarea 19 | id: what-happened 20 | attributes: 21 | label: Is your feature request related to a problem? Please describe. 22 | description: | 23 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 24 | placeholder: Tell us what you see! 25 | validations: 26 | required: true 27 | - type: textarea 28 | id: requests 29 | attributes: 30 | label: Describe the solution you'd like? 31 | description: A clear and concise description of what you want to happen. 32 | validations: 33 | required: true 34 | - type: textarea 35 | id: alternative 36 | attributes: 37 | label: Describe alternatives you've considered? 38 | description: A clear and concise description of any alternative solutions or features you've considered. 39 | validations: 40 | required: false 41 | - type: textarea 42 | attributes: 43 | label: Anything else? 44 | description: | 45 | Links? or References? 46 | 47 | Add any other context or screenshots about the feature request here. 48 | 49 | Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. 50 | validations: 51 | required: false 52 | - type: checkboxes 53 | id: terms 54 | attributes: 55 | label: Code of Conduct 56 | description: By submitting this issue, you agree to follow our [Code of Conduct](./CODE_OF_CONDUCT.md) 57 | options: 58 | - label: I agree to follow this project's Code of Conduct 59 | required: true 60 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: pip 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | labels: 9 | - "dependencies" 10 | - "dependabot" 11 | - "automerge" 12 | - package-ecosystem: github-actions 13 | directory: "/" 14 | schedule: 15 | interval: daily 16 | open-pull-requests-limit: 10 17 | labels: 18 | - "dependencies" 19 | - "dependabot" 20 | - "automerge" 21 | -------------------------------------------------------------------------------- /.github/workflows/auto-approve.yml: -------------------------------------------------------------------------------- 1 | name: Auto approve 2 | 3 | on: 4 | pull_request_target 5 | 6 | jobs: 7 | auto-approve: 8 | runs-on: ubuntu-latest 9 | if: | 10 | ( 11 | github.event.pull_request.user.login == 'dependabot[bot]' || 12 | github.event.pull_request.user.login == 'dependabot' || 13 | github.event.pull_request.user.login == 'dependabot-preview[bot]' || 14 | github.event.pull_request.user.login == 'dependabot-preview' || 15 | github.event.pull_request.user.login == 'renovate[bot]' || 16 | github.event.pull_request.user.login == 'renovate' || 17 | github.event.pull_request.user.login == 'github-actions[bot]' || 18 | github.event.pull_request.user.login == 'pre-commit-ci' || 19 | github.event.pull_request.user.login == 'pre-commit-ci[bot]' 20 | ) 21 | && 22 | ( 23 | github.actor == 'dependabot[bot]' || 24 | github.actor == 'dependabot' || 25 | github.actor == 'dependabot-preview[bot]' || 26 | github.actor == 'dependabot-preview' || 27 | github.actor == 'renovate[bot]' || 28 | github.actor == 'renovate' || 29 | github.actor == 'github-actions[bot]' || 30 | github.actor == 'pre-commit-ci' || 31 | github.actor == 'pre-commit-ci[bot]' 32 | ) 33 | steps: 34 | - uses: hmarr/auto-approve-action@v4 35 | with: 36 | github-token: ${{ secrets.PAT_TOKEN }} 37 | -------------------------------------------------------------------------------- /.github/workflows/auto-merge.yml: -------------------------------------------------------------------------------- 1 | name: automerge 2 | on: 3 | check_suite: 4 | types: 5 | - completed 6 | 7 | jobs: 8 | automerge: 9 | runs-on: ubuntu-latest 10 | if: | 11 | github.actor == 'dependabot[bot]' || 12 | github.actor == 'dependabot' || 13 | github.actor == 'dependabot-preview[bot]' || 14 | github.actor == 'dependabot-preview' || 15 | github.actor == 'renovate[bot]' || 16 | github.actor == 'renovate' 17 | steps: 18 | - name: automerge 19 | uses: pascalgn/automerge-action@v0.16.4 20 | env: 21 | GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }} 22 | MERGE_METHOD: "rebase" 23 | UPDATE_METHOD: "rebase" 24 | MERGE_RETRIES: "6" 25 | MERGE_RETRY_SLEEP: "100000" 26 | MERGE_LABELS: "" 27 | -------------------------------------------------------------------------------- /.github/workflows/codacy-analysis.yml: -------------------------------------------------------------------------------- 1 | # This workflow checks out code, performs a Codacy security scan 2 | # and integrates the results with the 3 | # GitHub Advanced Security code scanning feature. For more information on 4 | # the Codacy security scan action usage and parameters, see 5 | # https://github.com/codacy/codacy-analysis-cli-action. 6 | # For more information on Codacy Analysis CLI in general, see 7 | # https://github.com/codacy/codacy-analysis-cli. 8 | 9 | name: Codacy Security Scan 10 | 11 | on: 12 | push: 13 | branches: [ main ] 14 | pull_request: 15 | # The branches below must be a subset of the branches above 16 | branches: [ main ] 17 | schedule: 18 | - cron: '15 16 * * 2' 19 | 20 | jobs: 21 | codacy-security-scan: 22 | name: Codacy Security Scan 23 | runs-on: ubuntu-latest 24 | steps: 25 | # Checkout the repository to the GitHub Actions runner 26 | - name: Checkout code 27 | uses: actions/checkout@v4 28 | 29 | # Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis 30 | - name: Run Codacy Analysis CLI 31 | uses: codacy/codacy-analysis-cli-action@v4.4.5 32 | with: 33 | # Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository 34 | # You can also omit the token and run the tools that support default configurations 35 | project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} 36 | verbose: true 37 | output: results.sarif 38 | format: sarif 39 | # Adjust severity of non-security issues 40 | gh-code-scanning-compat: true 41 | # Force 0 exit code to allow SARIF file generation 42 | # This will handover control about PR rejection to the GitHub side 43 | max-allowed-issues: 2147483647 44 | 45 | # Upload the SARIF file generated in the previous step 46 | - name: Upload SARIF results file 47 | uses: github/codeql-action/upload-sarif@v3 48 | with: 49 | sarif_file: results.sarif 50 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Upload Python Package 2 | 3 | on: 4 | release: 5 | types: [created] 6 | 7 | jobs: 8 | deploy: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | with: 13 | fetch-depth: 0 14 | 15 | - name: Run semver-diff 16 | id: semver-diff 17 | uses: tj-actions/semver-diff@v3.0.1 18 | 19 | - name: Set up Python 20 | uses: actions/setup-python@v5 21 | with: 22 | python-version: '3.13.x' 23 | 24 | - name: Upgrade pip 25 | run: | 26 | pip install -U pip 27 | 28 | - name: Install dependencies 29 | run: make install-deploy 30 | 31 | - name: Setup git 32 | run: | 33 | git config --local user.email "github-actions[bot]@users.noreply.github.com" 34 | git config --local user.name "github-actions[bot]" 35 | 36 | - name: bumpversion 37 | run: | 38 | make increase-version PART="${{ steps.semver-diff.outputs.release_type }}" 39 | 40 | - name: Build and publish 41 | run: make release 42 | env: 43 | TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} 44 | TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} 45 | 46 | - name: Generate CHANGELOG 47 | uses: tj-actions/github-changelog-generator@v1.21 48 | 49 | - name: Create Pull Request 50 | uses: peter-evans/create-pull-request@v7 51 | with: 52 | base: "main" 53 | title: "Upgraded ${{ steps.semver-diff.outputs.old_version }} → ${{ steps.semver-diff.outputs.new_version }}" 54 | branch: "chore/upgrade-${{ steps.semver-diff.outputs.old_version }}-to-${{ steps.semver-diff.outputs.new_version }}" 55 | commit-message: "Upgraded from ${{ steps.semver-diff.outputs.old_version }} → ${{ steps.semver-diff.outputs.new_version }}" 56 | body: "View [CHANGES](https://github.com/${{ github.repository }}/compare/${{ steps.semver-diff.outputs.old_version }}...${{ steps.semver-diff.outputs.new_version }})" 57 | token: ${{ secrets.PAT_TOKEN }} 58 | -------------------------------------------------------------------------------- /.github/workflows/greetings.yml: -------------------------------------------------------------------------------- 1 | name: Greetings 2 | 3 | on: [pull_request_target, issues] 4 | 5 | jobs: 6 | greeting: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/first-interaction@v1 10 | with: 11 | repo-token: ${{ secrets.GITHUB_TOKEN }} 12 | issue-message: "Thanks for reporting this issue, don't forget to star this project if you haven't already to help us reach a wider audience." 13 | pr-message: "Thanks for implementing a fix, could you ensure that the test covers your changes if applicable." 14 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | - '**' 11 | 12 | jobs: 13 | cleanup-runs: 14 | runs-on: ubuntu-latest 15 | if: "!startsWith(github.ref, 'refs/tags/') && !endsWith(github.ref, 'main')" 16 | steps: 17 | - uses: rokroskar/workflow-run-cleanup-action@v0.3.3 18 | env: 19 | GITHUB_TOKEN: ${{ github.token }} 20 | 21 | build: 22 | runs-on: ${{ matrix.platform }} 23 | strategy: 24 | fail-fast: false 25 | max-parallel: 10 26 | matrix: 27 | platform: [ubuntu-latest, macos-latest, windows-latest] 28 | python-version: [3.7, 3.8, 3.9, '3.10', 3.11] 29 | exclude: 30 | - platform: macos-latest 31 | python-version: 3.11 32 | - platform: macos-latest 33 | python-version: 3.7 34 | - platform: windows-latest 35 | python-version: 3.11 36 | - platform: ubuntu-latest 37 | python-version: 3.7 38 | 39 | steps: 40 | - uses: actions/checkout@v4 41 | with: 42 | submodules: true 43 | fetch-depth: 0 44 | 45 | - name: Set up Python ${{ matrix.python-version }} 46 | uses: actions/setup-python@v5 47 | with: 48 | python-version: ${{ matrix.python-version }} 49 | 50 | - uses: actions/cache@v4 51 | id: pip-cache 52 | with: 53 | path: ~/.cache/pip 54 | key: ${{ runner.os }}-${{ matrix.platform }}-pip-${{ matrix.python-version }}-${{ hashFiles('requirements.txt') }} 55 | restore-keys: | 56 | ${{ runner.os }}-${{ matrix.platform }}-pip-${{ matrix.python-version }}- 57 | 58 | - name: Update branches 59 | run: | 60 | git fetch origin feature/migration-test-01:feature/migration-test-01 61 | git fetch origin feature/migration-test-02:feature/migration-test-02 62 | git fetch origin feature/migration-test-03:feature/migration-test-03 63 | git fetch origin feature/migration-test-04:feature/migration-test-04 64 | git fetch origin feature/migration-test-05:feature/migration-test-05 65 | working-directory: migration_fixer/tests/demo 66 | 67 | - name: Install dependencies 68 | run: | 69 | make install-test 70 | 71 | - name: Checkout feature/migration-test-01 72 | run: | 73 | git checkout feature/migration-test-01 74 | working-directory: migration_fixer/tests/demo 75 | 76 | - name: Run test 77 | run: make tox 78 | continue-on-error: true 79 | env: 80 | CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }} 81 | PLATFORM: ${{ matrix.platform }} 82 | 83 | - name: Run codacy-coverage-reporter 84 | uses: codacy/codacy-coverage-reporter-action@v1 85 | continue-on-error: true 86 | if: github.actor != 'dependabot[bot]' && github.actor != 'dependabot' && matrix.python-version == '3.9' 87 | with: 88 | project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} 89 | coverage-reports: coverage.xml 90 | 91 | - name: "Upload coverage to Codecov" 92 | uses: codecov/codecov-action@v5.4.3 93 | if: github.actor != 'dependabot[bot]' && github.actor != 'dependabot' && matrix.python-version == '3.9' 94 | with: 95 | token: ${{ secrets.CODECOV_TOKEN }} 96 | fail_ci_if_error: false 97 | -------------------------------------------------------------------------------- /.github/workflows/update-doc-assets.yml: -------------------------------------------------------------------------------- 1 | name: Sync doc assets 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | sync-doc-assets: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4.2.2 13 | with: 14 | fetch-depth: 0 15 | 16 | - name: Run test 17 | uses: tj-actions/remark@v3 18 | 19 | - name: Verify Changed files 20 | uses: tj-actions/verify-changed-files@v20 21 | id: verify_changed_files 22 | with: 23 | files: | 24 | README.md 25 | 26 | - name: README.md changed 27 | if: steps.verify_changed_files.outputs.files_changed == 'true' 28 | run: | 29 | echo "README.md has uncommited changes" 30 | exit 1 31 | 32 | - name: Create Pull Request 33 | if: failure() 34 | uses: peter-evans/create-pull-request@v7 35 | with: 36 | base: "main" 37 | title: "Updated README.md" 38 | branch: "chore/update-readme" 39 | commit-message: "Updated README.md" 40 | body: "Updated README.md" 41 | token: ${{ secrets.PAT_TOKEN }} 42 | 43 | - name: Copy doc assets 44 | run: | 45 | sed 's|./docs/images|./images|g' README.md > docs/README.md 46 | cp -f CHANGELOG.md docs/CHANGELOG.md 47 | 48 | - name: Set up Python 49 | uses: actions/setup-python@v5 50 | with: 51 | python-version: '3.13.x' 52 | 53 | - name: Upgrade pip 54 | run: | 55 | pip install -U pip 56 | 57 | - name: Install dependencies 58 | run: make install-docs 59 | 60 | - name: Deploy to github pages 61 | run: | 62 | make github-pages 63 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | 58 | # Flask stuff: 59 | instance/ 60 | .webassets-cache 61 | 62 | # Scrapy stuff: 63 | .scrapy 64 | 65 | # Sphinx documentation 66 | docs/_build/ 67 | 68 | # PyBuilder 69 | target/ 70 | 71 | # Jupyter Notebook 72 | .ipynb_checkpoints 73 | 74 | # pyenv 75 | .python-version 76 | 77 | # celery beat schedule file 78 | celerybeat-schedule 79 | 80 | # SageMath parsed files 81 | *.sage.py 82 | 83 | # dotenv 84 | .env 85 | 86 | # virtualenv 87 | .venv 88 | venv/ 89 | ENV/ 90 | 91 | # Spyder project settings 92 | .spyderproject 93 | .spyproject 94 | 95 | # Rope project settings 96 | .ropeproject 97 | 98 | # mkdocs documentation 99 | /site 100 | 101 | # mypy 102 | .mypy_cache/ 103 | 104 | # IDE settings 105 | .vscode/ 106 | 107 | # Pycharm 108 | .idea/ 109 | 110 | .eggs 111 | 112 | *.db 113 | 114 | *.sqlite3 115 | 116 | site/ 117 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "migration_fixer/tests/demo"] 2 | path = migration_fixer/tests/demo 3 | url = git@github.com:tj-django/demo.git 4 | -------------------------------------------------------------------------------- /.pep8speaks.yml: -------------------------------------------------------------------------------- 1 | scanner: 2 | diff_only: True # If False, the entire file touched by the Pull Request is scanned for errors. If True, only the diff is scanned. 3 | linter: pycodestyle 4 | 5 | pycodestyle: # Same as scanner.linter value. Other option is flake8 6 | max-line-length: 100 # Default is 79 in PEP 8 7 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/PyCQA/autoflake 3 | rev: v2.3.1 4 | hooks: 5 | - id: autoflake 6 | args: ['--in-place', '--remove-all-unused-imports', '--remove-unused-variable'] 7 | 8 | - repo: https://github.com/pycqa/isort 9 | rev: 5.13.2 10 | hooks: 11 | - id: isort 12 | args: ["--profile", "black", "--filter-files"] 13 | 14 | - repo: https://github.com/pre-commit/pre-commit-hooks 15 | rev: v5.0.0 16 | hooks: 17 | - id: trailing-whitespace 18 | exclude: ^docs/.*|.*.md 19 | - id: end-of-file-fixer 20 | exclude: ^docs/.*|.*.md 21 | 22 | - repo: https://github.com/psf/black 23 | rev: 24.10.0 24 | hooks: 25 | - id: black 26 | language_version: python3 27 | 28 | - repo: https://github.com/adrienverge/yamllint.git 29 | rev: v1.35.1 30 | hooks: 31 | - id: yamllint 32 | args: ["-d", "relaxed"] 33 | 34 | - repo: https://github.com/pycqa/flake8 35 | rev: 7.1.1 36 | hooks: 37 | - id: flake8 38 | -------------------------------------------------------------------------------- /.pyup.yml: -------------------------------------------------------------------------------- 1 | # autogenerated pyup.io config file 2 | # see https://pyup.io/docs/configuration/ for all available options 3 | 4 | schedule: '' 5 | update: False 6 | -------------------------------------------------------------------------------- /.whitesource: -------------------------------------------------------------------------------- 1 | { 2 | "scanSettings": { 3 | "baseBranches": [] 4 | }, 5 | "checkRunSettings": { 6 | "vulnerableCheckRunConclusionLevel": "failure", 7 | "displayMode": "diff" 8 | }, 9 | "issueSettings": { 10 | "minSeverityLevel": "LOW" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [v1.3.6](https://github.com/tj-django/django-migration-fixer/tree/v1.3.6) (2022-09-30) 4 | 5 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v1.3.5...v1.3.6) 6 | 7 | **Closed issues:** 8 | 9 | - Dependency Dashboard [\#40](https://github.com/tj-django/django-migration-fixer/issues/40) 10 | 11 | **Merged pull requests:** 12 | 13 | - chore\(deps\): update dependency pymdown-extensions to \>=9.6,\<9.7 [\#272](https://github.com/tj-django/django-migration-fixer/pull/272) ([renovate[bot]](https://github.com/apps/renovate)) 14 | - chore\(deps\): update dependency mkdocs to \>=1.4,\<1.5 [\#271](https://github.com/tj-django/django-migration-fixer/pull/271) ([renovate[bot]](https://github.com/apps/renovate)) 15 | - \[pre-commit.ci\] pre-commit autoupdate [\#270](https://github.com/tj-django/django-migration-fixer/pull/270) ([pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci)) 16 | - chore\(deps\): update dependency sqlparse to v0.4.3 [\#269](https://github.com/tj-django/django-migration-fixer/pull/269) ([renovate[bot]](https://github.com/apps/renovate)) 17 | - chore\(deps\): update codacy/codacy-analysis-cli-action action to v4.2.0 [\#268](https://github.com/tj-django/django-migration-fixer/pull/268) ([renovate[bot]](https://github.com/apps/renovate)) 18 | - chore\(deps\): update tj-actions/semver-diff action to v2.1.0 [\#267](https://github.com/tj-django/django-migration-fixer/pull/267) ([renovate[bot]](https://github.com/apps/renovate)) 19 | - chore\(deps\): update codecov/codecov-action action to v3.1.1 [\#266](https://github.com/tj-django/django-migration-fixer/pull/266) ([renovate[bot]](https://github.com/apps/renovate)) 20 | - chore\(deps\): update tj-actions/github-changelog-generator action to v1.15 [\#265](https://github.com/tj-django/django-migration-fixer/pull/265) ([renovate[bot]](https://github.com/apps/renovate)) 21 | - chore\(deps\): update dependency pymdown-extensions to \>=9.5,\<9.6 [\#264](https://github.com/tj-django/django-migration-fixer/pull/264) ([renovate[bot]](https://github.com/apps/renovate)) 22 | - chore\(deps\): update dependency django to v4.1.1 [\#263](https://github.com/tj-django/django-migration-fixer/pull/263) ([renovate[bot]](https://github.com/apps/renovate)) 23 | - chore\(deps\): update wearerequired/lint-action action to v2.1.0 [\#262](https://github.com/tj-django/django-migration-fixer/pull/262) ([renovate[bot]](https://github.com/apps/renovate)) 24 | - \[pre-commit.ci\] pre-commit autoupdate [\#261](https://github.com/tj-django/django-migration-fixer/pull/261) ([pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci)) 25 | - Bump tj-actions/verify-changed-files from 10 to 11 [\#260](https://github.com/tj-django/django-migration-fixer/pull/260) ([dependabot[bot]](https://github.com/apps/dependabot)) 26 | - chore\(deps\): update dependency pygments to \>=2.13,\<2.14 [\#259](https://github.com/tj-django/django-migration-fixer/pull/259) ([renovate[bot]](https://github.com/apps/renovate)) 27 | - chore\(deps\): update dependency pytz to v2022.2.1 [\#258](https://github.com/tj-django/django-migration-fixer/pull/258) ([renovate[bot]](https://github.com/apps/renovate)) 28 | - chore\(deps\): update dependency pytz to v2022.2 [\#257](https://github.com/tj-django/django-migration-fixer/pull/257) ([renovate[bot]](https://github.com/apps/renovate)) 29 | - Bump django from 4.0.6 to 4.1 [\#256](https://github.com/tj-django/django-migration-fixer/pull/256) ([dependabot[bot]](https://github.com/apps/dependabot)) 30 | - chore\(deps\): update wearerequired/lint-action action to v2.0.1 [\#255](https://github.com/tj-django/django-migration-fixer/pull/255) ([renovate[bot]](https://github.com/apps/renovate)) 31 | - Bump django from 4.0.5 to 4.0.6 [\#254](https://github.com/tj-django/django-migration-fixer/pull/254) ([dependabot[bot]](https://github.com/apps/dependabot)) 32 | - chore\(deps\): update dependency typing-extensions to v4.3.0 [\#253](https://github.com/tj-django/django-migration-fixer/pull/253) ([renovate[bot]](https://github.com/apps/renovate)) 33 | - Bump tj-actions/github-changelog-generator from 1.13 to 1.14 [\#252](https://github.com/tj-django/django-migration-fixer/pull/252) ([dependabot[bot]](https://github.com/apps/dependabot)) 34 | - Bump tj-actions/verify-changed-files from 9 to 10 [\#251](https://github.com/tj-django/django-migration-fixer/pull/251) ([dependabot[bot]](https://github.com/apps/dependabot)) 35 | - chore\(deps\): update codacy/codacy-analysis-cli-action action to v4.1.0 [\#250](https://github.com/tj-django/django-migration-fixer/pull/250) ([renovate[bot]](https://github.com/apps/renovate)) 36 | - \[pre-commit.ci\] pre-commit autoupdate [\#249](https://github.com/tj-django/django-migration-fixer/pull/249) ([pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci)) 37 | - chore\(deps\): update tj-actions/semver-diff action to v2 [\#248](https://github.com/tj-django/django-migration-fixer/pull/248) ([renovate[bot]](https://github.com/apps/renovate)) 38 | - chore\(deps\): update actions/setup-python action to v4 [\#247](https://github.com/tj-django/django-migration-fixer/pull/247) ([renovate[bot]](https://github.com/apps/renovate)) 39 | - Revert "chore\(deps\): update dependency pymdown-extensions to \>=9.5,\<9.6" [\#246](https://github.com/tj-django/django-migration-fixer/pull/246) ([jackton1](https://github.com/jackton1)) 40 | - chore\(deps\): update dependency pymdown-extensions to \>=9.5,\<9.6 [\#245](https://github.com/tj-django/django-migration-fixer/pull/245) ([renovate[bot]](https://github.com/apps/renovate)) 41 | - chore\(deps\): update dependency django to v4.0.5 [\#244](https://github.com/tj-django/django-migration-fixer/pull/244) ([renovate[bot]](https://github.com/apps/renovate)) 42 | - chore\(deps\): update dependency pymdown-extensions to \>=9.4,\<9.5 [\#243](https://github.com/tj-django/django-migration-fixer/pull/243) ([renovate[bot]](https://github.com/apps/renovate)) 43 | - chore\(deps\): update dependency pygments to \>=2.12,\<2.13 [\#242](https://github.com/tj-django/django-migration-fixer/pull/242) ([renovate[bot]](https://github.com/apps/renovate)) 44 | - Update README.md [\#241](https://github.com/tj-django/django-migration-fixer/pull/241) ([jackton1](https://github.com/jackton1)) 45 | - chore\(deps\): update dependency asgiref to v3.5.2 [\#240](https://github.com/tj-django/django-migration-fixer/pull/240) ([renovate[bot]](https://github.com/apps/renovate)) 46 | - chore\(deps\): update pascalgn/automerge-action action to v0.15.3 [\#239](https://github.com/tj-django/django-migration-fixer/pull/239) ([renovate[bot]](https://github.com/apps/renovate)) 47 | - chore\(deps\): update dependency asgiref to v3.5.1 [\#238](https://github.com/tj-django/django-migration-fixer/pull/238) ([renovate[bot]](https://github.com/apps/renovate)) 48 | - chore\(deps\): update wearerequired/lint-action action to v2 [\#237](https://github.com/tj-django/django-migration-fixer/pull/237) ([renovate[bot]](https://github.com/apps/renovate)) 49 | - chore\(deps\): update github/codeql-action action to v2 [\#236](https://github.com/tj-django/django-migration-fixer/pull/236) ([renovate[bot]](https://github.com/apps/renovate)) 50 | - Update codecov/codecov-action action to v3.1.0 [\#235](https://github.com/tj-django/django-migration-fixer/pull/235) ([renovate[bot]](https://github.com/apps/renovate)) 51 | - Update actions/checkout action to v3.0.2 [\#234](https://github.com/tj-django/django-migration-fixer/pull/234) ([renovate[bot]](https://github.com/apps/renovate)) 52 | - Update dependency typing-extensions to v4.2.0 [\#233](https://github.com/tj-django/django-migration-fixer/pull/233) ([renovate[bot]](https://github.com/apps/renovate)) 53 | - Update actions/checkout action to v3.0.1 [\#232](https://github.com/tj-django/django-migration-fixer/pull/232) ([renovate[bot]](https://github.com/apps/renovate)) 54 | - \[pre-commit.ci\] pre-commit autoupdate [\#231](https://github.com/tj-django/django-migration-fixer/pull/231) ([pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci)) 55 | - Bump django from 4.0.3 to 4.0.4 [\#230](https://github.com/tj-django/django-migration-fixer/pull/230) ([dependabot[bot]](https://github.com/apps/dependabot)) 56 | - Update codecov/codecov-action action to v3 [\#229](https://github.com/tj-django/django-migration-fixer/pull/229) ([renovate[bot]](https://github.com/apps/renovate)) 57 | - Update dependency mkdocs to \<1.4 [\#228](https://github.com/tj-django/django-migration-fixer/pull/228) ([renovate[bot]](https://github.com/apps/renovate)) 58 | - chore: update setup.py [\#227](https://github.com/tj-django/django-migration-fixer/pull/227) ([jackton1](https://github.com/jackton1)) 59 | - \[pre-commit.ci\] pre-commit autoupdate [\#226](https://github.com/tj-django/django-migration-fixer/pull/226) ([pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci)) 60 | - Update dependency mkdocs to v1.3.0 [\#225](https://github.com/tj-django/django-migration-fixer/pull/225) ([renovate[bot]](https://github.com/apps/renovate)) 61 | - Update pascalgn/automerge-action action to v0.15.2 [\#224](https://github.com/tj-django/django-migration-fixer/pull/224) ([renovate[bot]](https://github.com/apps/renovate)) 62 | - Update pascalgn/automerge-action action to v0.14.4 [\#223](https://github.com/tj-django/django-migration-fixer/pull/223) ([renovate[bot]](https://github.com/apps/renovate)) 63 | - Update peter-evans/create-pull-request action to v4 [\#222](https://github.com/tj-django/django-migration-fixer/pull/222) ([renovate[bot]](https://github.com/apps/renovate)) 64 | - Update tj-actions/semver-diff action to v1.2.1 [\#221](https://github.com/tj-django/django-migration-fixer/pull/221) ([renovate[bot]](https://github.com/apps/renovate)) 65 | - Update wearerequired/lint-action action to v1.12.0 [\#220](https://github.com/tj-django/django-migration-fixer/pull/220) ([renovate[bot]](https://github.com/apps/renovate)) 66 | - Bump actions/cache from 2 to 3 [\#219](https://github.com/tj-django/django-migration-fixer/pull/219) ([dependabot[bot]](https://github.com/apps/dependabot)) 67 | - Updated README.md [\#218](https://github.com/tj-django/django-migration-fixer/pull/218) ([jackton1](https://github.com/jackton1)) 68 | - Updated README.md [\#217](https://github.com/tj-django/django-migration-fixer/pull/217) ([jackton1](https://github.com/jackton1)) 69 | - Update dependency pytz to v2022 [\#216](https://github.com/tj-django/django-migration-fixer/pull/216) ([renovate[bot]](https://github.com/apps/renovate)) 70 | - Bump tj-actions/remark from 2.3 to 3 [\#215](https://github.com/tj-django/django-migration-fixer/pull/215) ([dependabot[bot]](https://github.com/apps/dependabot)) 71 | - Update tj-actions/github-changelog-generator action to v1.13 [\#214](https://github.com/tj-django/django-migration-fixer/pull/214) ([renovate[bot]](https://github.com/apps/renovate)) 72 | - Update tj-actions/verify-changed-files action to v9 [\#212](https://github.com/tj-django/django-migration-fixer/pull/212) ([renovate[bot]](https://github.com/apps/renovate)) 73 | - Update codacy/codacy-analysis-cli-action action to v4.0.2 [\#211](https://github.com/tj-django/django-migration-fixer/pull/211) ([renovate[bot]](https://github.com/apps/renovate)) 74 | - Update codacy/codacy-analysis-cli-action action to v4.0.1 [\#210](https://github.com/tj-django/django-migration-fixer/pull/210) ([renovate[bot]](https://github.com/apps/renovate)) 75 | - Update actions/checkout action [\#209](https://github.com/tj-django/django-migration-fixer/pull/209) ([renovate[bot]](https://github.com/apps/renovate)) 76 | - Update dependency django to v4.0.3 [\#208](https://github.com/tj-django/django-migration-fixer/pull/208) ([renovate[bot]](https://github.com/apps/renovate)) 77 | - Update actions/setup-python action to v3 [\#206](https://github.com/tj-django/django-migration-fixer/pull/206) ([renovate[bot]](https://github.com/apps/renovate)) 78 | - Update tj-actions/github-changelog-generator action to v1.12 [\#205](https://github.com/tj-django/django-migration-fixer/pull/205) ([renovate[bot]](https://github.com/apps/renovate)) 79 | - Bump gitpython from 3.1.26 to 3.1.27 [\#204](https://github.com/tj-django/django-migration-fixer/pull/204) ([dependabot[bot]](https://github.com/apps/dependabot)) 80 | - Update dependency typing-extensions to v4.1.1 [\#201](https://github.com/tj-django/django-migration-fixer/pull/201) ([renovate[bot]](https://github.com/apps/renovate)) 81 | - Update dependency typing-extensions to v4.1.0 [\#200](https://github.com/tj-django/django-migration-fixer/pull/200) ([renovate[bot]](https://github.com/apps/renovate)) 82 | - Updated README.md [\#198](https://github.com/tj-django/django-migration-fixer/pull/198) ([jackton1](https://github.com/jackton1)) 83 | - Upgraded v1.3.4 → v1.3.5 [\#197](https://github.com/tj-django/django-migration-fixer/pull/197) ([jackton1](https://github.com/jackton1)) 84 | 85 | ## [v1.3.5](https://github.com/tj-django/django-migration-fixer/tree/v1.3.5) (2022-02-06) 86 | 87 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v1.3.4...v1.3.5) 88 | 89 | **Closed issues:** 90 | 91 | - WS-2021-0369 \(Medium\) detected in sqlparse-0.4.1-py3-none-any.whl - autoclosed [\#152](https://github.com/tj-django/django-migration-fixer/issues/152) 92 | 93 | **Merged pull requests:** 94 | 95 | - Update actions/setup-python action to v2.3.2 [\#196](https://github.com/tj-django/django-migration-fixer/pull/196) ([renovate[bot]](https://github.com/apps/renovate)) 96 | - Update dependency django to v4.0.2 [\#195](https://github.com/tj-django/django-migration-fixer/pull/195) ([renovate[bot]](https://github.com/apps/renovate)) 97 | - \[pre-commit.ci\] pre-commit autoupdate [\#194](https://github.com/tj-django/django-migration-fixer/pull/194) ([pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci)) 98 | - Update dependency asgiref to v3.5.0 [\#193](https://github.com/tj-django/django-migration-fixer/pull/193) ([renovate[bot]](https://github.com/apps/renovate)) 99 | - Update wearerequired/lint-action action to v1.11.1 [\#192](https://github.com/tj-django/django-migration-fixer/pull/192) ([renovate[bot]](https://github.com/apps/renovate)) 100 | - Update wearerequired/lint-action action to v1.11.0 [\#191](https://github.com/tj-django/django-migration-fixer/pull/191) ([renovate[bot]](https://github.com/apps/renovate)) 101 | - Update dependency gitpython to v3.1.26 [\#190](https://github.com/tj-django/django-migration-fixer/pull/190) ([renovate[bot]](https://github.com/apps/renovate)) 102 | - Update dependency gitpython to v3.1.25 [\#189](https://github.com/tj-django/django-migration-fixer/pull/189) ([renovate[bot]](https://github.com/apps/renovate)) 103 | - Update dependency django to v4.0.1 [\#188](https://github.com/tj-django/django-migration-fixer/pull/188) ([renovate[bot]](https://github.com/apps/renovate)) 104 | - Update tj-actions/remark action to v2.3 [\#187](https://github.com/tj-django/django-migration-fixer/pull/187) ([renovate[bot]](https://github.com/apps/renovate)) 105 | - Update tj-actions/remark action to v2 [\#186](https://github.com/tj-django/django-migration-fixer/pull/186) ([renovate[bot]](https://github.com/apps/renovate)) 106 | - Update tj-actions/github-changelog-generator action to v1.11 [\#185](https://github.com/tj-django/django-migration-fixer/pull/185) ([renovate[bot]](https://github.com/apps/renovate)) 107 | - Update tj-actions/github-changelog-generator action to v1.10 [\#184](https://github.com/tj-django/django-migration-fixer/pull/184) ([renovate[bot]](https://github.com/apps/renovate)) 108 | - \[pre-commit.ci\] pre-commit autoupdate [\#183](https://github.com/tj-django/django-migration-fixer/pull/183) ([pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci)) 109 | - Update dependency django to v4 [\#182](https://github.com/tj-django/django-migration-fixer/pull/182) ([renovate[bot]](https://github.com/apps/renovate)) 110 | - Bump django from 3.2.9 to 3.2.10 [\#181](https://github.com/tj-django/django-migration-fixer/pull/181) ([dependabot[bot]](https://github.com/apps/dependabot)) 111 | - \[pre-commit.ci\] pre-commit autoupdate [\#180](https://github.com/tj-django/django-migration-fixer/pull/180) ([pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci)) 112 | - Update dependency typing-extensions to v4.0.1 [\#179](https://github.com/tj-django/django-migration-fixer/pull/179) ([renovate[bot]](https://github.com/apps/renovate)) 113 | - Update actions/setup-python action to v2.3.1 [\#178](https://github.com/tj-django/django-migration-fixer/pull/178) ([renovate[bot]](https://github.com/apps/renovate)) 114 | - \[pre-commit.ci\] pre-commit autoupdate [\#177](https://github.com/tj-django/django-migration-fixer/pull/177) ([pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci)) 115 | - Update actions/setup-python action to v2.3.0 [\#176](https://github.com/tj-django/django-migration-fixer/pull/176) ([renovate[bot]](https://github.com/apps/renovate)) 116 | - \[pre-commit.ci\] pre-commit autoupdate [\#175](https://github.com/tj-django/django-migration-fixer/pull/175) ([pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci)) 117 | - Update dependency typing-extensions to v4 [\#174](https://github.com/tj-django/django-migration-fixer/pull/174) ([renovate[bot]](https://github.com/apps/renovate)) 118 | - \[pre-commit.ci\] pre-commit autoupdate [\#173](https://github.com/tj-django/django-migration-fixer/pull/173) ([pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci)) 119 | - Updated README.md [\#172](https://github.com/tj-django/django-migration-fixer/pull/172) ([jackton1](https://github.com/jackton1)) 120 | - Update actions/checkout action to v2.4.0 [\#170](https://github.com/tj-django/django-migration-fixer/pull/170) ([renovate[bot]](https://github.com/apps/renovate)) 121 | - \[pre-commit.ci\] pre-commit autoupdate [\#169](https://github.com/tj-django/django-migration-fixer/pull/169) ([pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci)) 122 | - Updated README.md [\#168](https://github.com/tj-django/django-migration-fixer/pull/168) ([jackton1](https://github.com/jackton1)) 123 | - Update dependency django to v3.2.9 [\#167](https://github.com/tj-django/django-migration-fixer/pull/167) ([renovate[bot]](https://github.com/apps/renovate)) 124 | - Update dependency gitdb to v4.0.9 [\#166](https://github.com/tj-django/django-migration-fixer/pull/166) ([renovate[bot]](https://github.com/apps/renovate)) 125 | - Update dependency gitdb to v4.0.8 [\#165](https://github.com/tj-django/django-migration-fixer/pull/165) ([renovate[bot]](https://github.com/apps/renovate)) 126 | - Update actions/checkout action to v2.3.5 [\#164](https://github.com/tj-django/django-migration-fixer/pull/164) ([renovate[bot]](https://github.com/apps/renovate)) 127 | - Update dependency smmap to v5 [\#163](https://github.com/tj-django/django-migration-fixer/pull/163) ([renovate[bot]](https://github.com/apps/renovate)) 128 | - Update dependency mkdocs to v1.2.3 [\#161](https://github.com/tj-django/django-migration-fixer/pull/161) ([renovate[bot]](https://github.com/apps/renovate)) 129 | - Update dependency django to v3.2.8 [\#159](https://github.com/tj-django/django-migration-fixer/pull/159) ([renovate[bot]](https://github.com/apps/renovate)) 130 | - Update tj-actions/verify-changed-files action to v8 [\#158](https://github.com/tj-django/django-migration-fixer/pull/158) ([renovate[bot]](https://github.com/apps/renovate)) 131 | - Update dependency pytz to v2021.3 [\#157](https://github.com/tj-django/django-migration-fixer/pull/157) ([renovate[bot]](https://github.com/apps/renovate)) 132 | - \[pre-commit.ci\] pre-commit autoupdate [\#156](https://github.com/tj-django/django-migration-fixer/pull/156) ([pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci)) 133 | - Updated README.md [\#155](https://github.com/tj-django/django-migration-fixer/pull/155) ([jackton1](https://github.com/jackton1)) 134 | - Update dependency gitpython to v3.1.24 [\#154](https://github.com/tj-django/django-migration-fixer/pull/154) ([renovate[bot]](https://github.com/apps/renovate)) 135 | - Updated requirements.txt and fixed Makefile. [\#153](https://github.com/tj-django/django-migration-fixer/pull/153) ([jackton1](https://github.com/jackton1)) 136 | - Update codecov/codecov-action action to v2.1.0 [\#151](https://github.com/tj-django/django-migration-fixer/pull/151) ([renovate[bot]](https://github.com/apps/renovate)) 137 | - Updated README.md [\#150](https://github.com/tj-django/django-migration-fixer/pull/150) ([jackton1](https://github.com/jackton1)) 138 | - Upgraded v1.3.3 → v1.3.4 [\#149](https://github.com/tj-django/django-migration-fixer/pull/149) ([jackton1](https://github.com/jackton1)) 139 | 140 | ## [v1.3.4](https://github.com/tj-django/django-migration-fixer/tree/v1.3.4) (2021-09-04) 141 | 142 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v1.3.3...v1.3.4) 143 | 144 | **Merged pull requests:** 145 | 146 | - Removed unused code [\#148](https://github.com/tj-django/django-migration-fixer/pull/148) ([jackton1](https://github.com/jackton1)) 147 | - Upgraded v1.3.2 → v1.3.3 [\#147](https://github.com/tj-django/django-migration-fixer/pull/147) ([jackton1](https://github.com/jackton1)) 148 | 149 | ## [v1.3.3](https://github.com/tj-django/django-migration-fixer/tree/v1.3.3) (2021-09-03) 150 | 151 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v1.3.2...v1.3.3) 152 | 153 | **Merged pull requests:** 154 | 155 | - Upgraded v1.3.1 → v1.3.2 [\#146](https://github.com/tj-django/django-migration-fixer/pull/146) ([jackton1](https://github.com/jackton1)) 156 | 157 | ## [v1.3.2](https://github.com/tj-django/django-migration-fixer/tree/v1.3.2) (2021-09-03) 158 | 159 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v1.3.1...v1.3.2) 160 | 161 | **Merged pull requests:** 162 | 163 | - Update pascalgn/automerge-action action to v0.14.3 [\#145](https://github.com/tj-django/django-migration-fixer/pull/145) ([renovate[bot]](https://github.com/apps/renovate)) 164 | - Update checking if running on the current branch [\#144](https://github.com/tj-django/django-migration-fixer/pull/144) ([jackton1](https://github.com/jackton1)) 165 | - Upgraded v1.3.0 → v1.3.1 [\#143](https://github.com/tj-django/django-migration-fixer/pull/143) ([jackton1](https://github.com/jackton1)) 166 | 167 | ## [v1.3.1](https://github.com/tj-django/django-migration-fixer/tree/v1.3.1) (2021-09-03) 168 | 169 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v1.3.0...v1.3.1) 170 | 171 | **Merged pull requests:** 172 | 173 | - Update test.yml [\#142](https://github.com/tj-django/django-migration-fixer/pull/142) ([jackton1](https://github.com/jackton1)) 174 | - Update retrieving the current branch name [\#141](https://github.com/tj-django/django-migration-fixer/pull/141) ([jackton1](https://github.com/jackton1)) 175 | - Update docs. [\#140](https://github.com/tj-django/django-migration-fixer/pull/140) ([jackton1](https://github.com/jackton1)) 176 | - Update dependency Django to v3.2.7 [\#139](https://github.com/tj-django/django-migration-fixer/pull/139) ([renovate[bot]](https://github.com/apps/renovate)) 177 | - \[pre-commit.ci\] pre-commit autoupdate [\#138](https://github.com/tj-django/django-migration-fixer/pull/138) ([pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci)) 178 | - Upgraded v1.2.2 → v1.3.0 [\#137](https://github.com/tj-django/django-migration-fixer/pull/137) ([jackton1](https://github.com/jackton1)) 179 | 180 | ## [v1.3.0](https://github.com/tj-django/django-migration-fixer/tree/v1.3.0) (2021-08-28) 181 | 182 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v1.2.2...v1.3.0) 183 | 184 | **Fixed bugs:** 185 | 186 | - Resolve bug with reseeding migrations. [\#136](https://github.com/tj-django/django-migration-fixer/pull/136) ([jackton1](https://github.com/jackton1)) 187 | 188 | **Merged pull requests:** 189 | 190 | - Update codecov/codecov-action action to v2.0.3 [\#135](https://github.com/tj-django/django-migration-fixer/pull/135) ([renovate[bot]](https://github.com/apps/renovate)) 191 | - Updated README.md [\#134](https://github.com/tj-django/django-migration-fixer/pull/134) ([jackton1](https://github.com/jackton1)) 192 | - Update README.md [\#133](https://github.com/tj-django/django-migration-fixer/pull/133) ([jackton1](https://github.com/jackton1)) 193 | - Upgraded v1.2.1 → v1.2.2 [\#132](https://github.com/tj-django/django-migration-fixer/pull/132) ([jackton1](https://github.com/jackton1)) 194 | 195 | ## [v1.2.2](https://github.com/tj-django/django-migration-fixer/tree/v1.2.2) (2021-08-23) 196 | 197 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v1.2.1...v1.2.2) 198 | 199 | **Fixed bugs:** 200 | 201 | - Support custom migrations base paths [\#126](https://github.com/tj-django/django-migration-fixer/issues/126) 202 | 203 | **Merged pull requests:** 204 | 205 | - Bump tox from 3.24.2 to 3.24.3 [\#131](https://github.com/tj-django/django-migration-fixer/pull/131) ([dependabot[bot]](https://github.com/apps/dependabot)) 206 | - Update tj-actions/remark action to v1.7 [\#130](https://github.com/tj-django/django-migration-fixer/pull/130) ([renovate[bot]](https://github.com/apps/renovate)) 207 | - Upgraded v1.2.0 → v1.2.1 [\#129](https://github.com/tj-django/django-migration-fixer/pull/129) ([jackton1](https://github.com/jackton1)) 208 | - Fix migration path logic for custom migration locations. [\#128](https://github.com/tj-django/django-migration-fixer/pull/128) ([jackton1](https://github.com/jackton1)) 209 | 210 | ## [v1.2.1](https://github.com/tj-django/django-migration-fixer/tree/v1.2.1) (2021-08-22) 211 | 212 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v1.2.0...v1.2.1) 213 | 214 | **Implemented enhancements:** 215 | 216 | - Support fix without fetch/pull [\#125](https://github.com/tj-django/django-migration-fixer/issues/125) 217 | 218 | **Merged pull requests:** 219 | 220 | - Added support to skip pulling remote changes. [\#127](https://github.com/tj-django/django-migration-fixer/pull/127) ([jackton1](https://github.com/jackton1)) 221 | - Bump tox from 3.24.1 to 3.24.2 [\#124](https://github.com/tj-django/django-migration-fixer/pull/124) ([dependabot[bot]](https://github.com/apps/dependabot)) 222 | - Bump wheel from 0.36.2 to 0.37.0 [\#123](https://github.com/tj-django/django-migration-fixer/pull/123) ([dependabot[bot]](https://github.com/apps/dependabot)) 223 | - Upgraded v1.1.4 → v1.2.0 [\#122](https://github.com/tj-django/django-migration-fixer/pull/122) ([jackton1](https://github.com/jackton1)) 224 | 225 | ## [v1.2.0](https://github.com/tj-django/django-migration-fixer/tree/v1.2.0) (2021-08-08) 226 | 227 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v1.1.4...v1.2.0) 228 | 229 | **Merged pull requests:** 230 | 231 | - Increased test coverage. [\#121](https://github.com/tj-django/django-migration-fixer/pull/121) ([jackton1](https://github.com/jackton1)) 232 | - Fix bug editing previous migration files. [\#120](https://github.com/tj-django/django-migration-fixer/pull/120) ([jackton1](https://github.com/jackton1)) 233 | - Upgraded v1.1.3 → v1.1.4 [\#119](https://github.com/tj-django/django-migration-fixer/pull/119) ([jackton1](https://github.com/jackton1)) 234 | 235 | ## [v1.1.4](https://github.com/tj-django/django-migration-fixer/tree/v1.1.4) (2021-08-04) 236 | 237 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v1.1.3...v1.1.4) 238 | 239 | **Fixed bugs:** 240 | 241 | - \[BUG\] Doesn't work with multiple remotes [\#117](https://github.com/tj-django/django-migration-fixer/issues/117) 242 | 243 | **Merged pull requests:** 244 | 245 | - Pull changes from a specific remote defaults to origin [\#118](https://github.com/tj-django/django-migration-fixer/pull/118) ([jackton1](https://github.com/jackton1)) 246 | - Updated README.md [\#116](https://github.com/tj-django/django-migration-fixer/pull/116) ([jackton1](https://github.com/jackton1)) 247 | - Updated README.md [\#115](https://github.com/tj-django/django-migration-fixer/pull/115) ([jackton1](https://github.com/jackton1)) 248 | - Upgraded v1.1.2 → v1.1.3 [\#114](https://github.com/tj-django/django-migration-fixer/pull/114) ([jackton1](https://github.com/jackton1)) 249 | - Updated README.md [\#113](https://github.com/tj-django/django-migration-fixer/pull/113) ([jackton1](https://github.com/jackton1)) 250 | - Updated README.md [\#112](https://github.com/tj-django/django-migration-fixer/pull/112) ([jackton1](https://github.com/jackton1)) 251 | 252 | ## [v1.1.3](https://github.com/tj-django/django-migration-fixer/tree/v1.1.3) (2021-08-02) 253 | 254 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v1.1.2...v1.1.3) 255 | 256 | **Merged pull requests:** 257 | 258 | - Updated README.md [\#109](https://github.com/tj-django/django-migration-fixer/pull/109) ([jackton1](https://github.com/jackton1)) 259 | - Bump tox from 3.24.0 to 3.24.1 [\#107](https://github.com/tj-django/django-migration-fixer/pull/107) ([dependabot[bot]](https://github.com/apps/dependabot)) 260 | - Update dependency Django to v3.2.6 [\#106](https://github.com/tj-django/django-migration-fixer/pull/106) ([renovate[bot]](https://github.com/apps/renovate)) 261 | - Update precommit hook pycqa/isort to v5.9.3 [\#105](https://github.com/tj-django/django-migration-fixer/pull/105) ([renovate[bot]](https://github.com/apps/renovate)) 262 | - Fixed bug with changed\_files [\#104](https://github.com/tj-django/django-migration-fixer/pull/104) ([jackton1](https://github.com/jackton1)) 263 | - Bump twine from 3.4.1 to 3.4.2 [\#103](https://github.com/tj-django/django-migration-fixer/pull/103) ([dependabot[bot]](https://github.com/apps/dependabot)) 264 | - Bump mkdocs from 1.1.2 to 1.2.2 [\#102](https://github.com/tj-django/django-migration-fixer/pull/102) ([dependabot[bot]](https://github.com/apps/dependabot)) 265 | - Bump portray from 1.6.0 to 1.7.0 [\#101](https://github.com/tj-django/django-migration-fixer/pull/101) ([dependabot[bot]](https://github.com/apps/dependabot)) 266 | - Bump tox from 3.23.1 to 3.24.0 [\#100](https://github.com/tj-django/django-migration-fixer/pull/100) ([dependabot[bot]](https://github.com/apps/dependabot)) 267 | - Update codecov/codecov-action action to v2.0.2 [\#97](https://github.com/tj-django/django-migration-fixer/pull/97) ([renovate[bot]](https://github.com/apps/renovate)) 268 | - Update codacy/codacy-analysis-cli-action action to v4 [\#96](https://github.com/tj-django/django-migration-fixer/pull/96) ([renovate[bot]](https://github.com/apps/renovate)) 269 | - \[pre-commit.ci\] pre-commit autoupdate [\#95](https://github.com/tj-django/django-migration-fixer/pull/95) ([pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci)) 270 | - Update codacy/codacy-analysis-cli-action action to v3 [\#94](https://github.com/tj-django/django-migration-fixer/pull/94) ([renovate[bot]](https://github.com/apps/renovate)) 271 | - Upgraded v1.1.1 → v1.1.2 [\#93](https://github.com/tj-django/django-migration-fixer/pull/93) ([jackton1](https://github.com/jackton1)) 272 | 273 | ## [v1.1.2](https://github.com/tj-django/django-migration-fixer/tree/v1.1.2) (2021-07-19) 274 | 275 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v1.1.1...v1.1.2) 276 | 277 | **Merged pull requests:** 278 | 279 | - Update codecov/codecov-action action to v2 [\#92](https://github.com/tj-django/django-migration-fixer/pull/92) ([renovate[bot]](https://github.com/apps/renovate)) 280 | - Update dependency mkdocs to v1.2.2 [\#91](https://github.com/tj-django/django-migration-fixer/pull/91) ([renovate[bot]](https://github.com/apps/renovate)) 281 | - Upgraded v1.1.0 → v1.1.1 [\#90](https://github.com/tj-django/django-migration-fixer/pull/90) ([jackton1](https://github.com/jackton1)) 282 | 283 | ## [v1.1.1](https://github.com/tj-django/django-migration-fixer/tree/v1.1.1) (2021-07-18) 284 | 285 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v1.1.0...v1.1.1) 286 | 287 | **Merged pull requests:** 288 | 289 | - Updated README.md [\#89](https://github.com/tj-django/django-migration-fixer/pull/89) ([jackton1](https://github.com/jackton1)) 290 | - Increased test coverage. [\#88](https://github.com/tj-django/django-migration-fixer/pull/88) ([jackton1](https://github.com/jackton1)) 291 | - Updated README.md [\#87](https://github.com/tj-django/django-migration-fixer/pull/87) ([jackton1](https://github.com/jackton1)) 292 | - Upgraded v1.0.7 → v1.1.0 [\#86](https://github.com/tj-django/django-migration-fixer/pull/86) ([jackton1](https://github.com/jackton1)) 293 | 294 | ## [v1.1.0](https://github.com/tj-django/django-migration-fixer/tree/v1.1.0) (2021-07-09) 295 | 296 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v1.0.7...v1.1.0) 297 | 298 | **Implemented enhancements:** 299 | 300 | - \[Testing\]: Setup django-test-migrations [\#30](https://github.com/tj-django/django-migration-fixer/issues/30) 301 | 302 | **Merged pull requests:** 303 | 304 | - Increased test coverage [\#85](https://github.com/tj-django/django-migration-fixer/pull/85) ([jackton1](https://github.com/jackton1)) 305 | - Update precommit hook pycqa/isort to v5.9.2 [\#84](https://github.com/tj-django/django-migration-fixer/pull/84) ([renovate[bot]](https://github.com/apps/renovate)) 306 | - Upgraded v1.0.6 → v1.0.7 [\#83](https://github.com/tj-django/django-migration-fixer/pull/83) ([jackton1](https://github.com/jackton1)) 307 | - Updated README.md [\#82](https://github.com/tj-django/django-migration-fixer/pull/82) ([jackton1](https://github.com/jackton1)) 308 | - Updated README.md [\#81](https://github.com/tj-django/django-migration-fixer/pull/81) ([jackton1](https://github.com/jackton1)) 309 | 310 | ## [v1.0.7](https://github.com/tj-django/django-migration-fixer/tree/v1.0.7) (2021-07-06) 311 | 312 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v1.0.6...v1.0.7) 313 | 314 | **Merged pull requests:** 315 | 316 | - Updated README.md [\#80](https://github.com/tj-django/django-migration-fixer/pull/80) ([jackton1](https://github.com/jackton1)) 317 | - Upgraded v1.0.5 → v1.0.6 [\#79](https://github.com/tj-django/django-migration-fixer/pull/79) ([jackton1](https://github.com/jackton1)) 318 | 319 | ## [v1.0.6](https://github.com/tj-django/django-migration-fixer/tree/v1.0.6) (2021-07-06) 320 | 321 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v1.0.5...v1.0.6) 322 | 323 | **Merged pull requests:** 324 | 325 | - Preserve quotes [\#78](https://github.com/tj-django/django-migration-fixer/pull/78) ([jackton1](https://github.com/jackton1)) 326 | - Updated README.md [\#77](https://github.com/tj-django/django-migration-fixer/pull/77) ([jackton1](https://github.com/jackton1)) 327 | - Upgraded v1.0.4 → v1.0.5 [\#76](https://github.com/tj-django/django-migration-fixer/pull/76) ([jackton1](https://github.com/jackton1)) 328 | - Update README.md [\#75](https://github.com/tj-django/django-migration-fixer/pull/75) ([jackton1](https://github.com/jackton1)) 329 | 330 | ## [v1.0.5](https://github.com/tj-django/django-migration-fixer/tree/v1.0.5) (2021-07-06) 331 | 332 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v1.0.4...v1.0.5) 333 | 334 | **Merged pull requests:** 335 | 336 | - Upgraded v1.0.3 → v1.0.4 [\#74](https://github.com/tj-django/django-migration-fixer/pull/74) ([jackton1](https://github.com/jackton1)) 337 | 338 | ## [v1.0.4](https://github.com/tj-django/django-migration-fixer/tree/v1.0.4) (2021-07-06) 339 | 340 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v1.0.3...v1.0.4) 341 | 342 | **Merged pull requests:** 343 | 344 | - Upgraded v1.0.2 → v1.0.3 [\#73](https://github.com/tj-django/django-migration-fixer/pull/73) ([jackton1](https://github.com/jackton1)) 345 | - Updated README.md [\#72](https://github.com/tj-django/django-migration-fixer/pull/72) ([jackton1](https://github.com/jackton1)) 346 | - Fixed bug using a detached head [\#71](https://github.com/tj-django/django-migration-fixer/pull/71) ([jackton1](https://github.com/jackton1)) 347 | 348 | ## [v1.0.3](https://github.com/tj-django/django-migration-fixer/tree/v1.0.3) (2021-07-06) 349 | 350 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v1.0.2...v1.0.3) 351 | 352 | **Merged pull requests:** 353 | 354 | - Updated README.md [\#70](https://github.com/tj-django/django-migration-fixer/pull/70) ([jackton1](https://github.com/jackton1)) 355 | - Upgraded v1.0.1 → v1.0.2 [\#69](https://github.com/tj-django/django-migration-fixer/pull/69) ([jackton1](https://github.com/jackton1)) 356 | 357 | ## [v1.0.2](https://github.com/tj-django/django-migration-fixer/tree/v1.0.2) (2021-07-06) 358 | 359 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v1.0.1...v1.0.2) 360 | 361 | **Closed issues:** 362 | 363 | - Add github action that uses the GITHUB\_BASE\_REF instead of the default `branch` input. [\#22](https://github.com/tj-django/django-migration-fixer/issues/22) 364 | 365 | **Merged pull requests:** 366 | 367 | - Upgraded v1.0.0 → v1.0.1 [\#68](https://github.com/tj-django/django-migration-fixer/pull/68) ([jackton1](https://github.com/jackton1)) 368 | - Updated README.md [\#67](https://github.com/tj-django/django-migration-fixer/pull/67) ([jackton1](https://github.com/jackton1)) 369 | 370 | ## [v1.0.1](https://github.com/tj-django/django-migration-fixer/tree/v1.0.1) (2021-07-06) 371 | 372 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v1.0.0...v1.0.1) 373 | 374 | **Merged pull requests:** 375 | 376 | - Updated README.md [\#66](https://github.com/tj-django/django-migration-fixer/pull/66) ([jackton1](https://github.com/jackton1)) 377 | - Upgraded v0.0.7 → v1.0.0 [\#64](https://github.com/tj-django/django-migration-fixer/pull/64) ([jackton1](https://github.com/jackton1)) 378 | - Updated README.md [\#63](https://github.com/tj-django/django-migration-fixer/pull/63) ([jackton1](https://github.com/jackton1)) 379 | 380 | ## [v1.0.0](https://github.com/tj-django/django-migration-fixer/tree/v1.0.0) (2021-07-05) 381 | 382 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v0.0.7...v1.0.0) 383 | 384 | **Implemented enhancements:** 385 | 386 | - Improve logging [\#34](https://github.com/tj-django/django-migration-fixer/issues/34) 387 | - \[Enhancement\] Explore using PyGithub directly. [\#29](https://github.com/tj-django/django-migration-fixer/issues/29) 388 | 389 | **Closed issues:** 390 | 391 | - Improve test coverage [\#17](https://github.com/tj-django/django-migration-fixer/issues/17) 392 | 393 | **Merged pull requests:** 394 | 395 | - Increase test coverage. [\#62](https://github.com/tj-django/django-migration-fixer/pull/62) ([jackton1](https://github.com/jackton1)) 396 | - Updated README.md [\#60](https://github.com/tj-django/django-migration-fixer/pull/60) ([jackton1](https://github.com/jackton1)) 397 | - Updated README.md [\#57](https://github.com/tj-django/django-migration-fixer/pull/57) ([jackton1](https://github.com/jackton1)) 398 | - Update tox.ini [\#56](https://github.com/tj-django/django-migration-fixer/pull/56) ([jackton1](https://github.com/jackton1)) 399 | - Update dependency Django to v3.2.5 [\#55](https://github.com/tj-django/django-migration-fixer/pull/55) ([renovate[bot]](https://github.com/apps/renovate)) 400 | - Updated README.md [\#54](https://github.com/tj-django/django-migration-fixer/pull/54) ([jackton1](https://github.com/jackton1)) 401 | - Increased test coverage. [\#53](https://github.com/tj-django/django-migration-fixer/pull/53) ([jackton1](https://github.com/jackton1)) 402 | - Clean up docs. [\#52](https://github.com/tj-django/django-migration-fixer/pull/52) ([jackton1](https://github.com/jackton1)) 403 | - Update tj-actions/verify-changed-files action to v7 [\#51](https://github.com/tj-django/django-migration-fixer/pull/51) ([renovate[bot]](https://github.com/apps/renovate)) 404 | - Update precommit hook pycqa/isort to v5.9.1 [\#50](https://github.com/tj-django/django-migration-fixer/pull/50) ([renovate[bot]](https://github.com/apps/renovate)) 405 | - Update precommit hook pycqa/isort to v5.9.0 [\#49](https://github.com/tj-django/django-migration-fixer/pull/49) ([renovate[bot]](https://github.com/apps/renovate)) 406 | - Updated README.md [\#48](https://github.com/tj-django/django-migration-fixer/pull/48) ([jackton1](https://github.com/jackton1)) 407 | - Upgraded v0.0.6 → v0.0.7 [\#47](https://github.com/tj-django/django-migration-fixer/pull/47) ([jackton1](https://github.com/jackton1)) 408 | 409 | ## [v0.0.7](https://github.com/tj-django/django-migration-fixer/tree/v0.0.7) (2021-06-21) 410 | 411 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v0.0.6...v0.0.7) 412 | 413 | **Merged pull requests:** 414 | 415 | - Updated README.md [\#46](https://github.com/tj-django/django-migration-fixer/pull/46) ([jackton1](https://github.com/jackton1)) 416 | - Update README.md [\#45](https://github.com/tj-django/django-migration-fixer/pull/45) ([jackton1](https://github.com/jackton1)) 417 | - Updated README.md [\#44](https://github.com/tj-django/django-migration-fixer/pull/44) ([jackton1](https://github.com/jackton1)) 418 | - Improve test coverage [\#43](https://github.com/tj-django/django-migration-fixer/pull/43) ([jackton1](https://github.com/jackton1)) 419 | - \[pre-commit.ci\] pre-commit autoupdate [\#42](https://github.com/tj-django/django-migration-fixer/pull/42) ([pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci)) 420 | - Update wearerequired/lint-action action to v1.10.0 [\#41](https://github.com/tj-django/django-migration-fixer/pull/41) ([renovate[bot]](https://github.com/apps/renovate)) 421 | - Update tj-actions/verify-changed-files action to v6.2 [\#39](https://github.com/tj-django/django-migration-fixer/pull/39) ([renovate[bot]](https://github.com/apps/renovate)) 422 | - Update dependency portray to v1.7.0 [\#38](https://github.com/tj-django/django-migration-fixer/pull/38) ([renovate[bot]](https://github.com/apps/renovate)) 423 | - Update dependency mkdocs to v1.2.1 [\#37](https://github.com/tj-django/django-migration-fixer/pull/37) ([renovate[bot]](https://github.com/apps/renovate)) 424 | - Update codecov/codecov-action action to v1.5.2 [\#36](https://github.com/tj-django/django-migration-fixer/pull/36) ([renovate[bot]](https://github.com/apps/renovate)) 425 | - Update actions/cache action to v2.1.6 [\#35](https://github.com/tj-django/django-migration-fixer/pull/35) ([renovate[bot]](https://github.com/apps/renovate)) 426 | - Upgraded v0.0.5 → v0.0.6 [\#33](https://github.com/tj-django/django-migration-fixer/pull/33) ([jackton1](https://github.com/jackton1)) 427 | - Updated README.md [\#32](https://github.com/tj-django/django-migration-fixer/pull/32) ([jackton1](https://github.com/jackton1)) 428 | 429 | ## [v0.0.6](https://github.com/tj-django/django-migration-fixer/tree/v0.0.6) (2021-06-08) 430 | 431 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v0.0.5...v0.0.6) 432 | 433 | **Closed issues:** 434 | 435 | - Initial Update [\#24](https://github.com/tj-django/django-migration-fixer/issues/24) 436 | - Add documentation [\#18](https://github.com/tj-django/django-migration-fixer/issues/18) 437 | - subprocess call - check for execution of untrusted input. [\#10](https://github.com/tj-django/django-migration-fixer/issues/10) 438 | 439 | **Merged pull requests:** 440 | 441 | - Updated README.md [\#31](https://github.com/tj-django/django-migration-fixer/pull/31) ([jackton1](https://github.com/jackton1)) 442 | - Pin django to latest version 3.2.4 [\#26](https://github.com/tj-django/django-migration-fixer/pull/26) ([pyup-bot](https://github.com/pyup-bot)) 443 | - Config file for pyup.io [\#25](https://github.com/tj-django/django-migration-fixer/pull/25) ([pyup-bot](https://github.com/pyup-bot)) 444 | - Updated README.md [\#21](https://github.com/tj-django/django-migration-fixer/pull/21) ([jackton1](https://github.com/jackton1)) 445 | - Updated README.md [\#20](https://github.com/tj-django/django-migration-fixer/pull/20) ([jackton1](https://github.com/jackton1)) 446 | - Added documentation [\#19](https://github.com/tj-django/django-migration-fixer/pull/19) ([jackton1](https://github.com/jackton1)) 447 | - Remove pytest-runner [\#15](https://github.com/tj-django/django-migration-fixer/pull/15) ([jackton1](https://github.com/jackton1)) 448 | - Added mypy configuration and updated tox test. [\#14](https://github.com/tj-django/django-migration-fixer/pull/14) ([jackton1](https://github.com/jackton1)) 449 | - Added action to run makemigrations --fix [\#13](https://github.com/tj-django/django-migration-fixer/pull/13) ([jackton1](https://github.com/jackton1)) 450 | - \[Cleanup\]: Code duplication [\#12](https://github.com/tj-django/django-migration-fixer/pull/12) ([jackton1](https://github.com/jackton1)) 451 | - \[Security\]: Fix security issue using subprocess [\#11](https://github.com/tj-django/django-migration-fixer/pull/11) ([jackton1](https://github.com/jackton1)) 452 | - Upgraded v0.0.4 → v0.0.5 [\#9](https://github.com/tj-django/django-migration-fixer/pull/9) ([jackton1](https://github.com/jackton1)) 453 | 454 | ## [v0.0.5](https://github.com/tj-django/django-migration-fixer/tree/v0.0.5) (2021-05-24) 455 | 456 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v0.0.4...v0.0.5) 457 | 458 | ## [v0.0.4](https://github.com/tj-django/django-migration-fixer/tree/v0.0.4) (2021-05-24) 459 | 460 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v0.0.3...v0.0.4) 461 | 462 | ## [v0.0.3](https://github.com/tj-django/django-migration-fixer/tree/v0.0.3) (2021-05-24) 463 | 464 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v0.0.2...v0.0.3) 465 | 466 | **Merged pull requests:** 467 | 468 | - chore/update deployment [\#8](https://github.com/tj-django/django-migration-fixer/pull/8) ([jackton1](https://github.com/jackton1)) 469 | - Added bumpversion configuration. [\#7](https://github.com/tj-django/django-migration-fixer/pull/7) ([jackton1](https://github.com/jackton1)) 470 | - Update README.md [\#6](https://github.com/tj-django/django-migration-fixer/pull/6) ([jackton1](https://github.com/jackton1)) 471 | 472 | ## [v0.0.2](https://github.com/tj-django/django-migration-fixer/tree/v0.0.2) (2021-05-23) 473 | 474 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v0.0.1...v0.0.2) 475 | 476 | **Closed issues:** 477 | 478 | - Install instructions say "pip install django-view-breadcrumbs" [\#5](https://github.com/tj-django/django-migration-fixer/issues/5) 479 | 480 | ## [v0.0.1](https://github.com/tj-django/django-migration-fixer/tree/v0.0.1) (2021-05-23) 481 | 482 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/cb738baa4ee8f1587375d4701bd146fecee367b6...v0.0.1) 483 | 484 | **Merged pull requests:** 485 | 486 | - Update README.md [\#4](https://github.com/tj-django/django-migration-fixer/pull/4) ([jackton1](https://github.com/jackton1)) 487 | - Create LICENSE [\#3](https://github.com/tj-django/django-migration-fixer/pull/3) ([jackton1](https://github.com/jackton1)) 488 | - Added named migration. [\#2](https://github.com/tj-django/django-migration-fixer/pull/2) ([jackton1](https://github.com/jackton1)) 489 | - Increased the max\_length to 500. [\#1](https://github.com/tj-django/django-migration-fixer/pull/1) ([jackton1](https://github.com/jackton1)) 490 | 491 | 492 | 493 | \* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* 494 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | jtonye@ymail.com. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Tonye Jack 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include migration_fixer *.py 2 | exclude *.py 3 | exclude *.txt 4 | exclude *.yaml 5 | exclude LICENSE 6 | exclude Makefile 7 | prune demo 8 | prune django_migration_fixer 9 | prune migration_fixer/tests 10 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Self-Documented Makefile see https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html 2 | 3 | .DEFAULT_GOAL := help 4 | 5 | define BROWSER_PYSCRIPT 6 | import os, webbrowser, sys 7 | 8 | from urllib.request import pathname2url 9 | 10 | webbrowser.open("file://" + pathname2url(os.path.abspath(sys.argv[1]))) 11 | endef 12 | export BROWSER_PYSCRIPT 13 | 14 | BROWSER := python -c "$$BROWSER_PYSCRIPT" 15 | PART := minor 16 | 17 | # Put it first so that "make" without argument is like "make help". 18 | help: 19 | @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-32s-\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) 20 | 21 | guard-%: ## Checks that env var is set else exits with non 0 mainly used in CI; 22 | @if [ -z '${${*}}' ]; then echo 'Environment variable $* not set' && exit 1; fi 23 | 24 | # -------------------------------------------------------- 25 | # ------- Python package (pip) management commands ------- 26 | # -------------------------------------------------------- 27 | 28 | clean: clean-build clean-pyc clean-test clean-docs ## remove all build, test, coverage and Python artifacts 29 | 30 | clean-build: ## remove build artifacts 31 | @rm -fr build/ 32 | @rm -fr dist/ 33 | @rm -fr .eggs/ 34 | @find . -name '*.egg-info' -exec rm -fr {} + 35 | @find . -name '*.egg' -exec rm -f {} + 36 | 37 | clean-pyc: ## remove Python file artifacts 38 | @find . -name '*.pyc' -exec rm -f {} + 39 | @find . -name '*.pyo' -exec rm -f {} + 40 | @find . -name '*~' -exec rm -f {} + 41 | @find . -name '__pycache__' -exec rm -fr {} + || true 42 | 43 | clean-test: ## remove test and coverage artifacts 44 | @rm -fr .tox/ 45 | @rm -f .coverage 46 | @rm -fr htmlcov/ 47 | @rm -fr .pytest_cache 48 | @rm -fr .mypy_cache/ 49 | 50 | clean-docs: ## remove all doc artifacts 51 | @rm -fr site 52 | 53 | lint: ## check style with flake8 54 | @flake8 restricted_fields tests 55 | 56 | tox: ## Run tox test 57 | @tox 58 | 59 | coverage: ## check code coverage quickly with the default Python 60 | @coverage run --source restricted_fields -m pytest 61 | @coverage report -m 62 | @coverage html 63 | @$(BROWSER) htmlcov/index.html 64 | 65 | build-docs: 66 | @mkdocs build 67 | 68 | github-pages: install-docs 69 | @mkdocs gh-deploy 70 | 71 | servedocs: install-docs build-docs ## compile the docs watching for changes 72 | @mkdocs serve 73 | 74 | release: dist ## package and upload a release 75 | @twine upload dist/* 76 | 77 | dist: clean install-deploy ## builds source and wheel package 78 | @pip install twine==3.4.1 79 | @python setup.py sdist bdist_wheel 80 | 81 | increase-version: guard-PART ## Increase project version 82 | @bump2version $(PART) 83 | @git switch -c main 84 | 85 | install-wheel: clean ## Install wheel 86 | @echo "Installing wheel..." 87 | @pip install wheel 88 | 89 | install: requirements.txt install-wheel ## install the package to the active Python's site-packages 90 | @pip install -r requirements.txt 91 | 92 | install-dev: install-wheel ## Install local dev packages 93 | @pip install -e .'[development]' 94 | 95 | install-docs: install-wheel 96 | @pip install -e .'[docs]' 97 | 98 | install-test: install-wheel 99 | @pip install -e .'[test]' 100 | 101 | install-lint: install-wheel 102 | @pip install -e .'[lint]' 103 | 104 | install-deploy: install-wheel 105 | @pip install -e .'[deploy]' 106 | 107 | test: install-test 108 | @pytest -E invalid_repo 109 | @pytest -E utils 110 | 111 | update-requirements: 112 | @echo "Updating requirements.txt..." 113 | @pip-compile 114 | 115 | migrations: 116 | @python manage.py makemigrations 117 | 118 | .PHONY: clean clean-test clean-pyc clean-build docs help install-wheel install-docs install-dev install install-lint install-test install-deploy migrations 119 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![logo](https://user-images.githubusercontent.com/17484350/124649379-6821ad00-de66-11eb-9b0e-890913c65311.png) 2 | 3 | [![Codacy Badge](https://app.codacy.com/project/badge/Coverage/1e607eb508f64cefad18f50d6ff920cf)](https://www.codacy.com/gh/tj-django/django-migration-fixer/dashboard?utm_source=github.com\&utm_medium=referral\&utm_content=tj-django/django-migration-fixer\&utm_campaign=Badge_Coverage) 4 | [![codecov](https://codecov.io/gh/tj-django/django-migration-fixer/branch/main/graph/badge.svg?token=peNs0PpfP6)](https://codecov.io/gh/tj-django/django-migration-fixer) 5 | [![Codacy Badge](https://app.codacy.com/project/badge/Grade/1e607eb508f64cefad18f50d6ff920cf)](https://www.codacy.com/gh/tj-django/django-migration-fixer/dashboard?utm_source=github.com\&utm_medium=referral\&utm_content=tj-django/django-migration-fixer\&utm_campaign=Badge_Grade) 6 | [![Test](https://github.com/tj-django/django-migration-fixer/actions/workflows/test.yml/badge.svg)](https://github.com/tj-django/django-migration-fixer/actions/workflows/test.yml) 7 | [![Upload Python Package](https://github.com/tj-django/django-migration-fixer/actions/workflows/deploy.yml/badge.svg)](https://github.com/tj-django/django-migration-fixer/actions/workflows/deploy.yml) 8 | 9 | [![PyPI](https://img.shields.io/pypi/v/django-migration-fixer)](https://pypi.python.org/pypi/django-migration-fixer) 10 | [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/django-migration-fixer)](https://pypi.python.org/pypi/django-migration-fixer) [![PyPI - Django Version](https://img.shields.io/pypi/djversions/django-migration-fixer)](https://pypi.python.org/pypi/django-migration-fixer) [![Downloads](https://pepy.tech/badge/django-migration-fixer)](https://pepy.tech/project/django-migration-fixer) 11 | [![Public workflows that use this action.](https://img.shields.io/endpoint?url=https%3A%2F%2Fused-by.vercel.app%2Fapi%2Fgithub-actions%2Fused-by%3Faction%3Dtj-django%2Fdjango-migration-fixer%26badge%3Dtrue)](https://github.com/search?o=desc\&q=tj-django+django-migration-fixer+language%3AYAML\&s=\&type=Code) 12 | [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) 13 | 14 | # django-migration-fixer 15 | 16 | Resolve django makemigrations `multiple leaf nodes in the migration graph` by ensuring that migration files and dependencies are always ordered regardless of remote changes, without having to run `python manage.py makemigrations --merge`. 17 | 18 | ## Table of Contents 19 | 20 | * [Features](#features) 21 | * [Installation](#installation) 22 | * [Add `migration_fixer` to your INSTALLED\_APPS](#add-migration_fixer-to-your-installed_apps) 23 | * [Usage](#usage) 24 | * [Example](#example) 25 | * [After merging the default branch](#after-merging-the-default-branch) 26 | * [After running django-migration-fixer](#after-running-django-migration-fixer) 27 | * [Assumptions](#assumptions) 28 | * [Specifying a different default branch](#specifying-a-different-default-branch) 29 | * [Setup using Github Actions](#setup-using-github-actions) 30 | * [Inputs](#inputs) 31 | * [Test Platforms](#test-platforms) 32 | * [Found a Bug?](#found-a-bug) 33 | 34 | ## Features 35 | 36 | * Resolve migration conflicts on Pull Request branches 37 | * Resolve migration conflicts on the default branch **(NOT RECOMMENDED)** 38 | 39 | ## Installation 40 | 41 | ```bash 42 | $ pip install django-migration-fixer 43 | ``` 44 | 45 | ### Add `migration_fixer` to your INSTALLED\_APPS 46 | 47 | ```python 48 | 49 | INSTALLED_APPS = [ 50 | ..., 51 | "migration_fixer", 52 | ..., 53 | ] 54 | ``` 55 | 56 | ## Usage 57 | 58 | Merge the changes from the default branch or the target branch of the pull request. 59 | 60 | ```bash 61 | $ git checkout main # OR: develop/another parent feature branch 62 | $ git pull 63 | $ git checkout feature/xxxx 64 | $ git merge main 65 | ``` 66 | 67 | Fix the migration conflicts 68 | 69 | ```bash 70 | $ python manage.py makemigrations --fix 71 | ``` 72 | 73 | By default this uses `main` as the default branch 74 | 75 | ## Example 76 | 77 | ### After merging the default branch 78 | 79 | ![Screen Shot 2021-07-06 at 2 21 46 PM](https://user-images.githubusercontent.com/17484350/124648930-d7e36800-de65-11eb-99a3-bf806ecfd32b.png) 80 | 81 | ### After running django-migration-fixer 82 | 83 | ![Screen Shot 2021-07-06 at 2 22 31 PM](https://user-images.githubusercontent.com/17484350/124649105-0feaab00-de66-11eb-80f3-7987d67b361d.png) 84 | 85 | ## Assumptions 86 | 87 | The final migration on the default branch would be used as the base for all subsequent migrations. 88 | 89 | ### Specifying a different default branch 90 | 91 | Run: 92 | 93 | ```bash 94 | $ python manage.py makemigrations -b master --fix 95 | ``` 96 | 97 | ## Setup using Github Actions 98 | 99 | > NOTE: :warning: 100 | > 101 | > * To get this action to work you'll need to install [django-migration-fixer](#installation) and update your `INSTALLED_APPS` setting. 102 | 103 | ### Inputs 104 | 105 | | Input | type | required | default | description | 106 | |:-------------:|:-----------:|:--------------:|:-----------------------------:|:--------------------------:| 107 | | managepy-path | `string` | `true` | `./manage.py` | The location of manage.py. | 108 | | default-branch | `string` | `false` | `${{ github.base_ref }}` | The default branch or <br> target branch of a Pull request. | 109 | | force-update | `string` | `false` | | Force update the target branch <br> locally when git fetch fails. | 110 | | skip-default-branch-update | `string` | `false` | | Skip pulling the latest <br> changes from the default branch. | 111 | 112 | ```yaml 113 | name: Fix django migrations 114 | 115 | on: 116 | pull_request: 117 | branches: 118 | - main 119 | 120 | jobs: 121 | fix-migrations: 122 | runs-on: ubuntu-latest 123 | steps: 124 | - uses: actions/checkout@v2 125 | with: 126 | fetch-depth: 0 127 | 128 | - name: Set up Python 129 | uses: actions/setup-python@v2 130 | with: 131 | python-version: '3.6.x' 132 | 133 | - name: Upgrade pip 134 | run: | 135 | pip install -U pip 136 | 137 | - name: Install project dependencies 138 | run: | 139 | make install 140 | 141 | - name: Run django-migration-fixer 142 | uses: tj-django/django-migration-fixer@v1.3.6 143 | with: 144 | managepy-path: /path/to/manage.py 145 | 146 | - name: Verify Changed files 147 | uses: tj-actions/verify-changed-files@v7.1 148 | id: verify-changed-files 149 | with: 150 | files: | 151 | /path/to/migrations 152 | 153 | - name: Commit migration changes 154 | if: steps.verify-changed-files.outputs.files_changed == 'true' 155 | run: | 156 | git config --local user.email "github-actions[bot]@users.noreply.github.com" 157 | git config --local user.name "github-actions[bot]" 158 | git add /path/to/migrations 159 | git commit -m "Updated migrations" 160 | 161 | - name: Push migration changes 162 | if: steps.verify-changed-files.outputs.files_changed == 'true' 163 | uses: ad-m/github-push-action@master 164 | with: 165 | github_token: ${{ secrets.GITHUB_TOKEN }} 166 | branch: ${{ github.ref }} 167 | ``` 168 | 169 | See: [here](https://github.com/tj-django/django-clone/blob/main/.github/workflows/migration-fixer.yml) for a working example. 170 | 171 | ## Test Platforms 172 | 173 | * [`ubuntu-*`](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on) 174 | * [`macos-*`](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on) 175 | * [`windows-*`](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on) 176 | 177 | ## Found a Bug? 178 | 179 | To file a bug or submit a patch, please head over to [django-migration-fixer on github](https://github.com/tj-django/django-migration-fixer/issues). 180 | 181 | If you feel generous and want to show some extra appreciation: 182 | 183 | Support me with a :star: 184 | 185 | [![Buy me a coffee][buymeacoffee-shield]][buymeacoffee] 186 | 187 | [buymeacoffee]: https://www.buymeacoffee.com/jackton1 188 | 189 | [buymeacoffee-shield]: https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png 190 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: django-migration-fixer 2 | description: Resolve django makemigrations multiple leaf nodes in the migration graph error 3 | author: tj-actions 4 | inputs: 5 | managepy-path: 6 | description: 'The location of manage.py.' 7 | required: true 8 | default: './manage.py' 9 | default-branch: 10 | description: 'The default branch or target branch of a Pull request: Defaults to github.base_ref' 11 | required: false 12 | default: ${{ github.base_ref }} 13 | force-update: 14 | description: 'Force update the target branch locally when git fetch fails.' 15 | required: false 16 | skip-default-branch-update: 17 | description: 'Skip pulling the latest changes from the default branch.' 18 | required: false 19 | 20 | runs: 21 | using: 'composite' 22 | steps: 23 | - id: migration-fixer 24 | run: | 25 | DEFAULT_BRANCH="${{ inputs.default-branch }}" 26 | 27 | EXTRA_ARGS="--fix" 28 | 29 | if [[ '${{ inputs.force-update }}' == 'true' ]]; then 30 | EXTRA_ARGS+=" -f" 31 | fi 32 | 33 | if [[ '${{ inputs.skip-default-branch-update }}' == 'true' ]]; then 34 | EXTRA_ARGS+=" -s" 35 | fi 36 | 37 | python ${{ inputs.managepy-path }} makemigrations $EXTRA_ARGS -b "${DEFAULT_BRANCH}" 38 | shell: bash 39 | branding: 40 | icon: check 41 | color: white 42 | -------------------------------------------------------------------------------- /conftest.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import pytest 4 | 5 | 6 | def pytest_addoption(parser): 7 | parser.addoption( 8 | "-E", 9 | action="store", 10 | metavar="NAME", 11 | help="only run tests matching the environment NAME.", 12 | default=os.getenv("ENV"), 13 | ) 14 | 15 | 16 | def pytest_configure(config): 17 | # register an additional marker 18 | config.addinivalue_line( 19 | "markers", "env(name): mark test to run only on named environment" 20 | ) 21 | 22 | 23 | def pytest_runtest_setup(item): 24 | envnames = [mark.args[0] for mark in item.iter_markers(name="env")] 25 | if envnames: 26 | if item.config.getoption("-E") not in envnames: 27 | pytest.skip("test requires env in {!r}".format(envnames)) 28 | -------------------------------------------------------------------------------- /django_migration_fixer/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tj-django/django-migration-fixer/4826d3d82eb53840da1b538f56a2bbbda260dfb9/django_migration_fixer/__init__.py -------------------------------------------------------------------------------- /django_migration_fixer/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for django_migration_fixer project. 3 | 4 | Generated by 'django-admin startproject' using Django 2.2.20. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.2/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/2.2/ref/settings/ 11 | """ 12 | 13 | import os 14 | 15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 | 18 | # Quick-start development settings - unsuitable for production 19 | # See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/ 20 | 21 | # SECURITY WARNING: keep the secret key used in production secret! 22 | SECRET_KEY = "ljq%0159d51t&5&)-*ii6dudczbu(eq(5qda7qjg(qp@#4#vun" 23 | 24 | MIDDLEWARE = [ # lgtm [py/csrf-protection-disabled] 25 | "django.middleware.security.SecurityMiddleware", 26 | "django.middleware.common.CommonMiddleware", 27 | "django.contrib.auth.middleware.AuthenticationMiddleware", 28 | "django.middleware.clickjacking.XFrameOptionsMiddleware", 29 | ] 30 | 31 | TEMPLATES = [ 32 | { 33 | "BACKEND": "django.template.backends.django.DjangoTemplates", 34 | "DIRS": [], 35 | "APP_DIRS": True, 36 | }, 37 | ] 38 | 39 | # SECURITY WARNING: don't run with debug turned on in production! 40 | DEBUG = True 41 | 42 | # Application definition 43 | 44 | INSTALLED_APPS = [ 45 | "django.contrib.auth", 46 | "django.contrib.contenttypes", 47 | "migration_fixer", 48 | "migration_fixer.tests.demo", 49 | ] 50 | 51 | # Database 52 | # https://docs.djangoproject.com/en/2.2/ref/settings/#databases 53 | 54 | DATABASES = { 55 | "default": { 56 | "ENGINE": "django.db.backends.sqlite3", 57 | "NAME": os.path.join(BASE_DIR, "db.sqlite3"), 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /docs/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [v0.0.7](https://github.com/tj-django/django-migration-fixer/tree/v0.0.7) (2021-06-21) 4 | 5 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v0.0.6...v0.0.7) 6 | 7 | **Closed issues:** 8 | 9 | - Dependency Dashboard [\#40](https://github.com/tj-django/django-migration-fixer/issues/40) 10 | 11 | **Merged pull requests:** 12 | 13 | - Updated README.md [\#46](https://github.com/tj-django/django-migration-fixer/pull/46) ([jackton1](https://github.com/jackton1)) 14 | - Update README.md [\#45](https://github.com/tj-django/django-migration-fixer/pull/45) ([jackton1](https://github.com/jackton1)) 15 | - Updated README.md [\#44](https://github.com/tj-django/django-migration-fixer/pull/44) ([jackton1](https://github.com/jackton1)) 16 | - Improve test coverage [\#43](https://github.com/tj-django/django-migration-fixer/pull/43) ([jackton1](https://github.com/jackton1)) 17 | - \[pre-commit.ci\] pre-commit autoupdate [\#42](https://github.com/tj-django/django-migration-fixer/pull/42) ([pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci)) 18 | - Update wearerequired/lint-action action to v1.10.0 [\#41](https://github.com/tj-django/django-migration-fixer/pull/41) ([renovate[bot]](https://github.com/apps/renovate)) 19 | - Update tj-actions/verify-changed-files action to v6.2 [\#39](https://github.com/tj-django/django-migration-fixer/pull/39) ([renovate[bot]](https://github.com/apps/renovate)) 20 | - Update dependency portray to v1.7.0 [\#38](https://github.com/tj-django/django-migration-fixer/pull/38) ([renovate[bot]](https://github.com/apps/renovate)) 21 | - Update dependency mkdocs to v1.2.1 [\#37](https://github.com/tj-django/django-migration-fixer/pull/37) ([renovate[bot]](https://github.com/apps/renovate)) 22 | - Update codecov/codecov-action action to v1.5.2 [\#36](https://github.com/tj-django/django-migration-fixer/pull/36) ([renovate[bot]](https://github.com/apps/renovate)) 23 | - Update actions/cache action to v2.1.6 [\#35](https://github.com/tj-django/django-migration-fixer/pull/35) ([renovate[bot]](https://github.com/apps/renovate)) 24 | - Upgraded v0.0.5 → v0.0.6 [\#33](https://github.com/tj-django/django-migration-fixer/pull/33) ([jackton1](https://github.com/jackton1)) 25 | - Updated README.md [\#32](https://github.com/tj-django/django-migration-fixer/pull/32) ([jackton1](https://github.com/jackton1)) 26 | 27 | ## [v0.0.6](https://github.com/tj-django/django-migration-fixer/tree/v0.0.6) (2021-06-08) 28 | 29 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v0.0.5...v0.0.6) 30 | 31 | **Closed issues:** 32 | 33 | - Initial Update [\#24](https://github.com/tj-django/django-migration-fixer/issues/24) 34 | - Add documentation [\#18](https://github.com/tj-django/django-migration-fixer/issues/18) 35 | - subprocess call - check for execution of untrusted input. [\#10](https://github.com/tj-django/django-migration-fixer/issues/10) 36 | 37 | **Merged pull requests:** 38 | 39 | - Updated README.md [\#31](https://github.com/tj-django/django-migration-fixer/pull/31) ([jackton1](https://github.com/jackton1)) 40 | - Pin django to latest version 3.2.4 [\#26](https://github.com/tj-django/django-migration-fixer/pull/26) ([pyup-bot](https://github.com/pyup-bot)) 41 | - Config file for pyup.io [\#25](https://github.com/tj-django/django-migration-fixer/pull/25) ([pyup-bot](https://github.com/pyup-bot)) 42 | - Updated README.md [\#21](https://github.com/tj-django/django-migration-fixer/pull/21) ([jackton1](https://github.com/jackton1)) 43 | - Updated README.md [\#20](https://github.com/tj-django/django-migration-fixer/pull/20) ([jackton1](https://github.com/jackton1)) 44 | - Added documentation [\#19](https://github.com/tj-django/django-migration-fixer/pull/19) ([jackton1](https://github.com/jackton1)) 45 | - Remove pytest-runner [\#15](https://github.com/tj-django/django-migration-fixer/pull/15) ([jackton1](https://github.com/jackton1)) 46 | - Added mypy configuration and updated tox test. [\#14](https://github.com/tj-django/django-migration-fixer/pull/14) ([jackton1](https://github.com/jackton1)) 47 | - Added action to run makemigrations --fix [\#13](https://github.com/tj-django/django-migration-fixer/pull/13) ([jackton1](https://github.com/jackton1)) 48 | - \[Cleanup\]: Code duplication [\#12](https://github.com/tj-django/django-migration-fixer/pull/12) ([jackton1](https://github.com/jackton1)) 49 | - \[Security\]: Fix security issue using subprocess [\#11](https://github.com/tj-django/django-migration-fixer/pull/11) ([jackton1](https://github.com/jackton1)) 50 | - Upgraded v0.0.4 → v0.0.5 [\#9](https://github.com/tj-django/django-migration-fixer/pull/9) ([jackton1](https://github.com/jackton1)) 51 | 52 | ## [v0.0.5](https://github.com/tj-django/django-migration-fixer/tree/v0.0.5) (2021-05-24) 53 | 54 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v0.0.4...v0.0.5) 55 | 56 | ## [v0.0.4](https://github.com/tj-django/django-migration-fixer/tree/v0.0.4) (2021-05-24) 57 | 58 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v0.0.3...v0.0.4) 59 | 60 | ## [v0.0.3](https://github.com/tj-django/django-migration-fixer/tree/v0.0.3) (2021-05-24) 61 | 62 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v0.0.2...v0.0.3) 63 | 64 | **Merged pull requests:** 65 | 66 | - chore/update deployment [\#8](https://github.com/tj-django/django-migration-fixer/pull/8) ([jackton1](https://github.com/jackton1)) 67 | - Added bumpversion configuration. [\#7](https://github.com/tj-django/django-migration-fixer/pull/7) ([jackton1](https://github.com/jackton1)) 68 | - Update README.md [\#6](https://github.com/tj-django/django-migration-fixer/pull/6) ([jackton1](https://github.com/jackton1)) 69 | 70 | ## [v0.0.2](https://github.com/tj-django/django-migration-fixer/tree/v0.0.2) (2021-05-23) 71 | 72 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/v0.0.1...v0.0.2) 73 | 74 | **Closed issues:** 75 | 76 | - Install instructions say "pip install django-view-breadcrumbs" [\#5](https://github.com/tj-django/django-migration-fixer/issues/5) 77 | 78 | ## [v0.0.1](https://github.com/tj-django/django-migration-fixer/tree/v0.0.1) (2021-05-23) 79 | 80 | [Full Changelog](https://github.com/tj-django/django-migration-fixer/compare/cb738baa4ee8f1587375d4701bd146fecee367b6...v0.0.1) 81 | 82 | **Merged pull requests:** 83 | 84 | - Update README.md [\#4](https://github.com/tj-django/django-migration-fixer/pull/4) ([jackton1](https://github.com/jackton1)) 85 | - Create LICENSE [\#3](https://github.com/tj-django/django-migration-fixer/pull/3) ([jackton1](https://github.com/jackton1)) 86 | - Added named migration. [\#2](https://github.com/tj-django/django-migration-fixer/pull/2) ([jackton1](https://github.com/jackton1)) 87 | - Increased the max\_length to 500. [\#1](https://github.com/tj-django/django-migration-fixer/pull/1) ([jackton1](https://github.com/jackton1)) 88 | 89 | 90 | 91 | \* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* 92 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | [![django migration fixer](./images/logo.png)](https://tj-django.github.io/django-migration-fixer/) 2 | 3 | [![PyPI](https://img.shields.io/pypi/v/django-migration-fixer)](https://pypi.python.org/pypi/django-migration-fixer) [![Codacy Badge](https://app.codacy.com/project/badge/Coverage/1e607eb508f64cefad18f50d6ff920cf)](https://www.codacy.com/gh/tj-django/django-migration-fixer/dashboard?utm_source=github.com\&utm_medium=referral\&utm_content=tj-django/django-migration-fixer\&utm_campaign=Badge_Coverage) [![codecov](https://codecov.io/gh/tj-django/django-migration-fixer/branch/main/graph/badge.svg?token=peNs0PpfP6)](https://codecov.io/gh/tj-django/django-migration-fixer) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) 4 | 5 | [![Total alerts](https://img.shields.io/lgtm/alerts/g/tj-django/django-migration-fixer.svg?logo=lgtm\&logoWidth=18)](https://lgtm.com/projects/g/tj-django/django-migration-fixer/alerts/) [![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/tj-django/django-migration-fixer.svg?logo=lgtm\&logoWidth=18)](https://lgtm.com/projects/g/tj-django/django-migration-fixer/context:python) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/1e607eb508f64cefad18f50d6ff920cf)](https://www.codacy.com/gh/tj-django/django-migration-fixer/dashboard?utm_source=github.com\&utm_medium=referral\&utm_content=tj-django/django-migration-fixer\&utm_campaign=Badge_Grade) 6 | 7 | [![Test](https://github.com/tj-django/django-migration-fixer/actions/workflows/test.yml/badge.svg)](https://github.com/tj-django/django-migration-fixer/actions/workflows/test.yml) [![Upload Python Package](https://github.com/tj-django/django-migration-fixer/actions/workflows/deploy.yml/badge.svg)](https://github.com/tj-django/django-migration-fixer/actions/workflows/deploy.yml) [![Run linters](https://github.com/tj-django/django-migration-fixer/actions/workflows/lint.yml/badge.svg)](https://github.com/tj-django/django-migration-fixer/actions/workflows/lint.yml) 8 | 9 | [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/django-migration-fixer)](https://pypi.python.org/pypi/django-migration-fixer) [![PyPI - Django Version](https://img.shields.io/pypi/djversions/django-migration-fixer)](https://pypi.python.org/pypi/django-migration-fixer) [![Downloads](https://pepy.tech/badge/django-migration-fixer/month)](https://pepy.tech/project/django-migration-fixer) 10 | 11 | # django-migration-fixer 12 | 13 | Maintain a consistent migration history when conflicts occur as a result of changes made using different versions of the default branch. 14 | 15 | ## Installation 16 | 17 | ```bash 18 | $ pip install django-migration-fixer 19 | ``` 20 | 21 | #### Add `migration_fixer` to your INSTALLED_APPS 22 | 23 | ```python 24 | 25 | INSTALLED_APPS = [ 26 | ..., 27 | "migration_fixer", 28 | ..., 29 | ] 30 | 31 | ``` 32 | 33 | ## Usage 34 | 35 | ```bash 36 | $ python manage.py makemigrations --fix 37 | ``` 38 | 39 | By default this uses `main` as the default branch 40 | 41 | ### Specifying a different default branch 42 | 43 | Run: 44 | 45 | ```bash 46 | $ python manage.py makemigrations -b master --fix 47 | ``` 48 | 49 | ## Features 50 | 51 | * Resolve migration conflicts on PR branches 52 | * Resolve migration conflicts on the default branch **(NOT RECOMMENDED)** 53 | * Supports default migration modules i.e (`0001_....py`) 54 | * Re-number all migrations using the last migration on the default branch i.e `main` or `develop` 55 | 56 | ## Example 57 | 58 | **Branch:** `main` 59 | 60 | ```bash 61 | 62 | ├── app 63 | │ ├── migrations 64 | │ ├── 0001_initial.py 65 | │ ├── 0002_auto_20210521_2328.py 66 | 67 | ``` 68 | 69 | **Branch:** `feature/test-a` 70 | 71 | ```bash 72 | 73 | ├── app 74 | │ ├── migrations 75 | │ ├── 0001_initial.py 76 | │ ├── 0002_auto_20210521_2328.py 77 | │ ├── 0003_auto_20210522_1128.py 78 | 79 | ``` 80 | 81 | **Branch:**`feature/test-b` 82 | 83 | ```bash 84 | 85 | ├── app 86 | │ ├── migrations 87 | │ ├── 0001_initial.py 88 | │ ├── 0002_auto_20210521_2328.py 89 | │ ├── 0003_auto_20210522_1228.py 90 | 91 | ``` 92 | 93 | Both `feature/test-a` and `feature/test-b` share the last migration on `main` (`0002_auto_20210521_2328.py`) 94 | 95 | Once `feature/test-a` is merged into `main` you run into the problem of resolving migrations on `feature/test-b` which was dependent on `0002_auto_20210521_2328.py` 96 | 97 | **Branch:** `main` 98 | 99 | ```bash 100 | 101 | ├── app 102 | │ ├── migrations 103 | │ ├── 0001_initial.py 104 | │ ├── 0002_auto_20210521_2328.py 105 | │ ├── 0003_auto_20210522_1128.py 106 | 107 | ``` 108 | 109 | **Branch:** `feature/test-b` 110 | 111 | ```bash 112 | 113 | ├── app 114 | │ ├── migrations 115 | │ ├── 0001_initial.py 116 | │ ├── 0002_auto_20210521_2328.py 117 | │ ├── 0003_auto_20210522_1128.py \___________________ Both dependent on 0002_auto_20210521_2328.py 118 | │ ├── 0003_auto_20210522_1228.py / 119 | 120 | ``` 121 | 122 | Running [`makemigrations`](https://docs.djangoproject.com/en/3.2/ref/django-admin/#django-admin-makemigrations) fails with the following error: 123 | 124 | CommandError: Conflicting migrations detected; multiple leaf nodes in the migration graph: (0003_auto_20210522_1128, 0003_auto_20210522_1228 in app). 125 | To fix them run 'python manage.py makemigrations --merge' 126 | 127 | Using the [`--merge`](https://docs.djangoproject.com/en/3.2/ref/django-admin/#cmdoption-makemigrations-merge) option creates a new migration file which might not be desired. 128 | 129 | ## Solution 130 | 131 | `django-migration-fixer` identifies changes between the default branch `main`, and the feature branch `feature/test-b` and maintains a consistent dependency history as shown below: 132 | 133 | **Branch:** `feature/test-b` 134 | 135 | ```bash 136 | 137 | ├── app 138 | │ ├── migrations 139 | │ ├── 0001_initial.py 140 | │ ├── 0002_auto_20210521_2328.py 141 | │ ├── 0003_auto_20210522_1128.py 142 | │ ├── 0004_auto_20210522_1228.py # Renames: '0003_auto_20210522_1228.py' → '0004_auto_20210522_1228.py' 143 | 144 | ``` 145 | 146 | `0004_auto_20210522_1228.py` 147 | 148 | ```py 149 | ... 150 | from django.db import migrations, models 151 | 152 | 153 | class Migration(migrations.Migration): 154 | 155 | dependencies = [ 156 | ('app', '0003_auto_20210522_1128'), # Replaced '0002_auto_20210521_2328' → '0003_auto_20210522_1128' 157 | ] 158 | 159 | operations = [ 160 | ... 161 | ] 162 | ``` 163 | 164 | > NOTE: :warning: 165 | > 166 | > * This also works when there are conflicts detected on the default branch. 167 | > 168 | > i.e You can run `python manage.py makemigrations --fix` on the `main` branch 169 | > which relies on primitively picking the first migration file. 170 | > 171 | > e.g `(0003_auto_20210522_1128, 0003_auto_20210522_1228 in app)` 172 | > would result in `0003_auto_20210522_1128.py` being picked as the 173 | > base migration which might not be accurate in every case and is not recommended. 174 | 175 | ### Assumptions 176 | 177 | The final migration on the default branch would be used as the base for all subsequent migrations. 178 | 179 | ## Found a Bug? 180 | 181 | To file a bug or submit a patch, please head over to [django-migration-fixer on github](https://github.com/tj-django/django-migration-fixer/issues). 182 | 183 | If you feel generous and want to show some extra appreciation: 184 | 185 | [![Buy me a coffee][buymeacoffee-shield]][buymeacoffee] 186 | 187 | [buymeacoffee]: https://www.buymeacoffee.com/jackton1 188 | 189 | [buymeacoffee-shield]: https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png 190 | -------------------------------------------------------------------------------- /docs/command-options.md: -------------------------------------------------------------------------------- 1 | ```bash 2 | python manage.py makemigrations --help 3 | 4 | usage: manage.py makemigrations [-h] [--fix] [-b DEFAULT_BRANCH] [-s] [-r REMOTE] [-f] [--dry-run] [--merge] [--empty] [--noinput] [-n NAME] [--no-header] [--check] 5 | [--version] [-v {0,1,2,3}] [--settings SETTINGS] [--pythonpath PYTHONPATH] [--traceback] [--no-color] [--force-color] [--skip-checks] 6 | [app_label ...] 7 | 8 | Creates new migration(s) for apps and fix conflicts. 9 | 10 | positional arguments: 11 | app_label Specify the app label(s) to create migrations for. 12 | 13 | optional arguments: 14 | -h, --help show this help message and exit 15 | --fix Fix migrations conflicts. 16 | -b DEFAULT_BRANCH, --default-branch DEFAULT_BRANCH 17 | The name of the default branch. 18 | -s, --skip-default-branch-update 19 | Skip pulling the latest changes from the default branch. 20 | -r REMOTE, --remote REMOTE 21 | Git remote. 22 | -f, --force-update Force update the default branch. 23 | --dry-run Just show what migrations would be made; don't actually write them. 24 | --merge Enable fixing of migration conflicts. 25 | --empty Create an empty migration. 26 | --noinput, --no-input 27 | Tells Django to NOT prompt the user for input of any kind. 28 | -n NAME, --name NAME Use this name for migration file(s). 29 | --no-header Do not add header comments to new migration file(s). 30 | --check Exit with a non-zero status if model changes are missing migrations. 31 | --version show program's version number and exit 32 | -v {0,1,2,3}, --verbosity {0,1,2,3} 33 | Verbosity level; 0=minimal output, 1=normal output, 2=verbose output, 3=very verbose output 34 | --settings SETTINGS The Python path to a settings module, e.g. "myproject.settings.main". If this isn't provided, the DJANGO_SETTINGS_MODULE environment variable will 35 | be used. 36 | --pythonpath PYTHONPATH 37 | A directory to add to the Python path, e.g. "/home/djangoprojects/myproject". 38 | --traceback Raise on CommandError exceptions 39 | --no-color Don't colorize the command output. 40 | --force-color Force colorization of the command output. 41 | --skip-checks Skip system checks. 42 | ``` -------------------------------------------------------------------------------- /docs/css/custom.css: -------------------------------------------------------------------------------- 1 | div.autodoc-docstring { 2 | padding-left: 20px; 3 | margin-bottom: 30px; 4 | border-left: 5px solid rgba(230, 230, 230); 5 | } 6 | 7 | div.autodoc-members { 8 | padding-left: 20px; 9 | margin-bottom: 15px; 10 | } 11 | -------------------------------------------------------------------------------- /docs/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tj-django/django-migration-fixer/4826d3d82eb53840da1b538f56a2bbbda260dfb9/docs/images/logo.png -------------------------------------------------------------------------------- /docs/makemigrations.md: -------------------------------------------------------------------------------- 1 | # Management Command 2 | 3 | ::: migration_fixer.management.commands.makemigrations.Command 4 | :docstring: 5 | :members: 6 | -------------------------------------------------------------------------------- /docs/more-examples.md: -------------------------------------------------------------------------------- 1 | ### More Examples 2 | 3 | **Branch:** `main` 4 | 5 | ```bash 6 | 7 | ├── app 8 | │ ├── migrations 9 | │ ├── 0001_initial.py 10 | │ ├── 0002_auto_20210521_2328.py 11 | 12 | ``` 13 | 14 | **Branch:** `feature/test-a` 15 | 16 | ```bash 17 | 18 | ├── app 19 | │ ├── migrations 20 | │ ├── 0001_initial.py 21 | │ ├── 0002_auto_20210521_2328.py 22 | │ ├── 0003_auto_20210522_1128.py 23 | 24 | ``` 25 | 26 | **Branch:**`feature/test-b` 27 | 28 | ```bash 29 | 30 | ├── app 31 | │ ├── migrations 32 | │ ├── 0001_initial.py 33 | │ ├── 0002_auto_20210521_2328.py 34 | │ ├── 0003_auto_20210522_1228.py 35 | 36 | ``` 37 | 38 | Both `feature/test-a` and `feature/test-b` share the last migration on `main` (`0002_auto_20210521_2328.py`) 39 | 40 | Once `feature/test-a` is merged into `main` you run into the problem of resolving migrations on `feature/test-b` which was dependent on `0002_auto_20210521_2328.py` 41 | 42 | **Branch:** `main` 43 | 44 | ```bash 45 | 46 | ├── app 47 | │ ├── migrations 48 | │ ├── 0001_initial.py 49 | │ ├── 0002_auto_20210521_2328.py 50 | │ ├── 0003_auto_20210522_1128.py 51 | 52 | ``` 53 | 54 | **Branch:** `feature/test-b` 55 | 56 | ```bash 57 | 58 | ├── app 59 | │ ├── migrations 60 | │ ├── 0001_initial.py 61 | │ ├── 0002_auto_20210521_2328.py 62 | │ ├── 0003_auto_20210522_1128.py \___________________ Both dependent on 0002_auto_20210521_2328.py 63 | │ ├── 0003_auto_20210522_1228.py / 64 | 65 | ``` 66 | 67 | Running [`makemigrations`](https://docs.djangoproject.com/en/3.2/ref/django-admin/#django-admin-makemigrations) fails with the following error: 68 | 69 | CommandError: Conflicting migrations detected; multiple leaf nodes in the migration graph: (0003_auto_20210522_1128, 0003_auto_20210522_1228 in app). 70 | To fix them run 'python manage.py makemigrations --merge' 71 | 72 | Using the [`--merge`](https://docs.djangoproject.com/en/3.2/ref/django-admin/#cmdoption-makemigrations-merge) option creates a new migration file which might not be desired. 73 | 74 | ## Solution 75 | 76 | `django-migration-fixer` identifies changes between the default branch `main`, and the feature branch `feature/test-b` and maintains a consistent dependency history as shown below: 77 | 78 | **Branch:** `feature/test-b` 79 | 80 | ```bash 81 | 82 | ├── app 83 | │ ├── migrations 84 | │ ├── 0001_initial.py 85 | │ ├── 0002_auto_20210521_2328.py 86 | │ ├── 0003_auto_20210522_1128.py 87 | │ ├── 0004_auto_20210522_1228.py # Renames: '0003_auto_20210522_1228.py' → '0004_auto_20210522_1228.py' 88 | 89 | ``` 90 | 91 | `0004_auto_20210522_1228.py` 92 | 93 | ```py 94 | ... 95 | from django.db import migrations, models 96 | 97 | 98 | class Migration(migrations.Migration): 99 | 100 | dependencies = [ 101 | ('app', '0003_auto_20210522_1128'), # Replaced '0002_auto_20210521_2328' → '0003_auto_20210522_1128' 102 | ] 103 | 104 | operations = [ 105 | ... 106 | ] 107 | ``` 108 | 109 | > NOTE: :warning: 110 | > 111 | > * This also works when there are conflicts detected on the default branch. 112 | > 113 | > i.e You can run `python manage.py makemigrations --fix` on the `main` branch 114 | > which relies on primitively picking the first migration file. 115 | > 116 | > e.g `(0003_auto_20210522_1128, 0003_auto_20210522_1228 in app)` 117 | > would result in `0003_auto_20210522_1128.py` being picked as the 118 | > base migration which might not be accurate in every case and is not recommended. 119 | -------------------------------------------------------------------------------- /docs/utils.md: -------------------------------------------------------------------------------- 1 | # Utility Functions 2 | 3 | ::: migration_fixer.utils.fix_numbered_migration 4 | :docstring: 5 | 6 | ::: migration_fixer.utils.no_translations 7 | :docstring: 8 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main() -> None: 8 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_migration_fixer.settings") 9 | try: 10 | from django.core.management import execute_from_command_line 11 | except ImportError as exc: 12 | raise ImportError( 13 | "Couldn't import Django. Are you sure it's installed and " 14 | "available on your PYTHONPATH environment variable? Did you " 15 | "forget to activate a virtual environment?" 16 | ) from exc 17 | execute_from_command_line(sys.argv) 18 | 19 | 20 | if __name__ == "__main__": 21 | main() 22 | -------------------------------------------------------------------------------- /migration_fixer/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tj-django/django-migration-fixer/4826d3d82eb53840da1b538f56a2bbbda260dfb9/migration_fixer/__init__.py -------------------------------------------------------------------------------- /migration_fixer/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class MigrationFixerConfig(AppConfig): 5 | name = "migration_fixer" 6 | -------------------------------------------------------------------------------- /migration_fixer/management/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Top level management package for migration_fixer. 3 | """ 4 | -------------------------------------------------------------------------------- /migration_fixer/management/commands/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Top level commands package for migration_fixer. 3 | """ 4 | -------------------------------------------------------------------------------- /migration_fixer/management/commands/makemigrations.py: -------------------------------------------------------------------------------- 1 | """ 2 | Create a new django migration with support for fixing conflicts. 3 | """ 4 | 5 | import os 6 | from functools import partial 7 | 8 | from django.apps import apps 9 | from django.conf import settings 10 | from django.core.management.base import CommandError 11 | from django.core.management.commands.makemigrations import Command as BaseCommand 12 | from django.db import DEFAULT_DB_ALIAS, connections, router 13 | from django.db.migrations.loader import MigrationLoader 14 | from git import GitCommandError, InvalidGitRepositoryError, Repo 15 | 16 | from migration_fixer.utils import ( 17 | fix_numbered_migration, 18 | get_filename, 19 | get_migration_module_path, 20 | migration_sorter, 21 | no_translations, 22 | ) 23 | 24 | 25 | class Command(BaseCommand): 26 | """ 27 | Create a new django migration with support for fixing conflicts. 28 | """ 29 | 30 | help = "Creates new migration(s) for apps and fix conflicts." 31 | success_msg = "Successfully fixed migrations." 32 | 33 | def __init__(self, *args, repo=None, **kwargs): 34 | super().__init__(*args, **kwargs) 35 | self.cwd = os.getcwd() 36 | self.repo = repo or Repo.init(self.cwd) 37 | 38 | def add_arguments(self, parser): 39 | parser.add_argument( 40 | "--fix", 41 | action="store_true", 42 | help="Fix migrations conflicts.", 43 | ) 44 | parser.add_argument( 45 | "-b", 46 | "--default-branch", 47 | help="The name of the default branch.", 48 | default="main", 49 | ) 50 | parser.add_argument( 51 | "-s", 52 | "--skip-default-branch-update", 53 | help="Skip pulling the latest changes from the default branch.", 54 | action="store_true", 55 | ) 56 | parser.add_argument( 57 | "-r", 58 | "--remote", 59 | help="Git remote.", 60 | default="origin", 61 | ) 62 | parser.add_argument( 63 | "-f", 64 | "--force-update", 65 | help="Force update the default branch.", 66 | action="store_true", 67 | ) 68 | super().add_arguments(parser) 69 | 70 | @no_translations 71 | def handle(self, *app_labels, **options): 72 | self.merge = options["merge"] 73 | self.fix = options["fix"] 74 | self.force_update = options["force_update"] 75 | self.skip_default_branch_update = options["skip_default_branch_update"] 76 | self.default_branch = options["default_branch"] 77 | self.remote = options["remote"] 78 | 79 | if self.fix: 80 | try: 81 | super().handle(*app_labels, **options) 82 | except CommandError as e: 83 | [message] = e.args 84 | if "Conflicting migrations" in message: 85 | if self.verbosity >= 2: 86 | self.stdout.write("Verifying git repository...") 87 | 88 | try: 89 | self.repo.git_dir and self.repo.head.commit 90 | except (ValueError, InvalidGitRepositoryError): 91 | is_git_repo = False 92 | else: 93 | is_git_repo = True 94 | 95 | if not is_git_repo: 96 | raise CommandError( 97 | self.style.ERROR( 98 | f"Git repository is not yet setup. " 99 | "Please run (git init) in" 100 | f'\n"{self.cwd}"' 101 | ) 102 | ) 103 | 104 | if self.verbosity >= 2: 105 | self.stdout.write("Retrieving the current branch...") 106 | 107 | if self.repo.is_dirty(): # pragma: no cover 108 | raise CommandError( 109 | self.style.ERROR( 110 | "Git repository has uncommitted changes. " 111 | "Please commit any outstanding changes." 112 | ) 113 | ) 114 | 115 | if not self.skip_default_branch_update: 116 | if self.verbosity >= 2: 117 | self.stdout.write( 118 | f"Fetching git remote {self.remote} changes on: {self.default_branch}" 119 | ) 120 | 121 | try: 122 | remote = self.repo.remotes[self.remote] 123 | remote.fetch( 124 | f"{self.default_branch}:{self.default_branch}", # noqa 125 | force=self.force_update, 126 | ) 127 | except GitCommandError: # pragma: no cover 128 | try: 129 | remote = self.repo.remotes[self.remote] 130 | remote.pull( 131 | self.default_branch, 132 | force=self.force_update, 133 | ) 134 | except GitCommandError as e: 135 | raise CommandError( 136 | self.style.ERROR( 137 | f"Unable to retrieve changes from {self.remote} branch " 138 | f"'{self.default_branch}': {e.stderr}", 139 | ), 140 | ) 141 | 142 | default_branch_commit = self.repo.commit(self.default_branch) 143 | current_commit = self.repo.head.commit 144 | 145 | if self.verbosity >= 2: 146 | self.stdout.write( 147 | f"Retrieving the last commit sha on: {self.default_branch}" 148 | ) 149 | 150 | # Load the current graph state. Pass in None for the connection so 151 | # the loader doesn't try to resolve replaced migrations from DB. 152 | loader = MigrationLoader(None, ignore_no_migrations=True) 153 | 154 | # Raise an error if any migrations are applied before their dependencies. 155 | consistency_check_labels = { 156 | config.label for config in apps.get_app_configs() 157 | } 158 | # Non-default databases are only checked if database routers used. 159 | aliases_to_check = ( 160 | connections if settings.DATABASE_ROUTERS else [DEFAULT_DB_ALIAS] 161 | ) 162 | for alias in sorted(aliases_to_check): 163 | connection = connections[alias] 164 | if connection.settings_dict[ 165 | "ENGINE" 166 | ] != "django.db.backends.dummy" and any( 167 | # At least one model must be migrated to the database. 168 | router.allow_migrate( 169 | connection.alias, 170 | app_label, 171 | model_name=model._meta.object_name, 172 | ) 173 | for app_label in consistency_check_labels 174 | for model in apps.get_app_config(app_label).get_models() 175 | ): 176 | loader.check_consistent_history(connection) 177 | 178 | conflict_leaf_nodes = loader.detect_conflicts() 179 | 180 | for app_label, leaf_nodes in conflict_leaf_nodes.items(): 181 | migration_module, _ = loader.migrations_module(app_label) 182 | migration_path = get_migration_module_path(migration_module) 183 | 184 | with migration_path: 185 | if self.verbosity >= 2: 186 | self.stdout.write( 187 | "Retrieving changed files between " 188 | f"the current branch and {self.default_branch}" 189 | ) 190 | 191 | try: 192 | diff_index = default_branch_commit.diff(current_commit) 193 | 194 | # Files different on the current branch 195 | changed_files = [ 196 | diff.b_path 197 | for diff in diff_index 198 | if ( 199 | str(migration_path) 200 | in getattr(diff.a_blob, "abspath", "") 201 | or str(migration_path) 202 | in getattr(diff.b_blob, "abspath", "") 203 | ) 204 | ] 205 | 206 | sorted_changed_files = sorted( 207 | changed_files, 208 | key=partial(migration_sorter, app_label=app_label), 209 | ) 210 | 211 | # Local migration 212 | local_filenames = [ 213 | get_filename(p) for p in sorted_changed_files 214 | ] 215 | 216 | # Calculate the last changed file on the default branch 217 | conflict_bases = [ 218 | name 219 | for name in leaf_nodes 220 | if name not in local_filenames 221 | ] 222 | 223 | if not conflict_bases: # pragma: no cover 224 | raise CommandError( 225 | self.style.ERROR( 226 | f"Unable to determine the last migration on: " 227 | f"{self.default_branch}. " 228 | "Please verify the target branch using" 229 | '"-b [target branch]".', 230 | ) 231 | ) 232 | 233 | conflict_base = conflict_bases[0] 234 | 235 | if self.verbosity >= 2: 236 | self.stdout.write( 237 | f"Retrieving the last migration on: {self.default_branch}" 238 | ) 239 | 240 | seed_split = conflict_base.split("_") 241 | 242 | if ( 243 | seed_split 244 | and len(seed_split) > 1 245 | and str(seed_split[0]).isdigit() 246 | ): 247 | if self.verbosity >= 2: 248 | self.stdout.write( 249 | "Fixing numbered migration..." 250 | ) 251 | 252 | fix_numbered_migration( 253 | app_label=app_label, 254 | migration_path=migration_path, 255 | seed=int(seed_split[0]), 256 | start_name=conflict_base, 257 | changed_files=sorted_changed_files, 258 | writer=( 259 | lambda m: ( 260 | self.stdout.write(m) 261 | if self.verbosity >= 2 262 | else lambda x: x 263 | ) 264 | ), 265 | ) 266 | else: # pragma: no cover 267 | raise ValueError( 268 | f"Unable to fix migration: {conflict_base}. \n" 269 | f"NOTE: It needs to begin with a number. eg. 0001_*", 270 | ) 271 | except (ValueError, IndexError, TypeError) as e: 272 | self.stderr.write(f"Error: {e}") 273 | else: 274 | self.stdout.write(self.success_msg) 275 | 276 | else: 277 | return super(Command, self).handle(*app_labels, **options) 278 | -------------------------------------------------------------------------------- /migration_fixer/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tj-django/django-migration-fixer/4826d3d82eb53840da1b538f56a2bbbda260dfb9/migration_fixer/tests/__init__.py -------------------------------------------------------------------------------- /migration_fixer/tests/management/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tj-django/django-migration-fixer/4826d3d82eb53840da1b538f56a2bbbda260dfb9/migration_fixer/tests/management/__init__.py -------------------------------------------------------------------------------- /migration_fixer/tests/management/commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tj-django/django-migration-fixer/4826d3d82eb53840da1b538f56a2bbbda260dfb9/migration_fixer/tests/management/commands/__init__.py -------------------------------------------------------------------------------- /migration_fixer/tests/management/commands/_constants.py: -------------------------------------------------------------------------------- 1 | DEFAULT_BRANCH = "main" 2 | # Single merge to main 3 | TEST_01_MIGRATION_BRANCH = "feature/migration-test-01" 4 | # Single merge to main after 01 is merged (single conflict) 5 | TEST_02_MIGRATION_BRANCH = "feature/migration-test-02" 6 | # Single merge to main after 01 is merged (multiple conflicts) 7 | TEST_03_MIGRATION_BRANCH = "feature/migration-test-03" 8 | # Single merge to main after 01 is merged (named module) 9 | TEST_04_MIGRATION_BRANCH = "feature/migration-test-04" 10 | # Multiple migrations with a named migration file 11 | TEST_05_MIGRATION_BRANCH = "feature/migration-test-05" 12 | -------------------------------------------------------------------------------- /migration_fixer/tests/management/commands/_utils.py: -------------------------------------------------------------------------------- 1 | import contextlib 2 | import os 3 | from io import StringIO 4 | 5 | from django.core.management import call_command 6 | 7 | from migration_fixer.tests.management.commands.conftest import GitRepo 8 | 9 | 10 | def execute_command(cmd, *args, **kwargs): 11 | out = StringIO() 12 | kwargs["stdout"] = out 13 | kwargs["stderr"] = out 14 | call_command(cmd, *args, **kwargs) 15 | output = out.getvalue() 16 | 17 | return output 18 | 19 | 20 | @contextlib.contextmanager 21 | def temporary_checkout( 22 | git_repo: GitRepo, default_branch_name: str, target_branch_name: str 23 | ): 24 | cwd = os.getcwd() 25 | 26 | try: 27 | os.chdir(git_repo.workspace) 28 | # Clean all untracked files 29 | git_repo.api.git.clean("-xdf") 30 | 31 | target_branch = git_repo.api.heads[target_branch_name] 32 | 33 | target_branch.checkout(force=True) 34 | 35 | yield target_branch 36 | 37 | finally: 38 | # Clean all untracked files 39 | git_repo.api.git.clean("-xdf") 40 | 41 | default_branch = git_repo.api.heads[default_branch_name] 42 | 43 | default_branch.checkout(force=True) 44 | 45 | os.chdir(cwd) 46 | -------------------------------------------------------------------------------- /migration_fixer/tests/management/commands/conftest.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pathlib 3 | 4 | import pytest 5 | from git import Repo 6 | from pytest_shutil.workspace import Workspace 7 | 8 | 9 | @pytest.fixture(autouse=True) 10 | def use_demo_app(settings): 11 | settings.INSTALLED_APPS = [ 12 | "django.contrib.auth", 13 | "django.contrib.contenttypes", 14 | "migration_fixer", 15 | "migration_fixer.tests.demo", 16 | ] 17 | 18 | 19 | class GitRepo(Workspace): 20 | def __init__(self, workspace, delete=False): 21 | super(GitRepo, self).__init__(workspace, delete) 22 | self.api = Repo.init(self.workspace) 23 | self.uri = "file://%s" % self.workspace 24 | 25 | 26 | @pytest.fixture 27 | def git_repo(settings): 28 | workspace = pathlib.Path( 29 | os.path.join(settings.BASE_DIR, "migration_fixer", "tests", "demo") 30 | ) 31 | 32 | with GitRepo(workspace=workspace) as repo: 33 | yield repo 34 | 35 | 36 | @pytest.fixture 37 | def invalid_git_repo(settings): 38 | workspace = os.path.join(settings.BASE_DIR, "non_existing") 39 | 40 | with GitRepo(workspace=workspace, delete=True) as repo: 41 | yield repo 42 | -------------------------------------------------------------------------------- /migration_fixer/tests/management/commands/test_makemigrations.py: -------------------------------------------------------------------------------- 1 | """Tests for `migration_fixer` package.""" 2 | 3 | import pytest 4 | from django.core.management.base import CommandError 5 | 6 | from migration_fixer.management.commands.makemigrations import Command 7 | from migration_fixer.tests.management.commands._constants import ( 8 | TEST_01_MIGRATION_BRANCH, 9 | TEST_02_MIGRATION_BRANCH, 10 | TEST_03_MIGRATION_BRANCH, 11 | TEST_04_MIGRATION_BRANCH, 12 | TEST_05_MIGRATION_BRANCH, 13 | ) 14 | from migration_fixer.tests.management.commands._utils import ( 15 | execute_command, 16 | temporary_checkout, 17 | ) 18 | 19 | 20 | @pytest.mark.env("invalid_repo") 21 | @pytest.mark.django_db 22 | def test_invalid_repo(invalid_git_repo, mocker): 23 | mocker.patch( 24 | "django.core.management.commands.makemigrations.Command.handle", 25 | side_effect=CommandError("Conflicting migrations detected"), 26 | ) 27 | cmd = Command(repo=invalid_git_repo.api) 28 | cmd.verbosity = 1 29 | 30 | with pytest.raises(CommandError) as exc_info: 31 | execute_command(cmd, fix=True) 32 | 33 | assert "Git repository is not yet setup." in str(exc_info.value) 34 | 35 | 36 | @pytest.mark.env("test_01") 37 | @pytest.mark.django_db 38 | def test_run_makemigrations_is_valid_without_any_conflicts(git_repo): 39 | cmd = Command(repo=git_repo.api) 40 | 41 | with temporary_checkout( 42 | git_repo, 43 | default_branch_name=TEST_01_MIGRATION_BRANCH, 44 | target_branch_name=TEST_01_MIGRATION_BRANCH, 45 | ) as target_branch: 46 | output1 = execute_command(cmd) 47 | output2 = execute_command(cmd, fix=True) 48 | 49 | assert target_branch.name == TEST_01_MIGRATION_BRANCH 50 | assert output1 == "No changes detected\n" 51 | assert output2 == "No changes detected\n" 52 | 53 | 54 | @pytest.mark.env("test_01") 55 | @pytest.mark.django_db 56 | def test_run_makemigrations_is_valid_without_any_conflicts_verbose(git_repo): 57 | cmd = Command(repo=git_repo.api) 58 | 59 | with temporary_checkout( 60 | git_repo, 61 | default_branch_name=TEST_01_MIGRATION_BRANCH, 62 | target_branch_name=TEST_01_MIGRATION_BRANCH, 63 | ) as target_branch: 64 | output1 = execute_command(cmd, verbosity=2) 65 | output2 = execute_command(cmd, verbosity=2, fix=True) 66 | 67 | assert target_branch.name == TEST_01_MIGRATION_BRANCH 68 | assert output1 == "No changes detected\n" 69 | assert output2 == "No changes detected\n" 70 | 71 | 72 | @pytest.mark.env("test_02") 73 | @pytest.mark.django_db 74 | def test_run_makemigrations_with_fix_is_valid_for_conflicts(git_repo): 75 | cmd = Command(repo=git_repo.api) 76 | 77 | with temporary_checkout( 78 | git_repo, 79 | default_branch_name=TEST_01_MIGRATION_BRANCH, 80 | target_branch_name=TEST_02_MIGRATION_BRANCH, 81 | ) as target_branch: 82 | output = execute_command(cmd, default_branch=TEST_01_MIGRATION_BRANCH, fix=True) 83 | 84 | assert target_branch.name == TEST_02_MIGRATION_BRANCH 85 | assert output == f"{cmd.success_msg}\n" 86 | 87 | 88 | @pytest.mark.env("test_02") 89 | @pytest.mark.django_db 90 | def test_run_makemigrations_with_fix_is_valid_for_conflicts_verbose(git_repo): 91 | cmd = Command(repo=git_repo.api) 92 | expected_output = f"""Verifying git repository... 93 | Retrieving the current branch... 94 | Fetching git remote origin changes on: {TEST_01_MIGRATION_BRANCH} 95 | Retrieving the last commit sha on: {TEST_01_MIGRATION_BRANCH} 96 | Retrieving changed files between the current branch and {TEST_01_MIGRATION_BRANCH} 97 | Retrieving the last migration on: {TEST_01_MIGRATION_BRANCH} 98 | Fixing numbered migration... 99 | Updating migration "0002_alter_testmodel_active.py" dependency to 0002_alter_testmodel_age 100 | Renaming migration "0002_alter_testmodel_active.py" to "0003_alter_testmodel_active.py" 101 | Successfully fixed migrations. 102 | """ 103 | 104 | with temporary_checkout( 105 | git_repo, 106 | default_branch_name=TEST_01_MIGRATION_BRANCH, 107 | target_branch_name=TEST_02_MIGRATION_BRANCH, 108 | ) as target_branch: 109 | output = execute_command( 110 | cmd, default_branch=TEST_01_MIGRATION_BRANCH, verbosity=2, fix=True 111 | ) 112 | 113 | assert target_branch.name == TEST_02_MIGRATION_BRANCH 114 | assert output == expected_output 115 | 116 | 117 | @pytest.mark.env("test_02") 118 | @pytest.mark.django_db 119 | def test_run_makemigrations_with_fix_and_skip_update_is_valid_for_conflicts(git_repo): 120 | cmd = Command(repo=git_repo.api) 121 | 122 | with temporary_checkout( 123 | git_repo, 124 | default_branch_name=TEST_01_MIGRATION_BRANCH, 125 | target_branch_name=TEST_02_MIGRATION_BRANCH, 126 | ) as target_branch: 127 | output = execute_command( 128 | cmd, 129 | default_branch=TEST_01_MIGRATION_BRANCH, 130 | fix=True, 131 | skip_default_branch_update=True, 132 | ) 133 | 134 | assert target_branch.name == TEST_02_MIGRATION_BRANCH 135 | assert output == f"{cmd.success_msg}\n" 136 | 137 | 138 | @pytest.mark.env("test_02") 139 | @pytest.mark.django_db 140 | def test_run_makemigrations_with_fix_and_skip_update_is_valid_for_conflicts_verbose( 141 | git_repo, 142 | ): 143 | cmd = Command(repo=git_repo.api) 144 | expected_output = f"""Verifying git repository... 145 | Retrieving the current branch... 146 | Retrieving the last commit sha on: {TEST_01_MIGRATION_BRANCH} 147 | Retrieving changed files between the current branch and {TEST_01_MIGRATION_BRANCH} 148 | Retrieving the last migration on: {TEST_01_MIGRATION_BRANCH} 149 | Fixing numbered migration... 150 | Updating migration "0002_alter_testmodel_active.py" dependency to 0002_alter_testmodel_age 151 | Renaming migration "0002_alter_testmodel_active.py" to "0003_alter_testmodel_active.py" 152 | Successfully fixed migrations. 153 | """ 154 | 155 | with temporary_checkout( 156 | git_repo, 157 | default_branch_name=TEST_01_MIGRATION_BRANCH, 158 | target_branch_name=TEST_02_MIGRATION_BRANCH, 159 | ) as target_branch: 160 | output = execute_command( 161 | cmd, 162 | default_branch=TEST_01_MIGRATION_BRANCH, 163 | verbosity=2, 164 | fix=True, 165 | skip_default_branch_update=True, 166 | ) 167 | 168 | assert target_branch.name == TEST_02_MIGRATION_BRANCH 169 | assert output == expected_output 170 | 171 | 172 | @pytest.mark.env("test_03") 173 | @pytest.mark.django_db 174 | def test_run_makemigrations_with_fix_is_valid_for_multiple_file_conflicts(git_repo): 175 | cmd = Command(repo=git_repo.api) 176 | 177 | with temporary_checkout( 178 | git_repo, 179 | default_branch_name=TEST_01_MIGRATION_BRANCH, 180 | target_branch_name=TEST_03_MIGRATION_BRANCH, 181 | ) as target_branch: 182 | output = execute_command(cmd, default_branch=TEST_01_MIGRATION_BRANCH, fix=True) 183 | 184 | assert target_branch.name == TEST_03_MIGRATION_BRANCH 185 | assert output == f"{cmd.success_msg}\n" 186 | 187 | 188 | @pytest.mark.env("test_03") 189 | @pytest.mark.django_db 190 | def test_run_makemigrations_with_fix_is_valid_for_multiple_file_conflicts_verbose( 191 | git_repo, 192 | ): 193 | cmd = Command(repo=git_repo.api) 194 | expected_output = f"""Verifying git repository... 195 | Retrieving the current branch... 196 | Fetching git remote origin changes on: {TEST_01_MIGRATION_BRANCH} 197 | Retrieving the last commit sha on: {TEST_01_MIGRATION_BRANCH} 198 | Retrieving changed files between the current branch and {TEST_01_MIGRATION_BRANCH} 199 | Retrieving the last migration on: {TEST_01_MIGRATION_BRANCH} 200 | Fixing numbered migration... 201 | Updating migration "0002_testmodel_created_by.py" dependency to 0002_alter_testmodel_age 202 | Renaming migration "0002_testmodel_created_by.py" to "0003_testmodel_created_by.py" 203 | Updating migration "0003_auto_20210708_1317.py" dependency to 0003_testmodel_created_by 204 | Renaming migration "0003_auto_20210708_1317.py" to "0004_auto_20210708_1317.py" 205 | Successfully fixed migrations. 206 | """ 207 | 208 | with temporary_checkout( 209 | git_repo, 210 | default_branch_name=TEST_01_MIGRATION_BRANCH, 211 | target_branch_name=TEST_03_MIGRATION_BRANCH, 212 | ) as target_branch: 213 | output = execute_command( 214 | cmd, default_branch=TEST_01_MIGRATION_BRANCH, verbosity=2, fix=True 215 | ) 216 | 217 | assert target_branch.name == TEST_03_MIGRATION_BRANCH 218 | assert output == expected_output 219 | 220 | 221 | @pytest.mark.env("test_04") 222 | @pytest.mark.django_db 223 | def test_run_makemigrations_fix_with_an_invalid_module(git_repo): 224 | expected_output = """Error: Unable to fix migration for "demo" app: testmodel_dob.py 225 | NOTE: It needs to begin with a number. eg. 0001_* 226 | """ 227 | cmd = Command(repo=git_repo.api) 228 | 229 | with temporary_checkout( 230 | git_repo, 231 | default_branch_name=TEST_01_MIGRATION_BRANCH, 232 | target_branch_name=TEST_04_MIGRATION_BRANCH, 233 | ) as target_branch: 234 | output = execute_command(cmd, default_branch=TEST_01_MIGRATION_BRANCH, fix=True) 235 | 236 | assert target_branch.name == TEST_04_MIGRATION_BRANCH 237 | assert expected_output == output 238 | 239 | 240 | @pytest.mark.env("test_05") 241 | @pytest.mark.django_db 242 | def test_run_makemigrations_fix_with_mixed_invalid_modules(git_repo): 243 | expected_output = """Error: Unable to fix migration for "demo" app: custom_migration.py 244 | NOTE: It needs to begin with a number. eg. 0001_* 245 | """ 246 | cmd = Command(repo=git_repo.api) 247 | 248 | with temporary_checkout( 249 | git_repo, 250 | default_branch_name=TEST_01_MIGRATION_BRANCH, 251 | target_branch_name=TEST_05_MIGRATION_BRANCH, 252 | ) as target_branch: 253 | output = execute_command(cmd, default_branch=TEST_01_MIGRATION_BRANCH, fix=True) 254 | 255 | assert target_branch.name == TEST_05_MIGRATION_BRANCH 256 | assert expected_output == output 257 | -------------------------------------------------------------------------------- /migration_fixer/tests/test_utils.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from django.utils import translation 3 | 4 | from migration_fixer.utils import _clean_message, _decode_message, no_translations 5 | 6 | 7 | @pytest.mark.env("utils") 8 | def test__clean_message(): 9 | message = "New\n\rTest\n\r" 10 | expected_output = "New\n\rTest" 11 | 12 | current_output = _clean_message(message) 13 | 14 | assert expected_output == current_output 15 | 16 | 17 | @pytest.mark.env("utils") 18 | def test__decode_message(): 19 | encoding = "utf-8" 20 | message = b"\xe2\x86\x92" 21 | expected_output = "→" 22 | 23 | current_output = _decode_message(message, encoding) 24 | 25 | assert expected_output == current_output 26 | 27 | 28 | @pytest.mark.env("utils") 29 | def test_no_translations(): 30 | @no_translations 31 | def do_not_translate(): 32 | assert translation.get_language() is None 33 | 34 | do_not_translate() 35 | -------------------------------------------------------------------------------- /migration_fixer/utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | from importlib import import_module 4 | from itertools import count 5 | from pathlib import Path 6 | from typing import Callable, List 7 | 8 | DEFAULT_TIMEOUT = 120 9 | MIGRATION_REGEX = "\\((?P<comma>['\"]){app_label}(['\"]),\\s(['\"])(?P<conflict_migration>.*)(['\"])\\)," 10 | 11 | 12 | def _clean_message(output: str) -> str: 13 | """Strips the succeeding new line and carriage return characters.""" 14 | return output.rstrip("\n\r") 15 | 16 | 17 | def _decode_message(output: bytes, encoding: str) -> str: 18 | """Converts bytes to string, stripping white spaces.""" 19 | return output.decode(encoding).strip() 20 | 21 | 22 | def _update_migration(conflict_path: Path, app_label: str, prev_migration: str) -> None: 23 | """Modify the migration file.""" 24 | regex = MIGRATION_REGEX.format(app_label=app_label) 25 | replace_regex = re.compile(regex, re.I) 26 | 27 | match = replace_regex.search(conflict_path.read_text()) 28 | 29 | if match: 30 | comma = match.group("comma") 31 | replacement = ( 32 | f"({comma}{app_label}{comma}, {comma}{prev_migration}{comma})," # noqa 33 | ) 34 | 35 | # Update the migration 36 | output = re.sub( 37 | replace_regex, 38 | replacement, 39 | conflict_path.read_text(), 40 | ) 41 | 42 | # Write to the conflict file. 43 | conflict_path.write_text(output) 44 | else: # pragma: no cover 45 | raise ValueError(f'Couldn\'t find "{regex}" in {conflict_path.name}') 46 | 47 | 48 | def migration_sorter(path: str, app_label: str) -> int: 49 | path = os.path.split(path)[-1] 50 | parts = path.split("_") 51 | key = parts[0] 52 | 53 | if not str(key).isdigit(): 54 | raise ValueError( 55 | f'Unable to fix migration for "{app_label}" app: {path}\n' 56 | f"NOTE: It needs to begin with a number. eg. 0001_*", 57 | ) 58 | 59 | return int(key) 60 | 61 | 62 | def fix_numbered_migration( 63 | *, 64 | app_label: str, 65 | migration_path: Path, 66 | seed: int, 67 | start_name: str, 68 | changed_files: List[str], 69 | writer: Callable[[str], None], 70 | ) -> None: 71 | """Resolve migration conflicts for numbered migrations.""" 72 | seen = [start_name] 73 | counter = count(seed + 1) # 0537 -> 538 74 | 75 | for path in changed_files: 76 | next_ = str(next(counter)) 77 | 78 | if len(next_) < 4: 79 | next_ = f"{next_}".rjust(4, "0") # 0537 80 | 81 | basename = os.path.basename(path) 82 | conflict_path = migration_path / basename 83 | conflict_parts = basename.split("_") 84 | 85 | conflict_parts[0] = next_ 86 | 87 | new_conflict_name = "_".join(conflict_parts) 88 | 89 | conflict_new_path = conflict_path.with_name(new_conflict_name) 90 | 91 | with conflict_path: 92 | prev_migration = seen[-1] 93 | 94 | writer( 95 | f'Updating migration "{conflict_path.name}" dependency to {prev_migration}' 96 | ) 97 | _update_migration(conflict_path, app_label, prev_migration) 98 | 99 | writer( 100 | f'Renaming migration "{conflict_path.name}" to "{conflict_new_path.name}"' 101 | ) 102 | # Rename the migration file 103 | conflict_path.rename(conflict_new_path) 104 | 105 | seen.append(conflict_new_path.stem) 106 | 107 | 108 | def no_translations(handle_func): 109 | """Decorator that forces a command to run with translations deactivated.""" 110 | 111 | def wrapped(*args, **kwargs): 112 | from django.utils import translation 113 | 114 | saved_locale = translation.get_language() 115 | translation.deactivate_all() 116 | try: 117 | res = handle_func(*args, **kwargs) 118 | finally: 119 | if saved_locale is not None: 120 | translation.activate(saved_locale) 121 | return res 122 | 123 | return wrapped 124 | 125 | 126 | def get_filename(path: str) -> str: 127 | """Return the file name from a path.""" 128 | return os.path.splitext(os.path.basename(path))[0] 129 | 130 | 131 | def get_migration_module_path(migration_module_path: str) -> Path: 132 | try: 133 | migration_module = import_module(migration_module_path) 134 | except ImportError as e: 135 | if "bad magic number" in str(e): 136 | raise ImportError( 137 | f"Couldn't import {migration_module_path} as it appears to be a stale .pyc file." 138 | ) from e 139 | else: 140 | raise 141 | 142 | return Path(os.path.dirname(os.path.abspath(migration_module.__file__))) 143 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: django-migration-fixer 2 | site_author: Tonye Jack 3 | site_description: Fix django migrations 4 | copyright: "© 2021 Tonye Jack" 5 | repo_url: https://github.com/tj-django/django-migration-fixer 6 | site_url: https://tj-django.github.io/django-migration-fixer 7 | theme: 8 | name: material 9 | language: en 10 | favicon: images/logo.png 11 | logo: images/logo.png 12 | palette: 13 | primary: blue 14 | accent: white 15 | icon: 16 | repo: fontawesome/brands/github-alt 17 | markdown_extensions: 18 | - pymdownx.highlight 19 | - pymdownx.superfences 20 | - pymdownx.inlinehilite 21 | - pymdownx.details 22 | - admonition 23 | - codehilite: 24 | css_class: highlight 25 | - mkautodoc 26 | nav: 27 | - Home: README.md 28 | - Command Options: command-options.md 29 | - API Reference: 30 | management: makemigrations.md 31 | utils: utils.md 32 | - More Examples: more-examples.md 33 | - ChangeLog: CHANGELOG.md 34 | 35 | extra_css: 36 | - css/custom.css 37 | -------------------------------------------------------------------------------- /mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | # Mypy configuration: 3 | # https://mypy.readthedocs.io/en/latest/config_file.html 4 | python_version = 3.6 5 | 6 | allow_redefinition = False 7 | check_untyped_defs = True 8 | disallow_untyped_decorators = True 9 | disallow_any_explicit = False 10 | disallow_any_generics = True 11 | disallow_untyped_calls = True 12 | ignore_errors = False 13 | ignore_missing_imports = True 14 | implicit_reexport = False 15 | strict_optional = True 16 | strict_equality = True 17 | no_implicit_optional = True 18 | warn_unused_ignores = True 19 | warn_redundant_casts = True 20 | warn_unused_configs = True 21 | warn_unreachable = True 22 | warn_no_return = True 23 | 24 | ;plugins = 25 | ; mypy_django_plugin.main 26 | ; 27 | ;[mypy.plugins.django-stubs] 28 | ;django_settings_module = django_model_subscription.settings 29 | 30 | [mypy-demo.*.migrations.*] 31 | # Django migrations should not produce any errors: 32 | ignore_errors = True 33 | 34 | [mypy-django_migration_fixer.*.settings.*] 35 | # Django settings should not produce any errors: 36 | ignore_errors = True 37 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ], 5 | "enabled": true, 6 | "prHourlyLimit": 10, 7 | "prConcurrentLimit": 5, 8 | "rebaseWhen": "behind-base-branch", 9 | "addLabels": [ 10 | "dependencies" 11 | ], 12 | "assignees": [ 13 | "jackton1" 14 | ], 15 | "assignAutomerge": true, 16 | "dependencyDashboard": true, 17 | "dependencyDashboardAutoclose": true, 18 | "lockFileMaintenance": { 19 | "enabled": true, 20 | "automerge": true 21 | }, 22 | "packageRules": [ 23 | { 24 | "matchUpdateTypes": ["major", "minor", "patch", "pin", "digest"], 25 | "automerge": true, 26 | "rebaseWhen": "behind-base-branch", 27 | "addLabels": [ 28 | "automerge" 29 | ] 30 | }, 31 | { 32 | "description": "docker images", 33 | "matchLanguages": [ 34 | "docker" 35 | ], 36 | "matchUpdateTypes": ["major", "minor", "patch", "pin", "digest"], 37 | "rebaseWhen": "behind-base-branch", 38 | "addLabels": [ 39 | "automerge" 40 | ], 41 | "automerge": true 42 | } 43 | ] 44 | } 45 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with python 3.8 3 | # To update, run: 4 | # 5 | # pip-compile 6 | # 7 | asgiref==3.8.1 8 | # via django 9 | django==5.2.2 10 | # via django-migration-fixer (setup.py) 11 | gitdb==4.0.12 12 | # via gitpython 13 | gitpython==3.1.44 14 | # via django-migration-fixer (setup.py) 15 | pytz==2025.2 16 | # via django 17 | smmap==5.0.2 18 | # via gitdb 19 | sqlparse==0.5.3 20 | # via django 21 | typing-extensions==4.14.0 22 | # via django-migration-fixer (setup.py) 23 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 1.3.6 3 | commit = True 4 | tag = False 5 | 6 | [bumpversion:file:setup.py] 7 | search = version="{current_version}" 8 | replace = version="{new_version}" 9 | 10 | [bumpversion:file:README.md] 11 | search = v{current_version} 12 | replace = v{new_version} 13 | 14 | [bdist_wheel] 15 | universal = 1 16 | 17 | [tool:pytest] 18 | DJANGO_SETTINGS_MODULE = django_migration_fixer.settings 19 | testpaths = migration_fixer/tests 20 | addopts = --ignore-glob=setup.* 21 | 22 | [flake8] 23 | exclude = 24 | docs, 25 | .tox, 26 | .eggs, 27 | setup.py, 28 | venv, 29 | max-line-length = 120 30 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """The setup script.""" 4 | 5 | from setuptools import find_packages, setup 6 | 7 | with open("README.md") as readme_file: 8 | readme = readme_file.read() 9 | 10 | deploy_requires = [ 11 | "bump2version", 12 | "readme_renderer[md]", 13 | ] 14 | 15 | docs_requires = [ 16 | "mkautodoc", 17 | "mkdocs>=1.6,<1.7", 18 | "portray", 19 | "mkdocs-material-extensions>=1.0.3", 20 | "pygments>=2.19,<2.20", 21 | "pymdown-extensions>=10.15,<10.16", 22 | ] 23 | 24 | install_requires = [ 25 | "django", 26 | "GitPython", 27 | "typing_extensions>=3.10.0.0", 28 | ] 29 | 30 | test_requires = [ 31 | "pytest>=3", 32 | "pytest-django", 33 | "bump2version", 34 | "pytest-sugar", 35 | "pytest-mock", 36 | "pytest-git", 37 | "tox", 38 | "tox-gh-actions", 39 | "coverage", 40 | "pip-tools", 41 | ] 42 | 43 | lint_requires = [ 44 | "flake8", 45 | "yamllint", 46 | "isort", 47 | "black", 48 | "mypy", 49 | ] 50 | 51 | extras_require = { 52 | "development": [ 53 | install_requires, 54 | deploy_requires, 55 | test_requires, 56 | lint_requires, 57 | ], 58 | "test": test_requires, 59 | "lint": lint_requires, 60 | "deploy": deploy_requires, 61 | "docs": docs_requires, 62 | } 63 | 64 | setup( 65 | author="Tonye Jack", 66 | author_email="jtonye@ymail.com", 67 | python_requires=">=3.6", 68 | classifiers=[ 69 | "Development Status :: 5 - Production/Stable", 70 | "Intended Audience :: Developers", 71 | "License :: OSI Approved :: MIT License", 72 | "Natural Language :: English", 73 | "Programming Language :: Python :: 3.6", 74 | "Programming Language :: Python :: 3.7", 75 | "Programming Language :: Python :: 3.8", 76 | "Programming Language :: Python :: 3.9", 77 | "Programming Language :: Python :: 3.10", 78 | "Programming Language :: Python :: Implementation :: CPython", 79 | "Programming Language :: Python :: Implementation :: PyPy", 80 | "Framework :: Django :: 1.11", 81 | "Framework :: Django :: 2.0", 82 | "Framework :: Django :: 2.1", 83 | "Framework :: Django :: 2.2", 84 | "Framework :: Django :: 3.0", 85 | "Framework :: Django :: 3.1", 86 | "Framework :: Django :: 3.2", 87 | ], 88 | description="Resolve migration errors", 89 | install_requires=install_requires, 90 | license="MIT license", 91 | long_description=readme, 92 | long_description_content_type="text/markdown", 93 | include_package_data=False, 94 | keywords=[ 95 | "migration fixer", 96 | "django migrations", 97 | "django migrations fixer", 98 | "django migrations auto fix", 99 | "migrations fix", 100 | "migrations conflict resolver", 101 | "django migrations", 102 | "django migrations autofix", 103 | ], 104 | name="django-migration-fixer", 105 | packages=find_packages(include=["migration_fixer", "migration_fixer.*"]), 106 | test_suite="tests", 107 | tests_require=test_requires, 108 | extras_require=extras_require, 109 | url="https://github.com/tj-django/django-migration-fixer", 110 | project_urls={ 111 | "Source": "https://github.com/tj-django/django-migration-fixer", 112 | "Documentation": "https://tj-django.github.io/django-migration-fixer", 113 | }, 114 | version="1.3.6", 115 | zip_safe=False, 116 | ) 117 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | minversion = 3.8.0 3 | skipsdist = false 4 | envlist = 5 | yamllint 6 | flake8 7 | mypy 8 | py36-django{11,20,21,22,30,31,32,main}-{linux,macos,windows} 9 | py37-django{11,20,21,22,30,31,32,main}-{linux,macos,windows} 10 | py38-django{11,20,21,22,30,31,32,main}-{linux,macos,windows} 11 | py39-django{11,20,21,22,30,31,32,main}-{linux,macos,windows} 12 | py310-django{21,22,30,31,32,main}-{linux,macos,windows} 13 | skip_missing_interpreters = true 14 | 15 | [gh-actions] 16 | python = 17 | 3.6: py36 18 | 3.7: py37 19 | 3.8: py38 20 | 3.9: py39 21 | 3.10: py310 22 | 23 | [gh-actions:env] 24 | PLATFORM = 25 | ubuntu-latest: linux 26 | macos-latest: macos 27 | windows-latest: windows 28 | 29 | [testenv] 30 | whitelist_externals = make 31 | passenv = * 32 | extras = 33 | test 34 | deps = 35 | django11: Django>=1.11.0,<2.0 36 | django20: Django>=2.0,<2.1 37 | django21: Django>=2.1,<2.2 38 | django22: Django>=2.2,<2.3 39 | django30: Django>=3.0,<3.1 40 | django31: Django>=3.1,<3.2 41 | django32: Django>=3.2,<3.3 42 | main: https://github.com/django/django/archive/main.tar.gz 43 | usedevelop = true 44 | commands = 45 | coverage run -m pytest -vv --basetemp={envtmpdir} -E invalid_repo 46 | coverage run -a -m pytest -vv --basetemp={envtmpdir} -E utils 47 | coverage run -a -m pytest -vv --basetemp={envtmpdir} -E test_01 48 | coverage run -a -m pytest -vv --basetemp={envtmpdir} -E test_02 49 | coverage run -a -m pytest -vv --basetemp={envtmpdir} -E test_03 50 | coverage run -a -m pytest -vv --basetemp={envtmpdir} -E test_04 51 | coverage run -a -m pytest -vv --basetemp={envtmpdir} -E test_05 52 | coverage xml 53 | 54 | [testenv:flake8] 55 | deps = flake8 56 | commands = 57 | flake8 . 58 | 59 | [testenv:yamllint] 60 | deps = yamllint 61 | changedir = {toxinidir} 62 | commands = 63 | yamllint --strict -f standard .github 64 | 65 | [testenv:mypy] 66 | basepython = python3.6 67 | deps = mypy==0.740 68 | commands = mypy . 69 | --------------------------------------------------------------------------------