You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
-**`mrt check --since <revision>`** — scan only migrations added since a given git revision or tag. Eliminates re-scanning the full history on every PR in large codebases. Works with any git ref: `--since main`, `--since v1.2.0`, `--since HEAD~3`.
14
+
-**pre-commit hook integration** — `.pre-commit-hooks.yaml` ships with pytest-mrt. Add `mrt check` to your pre-commit pipeline with two lines:
15
+
```yaml
16
+
- repo: https://github.com/croc100/pytest-mrt
17
+
rev: v1.3.0
18
+
hooks:
19
+
- id: mrt-check
20
+
```
21
+
- **Django-aware `mrt fix`** — `mrt fix <migration.py>` now works on Django migrations:
22
+
- `RunSQL` without `reverse_sql`: adds `reverse_sql=migrations.RunSQL.noop`
23
+
- `RunPython` without `reverse_code`: adds `reverse_code=migrations.RunPython.noop`
24
+
- `RemoveField`: injects a `RunPython(backup, restore)` operation before the field removal. The backup function copies column data to `_mrt_backups` using keyset pagination (safe for large tables, no server-side cursors). The restore function writes the data back when rolling back.
25
+
- `DeleteModel`: same as `RemoveField` but backs up all columns. The restore function uses `disable_constraint_checking()` to handle FK dependencies safely.
26
+
- Inline type codec (`__mrt_enc` / `__mrt_dec`) injected once per migration — no runtime pytest-mrt dependency in production migrations. Handles `Decimal`, `datetime` (naive + tz-aware), `date`, `time`, `UUID`, `bytes`.
27
+
- Use `--apply` to write the fix to the file.
28
+
- **`mrt clean-backups`** — removes backup rows from `_mrt_backups` after deployment is confirmed stable. Supports `--label` to remove a single migration's backup, `--list` to preview, `--yes` to skip confirmation.
29
+
30
+
### Changed
31
+
- `mrt fix`output for Django migrations includes a `[Django]` tag and a per-operation table (Line / Operation / Fix / Confidence).
For `RemoveField` and `DeleteModel`, the generated code backs up data to a `_mrt_backups` table before the migration runs, and restores it on rollback. After deployment is confirmed stable, clean up the backup rows:
-**`mrt check --since <revision>`** — check only migrations added since a given revision; eliminates the need to re-run the full history on every PR in large codebases
70
-
-**pre-commit hook integration** — `.pre-commit-hooks.yaml` + registration on pre-commit.com; run `mrt check` automatically before every push without manual CI setup
69
+
-**`mrt check --since <revision>`** — check only migrations added since a given revision; eliminates re-scanning full history on every PR
70
+
-**pre-commit hook** — `.pre-commit-hooks.yaml` ships with the package; two-line setup
71
+
-**Django-aware `mrt fix`** — auto-generates reverse operations for `RunSQL`, `RunPython`, `RemoveField`, `DeleteModel` with transactional DB backup/restore scaffolding
72
+
-**`mrt clean-backups`** — CLI command to remove `_mrt_backups` data after deployment
73
+
74
+
---
75
+
76
+
## v1.4.0 — Under consideration
77
+
78
+
-**`mrt check --watch`** — re-run on file change during development
79
+
-**Django: `squashmigrations` detection** — squashed migrations with unresolved refs
80
+
-**Per-pattern confidence scores** in JSON output
81
+
-**HTML report: source line links** — click a finding to jump to the migration file
82
+
-**Sentry integration** — report migration failures as Sentry events
83
+
-**GitHub App** — automated PR comments with migration risk summary
84
+
-**VS Code extension** — inline warnings in migration files
71
85
72
86
---
73
87
@@ -82,6 +96,7 @@ These are not committed to a specific version yet:
82
96
-**Sentry integration** — report migration failures as Sentry events
83
97
-**GitHub App** — automated PR comments with migration risk summary
84
98
-**VS Code extension** — inline warnings in migration files
99
+
-**`mrt fix --apply` batch mode** — fix all migration files in a directory at once
|`mrt drift`| Compare live DB schema against ORM models | Yes |
14
17
|`mrt report <dir>`| HTML safety report of entire migration history | No |
15
18
|`mrt explain <file>`| AI explanation in plain English | No (needs API key) |
16
19
|`mrt version`| Show installed version | No |
@@ -54,6 +57,19 @@ mrt check migrations/versions/
54
57
| Option | Description | Default |
55
58
|---|---|---|
56
59
|`--strict`| Also fail on warnings, not just errors | Off |
60
+
|`--since <ref>`| Only check migrations added since this git revision / tag | Off |
61
+
62
+
#### `--since` — incremental scanning
63
+
64
+
In large codebases, scanning the full migration history on every PR is wasteful. `--since` limits the scan to migrations whose files were added after the given git ref:
65
+
66
+
```bash
67
+
mrt check migrations/versions/ --since main
68
+
mrt check myapp/migrations/ --since v1.2.0
69
+
mrt check myapp/migrations/ --since HEAD~5
70
+
```
71
+
72
+
This is the recommended setup for CI: check only the migrations that changed in the current PR branch.
57
73
58
74
### Exit codes
59
75
@@ -90,11 +106,78 @@ When there are no problems:
90
106
91
107
---
92
108
109
+
## CLI: `mrt fix`
110
+
111
+
Auto-generates missing reverse operations. Works for both Alembic and Django migrations.
112
+
113
+
```bash
114
+
mrt fix <migration-file># preview
115
+
mrt fix <migration-file> --apply # write to file
116
+
```
117
+
118
+
### Alembic
119
+
120
+
Generates a missing or stub `downgrade()` function with the inverse operations inferred from `upgrade()`.
121
+
122
+
### Django (v1.3.0)
123
+
124
+
Detects and fixes four operation types:
125
+
126
+
| Operation | Fix | Confidence |
127
+
|---|---|---|
128
+
|`RunSQL` without `reverse_sql`| Adds `reverse_sql=migrations.RunSQL.noop`| High |
129
+
|`RunPython` without `reverse_code`| Adds `reverse_code=migrations.RunPython.noop`| Medium |
130
+
|`RemoveField`| Injects `RunPython(backup, restore)` before the op | Medium |
131
+
|`DeleteModel`| Injects `RunPython(backup, restore)` before the op | Medium |
132
+
133
+
For `RemoveField` and `DeleteModel`, the generated code:
134
+
135
+
1.**Backs up** the column/row data into a `_mrt_backups` table using keyset pagination (safe for large tables, no server-side cursors required)
136
+
2.**Restores** the data when the migration is reversed, with constraint checking disabled for FK safety
137
+
3.**Inlines a type codec** (`__mrt_enc`/`__mrt_dec`) directly into the migration file — no runtime dependency on pytest-mrt in your production migrations
138
+
139
+
After you've confirmed the deployment is stable and rollback is no longer needed:
|**`mrt fix`**| Yes |No (Django doesn't have a `downgrade()`) |
35
+
|**`mrt fix`**| Yes |Yes (v1.3.0) |
36
36
37
37
### Django migrations don't have `downgrade()` — how does pytest-mrt help?
38
38
39
-
For Django, pytest-mrt provides both **static analysis** and **dynamic rollback verification**:
39
+
For Django, pytest-mrt provides **static analysis**, **dynamic rollback verification**, and (since v1.3.0) **auto-fix**:
40
40
41
41
-**Static**: detects `RemoveField`, `DeleteModel`, `RunPython` without `reverse_code`, `RunSQL` without `reverse_sql`, unsafe `AddField` patterns, and more (10 Django-specific patterns).
42
42
-**Dynamic**: `DjangoMigrationRunner` runs the full `migrate` / `migrate --backwards` cycle and verifies data integrity, just like Alembic mode.
43
+
-**Fix** (`mrt fix --apply`): adds `reverse_sql`/`reverse_code` where missing and generates transactional backup/restore scaffolding for `RemoveField` and `DeleteModel`. The generated code is self-contained — no runtime dependency on pytest-mrt in your production migrations.
0 commit comments