├── .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] "
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 | 
2 |
3 | [](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 | [](https://codecov.io/gh/tj-django/django-migration-fixer)
5 | [](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 | [](https://github.com/tj-django/django-migration-fixer/actions/workflows/test.yml)
7 | [](https://github.com/tj-django/django-migration-fixer/actions/workflows/deploy.yml)
8 |
9 | [](https://pypi.python.org/pypi/django-migration-fixer)
10 | [](https://pypi.python.org/pypi/django-migration-fixer) [](https://pypi.python.org/pypi/django-migration-fixer) [](https://pepy.tech/project/django-migration-fixer)
11 | [](https://github.com/search?o=desc\&q=tj-django+django-migration-fixer+language%3AYAML\&s=\&type=Code)
12 | [](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 | 
80 |
81 | ### After running django-migration-fixer
82 |
83 | 
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
target branch of a Pull request. |
109 | | force-update | `string` | `false` | | Force update the target branch
locally when git fetch fails. |
110 | | skip-default-branch-update | `string` | `false` | | Skip pulling the latest
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 | [](https://tj-django.github.io/django-migration-fixer/)
2 |
3 | [](https://pypi.python.org/pypi/django-migration-fixer) [](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) [](https://codecov.io/gh/tj-django/django-migration-fixer) [](https://github.com/psf/black)
4 |
5 | [](https://lgtm.com/projects/g/tj-django/django-migration-fixer/alerts/) [](https://lgtm.com/projects/g/tj-django/django-migration-fixer/context:python) [](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 | [](https://github.com/tj-django/django-migration-fixer/actions/workflows/test.yml) [](https://github.com/tj-django/django-migration-fixer/actions/workflows/deploy.yml) [](https://github.com/tj-django/django-migration-fixer/actions/workflows/lint.yml)
8 |
9 | [](https://pypi.python.org/pypi/django-migration-fixer) [](https://pypi.python.org/pypi/django-migration-fixer) [](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['\"]){app_label}(['\"]),\\s(['\"])(?P.*)(['\"])\\),"
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 |
--------------------------------------------------------------------------------