Metadata-Version: 2.4
Name: migratecheck
Version: 0.1.0
Summary: Catch dangerous database migrations before they hit production
License: MIT
Project-URL: Repository, https://github.com/shahabRDZ/migratecheck
Keywords: database,migration,postgresql,safety,alembic,ci
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

<h1 align="center">migratecheck</h1>
<p align="center"><strong>Catch dangerous database migrations before they hit production</strong></p>
<p align="center">
  <img src="https://img.shields.io/badge/python-3.10+-blue?logo=python&logoColor=white" />
  <img src="https://img.shields.io/badge/PostgreSQL-focused-336791?logo=postgresql" />
  <img src="https://img.shields.io/badge/dependencies-zero-brightgreen" />
  <img src="https://img.shields.io/badge/license-MIT-green" />
</p>

---

## Install

```bash
pip install migratecheck
```

## Usage

```python
from migratecheck import analyze_sql

sql = open("alembic/versions/0042_add_column.py").read()
risks = analyze_sql(sql)

for risk in risks:
    print(f"[{risk.level.value}] {risk.message}")
    print(f"  Line: {risk.line}")
    print(f"  Fix:  {risk.suggestion}")
```

## What It Detects

| Risk | Level | Why |
|------|-------|-----|
| `ADD COLUMN NOT NULL` without default | Critical | Rewrites entire table, holds lock |
| `DROP TABLE` | Critical | Permanent data loss |
| `TRUNCATE` | Critical | Deletes all rows |
| `ALTER COLUMN TYPE` | Critical | Full table rewrite + exclusive lock |
| `LOCK TABLE` | Critical | Blocks all access |
| `DROP COLUMN` | Danger | Irreversible, may break app |
| `CREATE INDEX` (not concurrent) | Danger | Locks writes |
| `RENAME TABLE/COLUMN` | Danger | Breaks references |
| `ADD FOREIGN KEY` | Warning | Full table scan |
| `DROP INDEX` | Warning | May slow queries |

## Use in CI

```yaml
- name: Check migrations
  run: python -c "
    from migratecheck import analyze_sql
    import sys, glob
    for f in glob.glob('alembic/versions/*.py'):
      risks = analyze_sql(open(f).read())
      for r in risks:
        if r.level.value in ('critical', 'danger'):
          print(f'BLOCKED: {r.message}')
          sys.exit(1)
  "
```

## License

MIT
