delembic 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. delembic-0.2.0/.bumpversion.cfg +13 -0
  2. delembic-0.2.0/.github/workflows/release.yml +88 -0
  3. delembic-0.2.0/.gitignore +32 -0
  4. delembic-0.2.0/.readthedocs.yaml +17 -0
  5. delembic-0.2.0/PKG-INFO +155 -0
  6. delembic-0.2.0/README.md +137 -0
  7. delembic-0.2.0/docs/_build/html/.buildinfo +4 -0
  8. delembic-0.2.0/docs/_build/html/.doctrees/alembic-integration.doctree +0 -0
  9. delembic-0.2.0/docs/_build/html/.doctrees/changelog.doctree +0 -0
  10. delembic-0.2.0/docs/_build/html/.doctrees/cli-reference.doctree +0 -0
  11. delembic-0.2.0/docs/_build/html/.doctrees/configuration.doctree +0 -0
  12. delembic-0.2.0/docs/_build/html/.doctrees/dependency-tracking.doctree +0 -0
  13. delembic-0.2.0/docs/_build/html/.doctrees/environment.pickle +0 -0
  14. delembic-0.2.0/docs/_build/html/.doctrees/getting-started.doctree +0 -0
  15. delembic-0.2.0/docs/_build/html/.doctrees/index.doctree +0 -0
  16. delembic-0.2.0/docs/_build/html/.doctrees/internals.doctree +0 -0
  17. delembic-0.2.0/docs/_build/html/.doctrees/writing-migrations.doctree +0 -0
  18. delembic-0.2.0/docs/_build/html/_sources/alembic-integration.md.txt +112 -0
  19. delembic-0.2.0/docs/_build/html/_sources/changelog.md.txt +11 -0
  20. delembic-0.2.0/docs/_build/html/_sources/cli-reference.md.txt +169 -0
  21. delembic-0.2.0/docs/_build/html/_sources/configuration.md.txt +98 -0
  22. delembic-0.2.0/docs/_build/html/_sources/dependency-tracking.md.txt +125 -0
  23. delembic-0.2.0/docs/_build/html/_sources/getting-started.md.txt +133 -0
  24. delembic-0.2.0/docs/_build/html/_sources/index.md.txt +45 -0
  25. delembic-0.2.0/docs/_build/html/_sources/internals.md.txt +130 -0
  26. delembic-0.2.0/docs/_build/html/_sources/writing-migrations.md.txt +137 -0
  27. delembic-0.2.0/docs/_build/html/_static/base-stemmer.js +476 -0
  28. delembic-0.2.0/docs/_build/html/_static/basic.css +906 -0
  29. delembic-0.2.0/docs/_build/html/_static/check-solid.svg +4 -0
  30. delembic-0.2.0/docs/_build/html/_static/clipboard.min.js +7 -0
  31. delembic-0.2.0/docs/_build/html/_static/copy-button.svg +5 -0
  32. delembic-0.2.0/docs/_build/html/_static/copybutton.css +94 -0
  33. delembic-0.2.0/docs/_build/html/_static/copybutton.js +248 -0
  34. delembic-0.2.0/docs/_build/html/_static/copybutton_funcs.js +73 -0
  35. delembic-0.2.0/docs/_build/html/_static/debug.css +69 -0
  36. delembic-0.2.0/docs/_build/html/_static/doctools.js +150 -0
  37. delembic-0.2.0/docs/_build/html/_static/documentation_options.js +13 -0
  38. delembic-0.2.0/docs/_build/html/_static/english-stemmer.js +1066 -0
  39. delembic-0.2.0/docs/_build/html/_static/file.png +0 -0
  40. delembic-0.2.0/docs/_build/html/_static/language_data.js +13 -0
  41. delembic-0.2.0/docs/_build/html/_static/minus.png +0 -0
  42. delembic-0.2.0/docs/_build/html/_static/plus.png +0 -0
  43. delembic-0.2.0/docs/_build/html/_static/pygments.css +250 -0
  44. delembic-0.2.0/docs/_build/html/_static/scripts/furo-extensions.js +0 -0
  45. delembic-0.2.0/docs/_build/html/_static/scripts/furo.js +3 -0
  46. delembic-0.2.0/docs/_build/html/_static/scripts/furo.js.LICENSE.txt +7 -0
  47. delembic-0.2.0/docs/_build/html/_static/scripts/furo.js.map +1 -0
  48. delembic-0.2.0/docs/_build/html/_static/searchtools.js +693 -0
  49. delembic-0.2.0/docs/_build/html/_static/skeleton.css +296 -0
  50. delembic-0.2.0/docs/_build/html/_static/sphinx_highlight.js +159 -0
  51. delembic-0.2.0/docs/_build/html/_static/styles/furo-extensions.css +2 -0
  52. delembic-0.2.0/docs/_build/html/_static/styles/furo-extensions.css.map +1 -0
  53. delembic-0.2.0/docs/_build/html/_static/styles/furo.css +2 -0
  54. delembic-0.2.0/docs/_build/html/_static/styles/furo.css.map +1 -0
  55. delembic-0.2.0/docs/_build/html/alembic-integration.html +423 -0
  56. delembic-0.2.0/docs/_build/html/changelog.html +328 -0
  57. delembic-0.2.0/docs/_build/html/cli-reference.html +499 -0
  58. delembic-0.2.0/docs/_build/html/configuration.html +491 -0
  59. delembic-0.2.0/docs/_build/html/dependency-tracking.html +446 -0
  60. delembic-0.2.0/docs/_build/html/genindex.html +281 -0
  61. delembic-0.2.0/docs/_build/html/getting-started.html +462 -0
  62. delembic-0.2.0/docs/_build/html/index.html +408 -0
  63. delembic-0.2.0/docs/_build/html/internals.html +458 -0
  64. delembic-0.2.0/docs/_build/html/objects.inv +0 -0
  65. delembic-0.2.0/docs/_build/html/search.html +292 -0
  66. delembic-0.2.0/docs/_build/html/searchindex.js +1 -0
  67. delembic-0.2.0/docs/_build/html/writing-migrations.html +466 -0
  68. delembic-0.2.0/docs/_static/.gitkeep +0 -0
  69. delembic-0.2.0/docs/alembic-integration.md +112 -0
  70. delembic-0.2.0/docs/changelog.md +11 -0
  71. delembic-0.2.0/docs/cli-reference.md +169 -0
  72. delembic-0.2.0/docs/conf.py +40 -0
  73. delembic-0.2.0/docs/configuration.md +98 -0
  74. delembic-0.2.0/docs/dependency-tracking.md +125 -0
  75. delembic-0.2.0/docs/getting-started.md +133 -0
  76. delembic-0.2.0/docs/index.md +45 -0
  77. delembic-0.2.0/docs/internals.md +130 -0
  78. delembic-0.2.0/docs/requirements.txt +4 -0
  79. delembic-0.2.0/docs/writing-migrations.md +137 -0
  80. delembic-0.2.0/pyproject.toml +33 -0
  81. delembic-0.2.0/src/delembic/__init__.py +4 -0
  82. delembic-0.2.0/src/delembic/alembic_compat.py +65 -0
  83. delembic-0.2.0/src/delembic/cli.py +199 -0
  84. delembic-0.2.0/src/delembic/config.py +38 -0
  85. delembic-0.2.0/src/delembic/dag.py +37 -0
  86. delembic-0.2.0/src/delembic/db.py +75 -0
  87. delembic-0.2.0/src/delembic/executor.py +115 -0
  88. delembic-0.2.0/src/delembic/migration.py +14 -0
  89. delembic-0.2.0/src/delembic/registry.py +34 -0
  90. delembic-0.2.0/tests/__init__.py +0 -0
  91. delembic-0.2.0/tests/test_alembic_compat.py +97 -0
  92. delembic-0.2.0/tests/test_cli.py +176 -0
  93. delembic-0.2.0/tests/test_dag.py +74 -0
  94. delembic-0.2.0/tests/test_db.py +83 -0
  95. delembic-0.2.0/tests/test_executor.py +165 -0
  96. delembic-0.2.0/tests/test_registry.py +63 -0
@@ -0,0 +1,13 @@
1
+ [bumpversion]
2
+ current_version = 0.2.0
3
+ commit = True
4
+ tag = True
5
+ tag_name = v{new_version}
6
+
7
+ [bumpversion:file:pyproject.toml]
8
+ search = version = "{current_version}"
9
+ replace = version = "{new_version}"
10
+
11
+ [bumpversion:file:src/delembic/__init__.py]
12
+ search = __version__ = "{current_version}"
13
+ replace = __version__ = "{new_version}"
@@ -0,0 +1,88 @@
1
+ name: Build and Release
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main # only trigger on main branch
7
+
8
+ permissions:
9
+ contents: write
10
+ id-token: write
11
+
12
+ jobs:
13
+ release:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - name: Checkout code
17
+ uses: actions/checkout@v4
18
+ with:
19
+ fetch-depth: 0 # required to fetch tags
20
+
21
+ - name: Set up Python
22
+ uses: actions/setup-python@v5
23
+ with:
24
+ python-version: "3.10"
25
+
26
+ - name: Install bump2version & build tools
27
+ run: |
28
+ python -m pip install --upgrade pip
29
+ pip install bump2version build wheel
30
+
31
+ - name: Configure git user
32
+ run: |
33
+ git config --global user.name "github-actions[bot]"
34
+ git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
35
+
36
+ - name: Fetch tags
37
+ run: git fetch --tags
38
+
39
+ - name: Determine bump type
40
+ id: bump_type
41
+ run: |
42
+ msg="${{ github.event.head_commit.message }}"
43
+ if [[ "$msg" == *"bump: major"* ]]; then
44
+ echo "value=major" >> $GITHUB_OUTPUT
45
+ elif [[ "$msg" == *"bump: minor"* ]]; then
46
+ echo "value=minor" >> $GITHUB_OUTPUT
47
+ elif [[ "$msg" == *"bump: patch"* ]]; then
48
+ echo "value=patch" >> $GITHUB_OUTPUT
49
+ else
50
+ echo "ERROR: Commit must include 'bump: patch|minor|major'"
51
+ exit 1
52
+ fi
53
+
54
+ - name: Bump version
55
+ run: bump2version ${{ steps.bump_type.outputs.value }}
56
+
57
+ - name: Push new version and tag
58
+ run: |
59
+ git push origin HEAD --tags
60
+
61
+ - name: Get new version tag
62
+ id: new_tag
63
+ run: |
64
+ new_tag=$(git describe --tags `git rev-list --tags --max-count=1`)
65
+ echo "new_tag=$new_tag" >> $GITHUB_ENV
66
+
67
+ - name: Build package
68
+ run: python -m build
69
+
70
+ - name: Publish to PyPI
71
+ uses: pypa/gh-action-pypi-publish@release/v1
72
+
73
+ - name: Upload release assets
74
+ uses: softprops/action-gh-release@v1
75
+ with:
76
+ tag_name: ${{ env.new_tag }}
77
+ name: "Delembic ${{ env.new_tag }}"
78
+ body: |
79
+ Release ${{ env.new_tag }}
80
+
81
+ Changes in this release:
82
+ - Auto-bumped version via GitHub Actions
83
+ - See commit history for details
84
+ files: |
85
+ dist/*.whl
86
+ dist/*.tar.gz
87
+ env:
88
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -0,0 +1,32 @@
1
+ # Python
2
+ .venv/
3
+ __pycache__/
4
+ *.pyc
5
+ *.pyo
6
+ *.pyd
7
+ *.egg-info/
8
+ *.egg
9
+ .eggs/
10
+
11
+ # Build
12
+ dist/
13
+ build/
14
+
15
+ # Test / coverage
16
+ .pytest_cache/
17
+ .coverage
18
+ htmlcov/
19
+ *.db
20
+
21
+ # Type checkers / linters
22
+ .mypy_cache/
23
+ .ruff_cache/
24
+
25
+ # Env
26
+ .env
27
+ .env.*
28
+
29
+ # IDE
30
+ .vscode/
31
+ .idea/
32
+ *.swp
@@ -0,0 +1,17 @@
1
+ version: 2
2
+
3
+ build:
4
+ os: ubuntu-22.04
5
+ tools:
6
+ python: "3.11"
7
+
8
+ sphinx:
9
+ configuration: docs/conf.py
10
+
11
+ python:
12
+ install:
13
+ - requirements: docs/requirements.txt
14
+ - method: pip
15
+ path: .
16
+ extra_requirements:
17
+ - dev
@@ -0,0 +1,155 @@
1
+ Metadata-Version: 2.4
2
+ Name: delembic
3
+ Version: 0.2.0
4
+ Summary: Data migration framework for versioning ETL and data operations alongside Alembic
5
+ Author-email: htshpradhan5@gmail.com
6
+ License: MIT
7
+ Requires-Python: >=3.11
8
+ Requires-Dist: click>=8.0
9
+ Requires-Dist: sqlalchemy>=2.0
10
+ Provides-Extra: dev
11
+ Requires-Dist: pytest>=8.0; extra == 'dev'
12
+ Provides-Extra: docs
13
+ Requires-Dist: furo>=2024.0; extra == 'docs'
14
+ Requires-Dist: myst-parser>=3.0; extra == 'docs'
15
+ Requires-Dist: sphinx-copybutton>=0.5; extra == 'docs'
16
+ Requires-Dist: sphinx>=7.0; extra == 'docs'
17
+ Description-Content-Type: text/markdown
18
+
19
+ # Delembic
20
+
21
+ Data migration framework for Python — Alembic for ETL and data operations.
22
+
23
+ Alembic versions schema changes. Delembic versions **data** changes: vocabulary loads, ETL runs, reference data inserts, corrections. Together they describe the complete database state.
24
+
25
+ ## Installation
26
+
27
+ ```bash
28
+ pip install delembic
29
+ ```
30
+
31
+ ## Quick Start
32
+
33
+ ```bash
34
+ # 1. Initialize in your project
35
+ delembic init
36
+
37
+ # 2. Edit delembic.ini — set your database URL
38
+ # sqlalchemy.url = postgresql+psycopg://user:pass@host/dbname
39
+
40
+ # 3. Create a migration
41
+ delembic revision -m "load vocabulary"
42
+
43
+ # 4. Fill in the generated file, then run
44
+ delembic upgrade head
45
+ ```
46
+
47
+ ## Configuration
48
+
49
+ `delembic init` creates:
50
+
51
+ ```
52
+ your-project/
53
+ ├── delembic.ini # config — commit this
54
+ └── delembic/
55
+ ├── env.py # optional connection helpers
56
+ └── versions/ # migration files live here
57
+ ```
58
+
59
+ **`delembic.ini`:**
60
+
61
+ ```ini
62
+ [delembic]
63
+ script_location = delembic
64
+ sqlalchemy.url = postgresql+psycopg://user:pass@localhost/mydb
65
+ alembic_config = alembic.ini
66
+ ```
67
+
68
+ You can name the script folder anything:
69
+
70
+ ```bash
71
+ delembic init data-migrations
72
+ ```
73
+
74
+ ## Writing Migrations
75
+
76
+ ```python
77
+ from delembic import DataMigration
78
+
79
+ class LoadVocabulary(DataMigration):
80
+
81
+ revision = "D001"
82
+ depends_on = []
83
+ description = "Load OMOP vocabulary tables"
84
+
85
+ def upgrade(self, conn):
86
+ conn.execute(...)
87
+
88
+ def validate(self, conn):
89
+ count = conn.execute("SELECT COUNT(*) FROM concept").scalar()
90
+ assert count > 0, "vocabulary load produced no rows"
91
+ ```
92
+
93
+ `conn` is a SQLAlchemy `Connection`. `validate` is optional — migration is marked failed if it raises.
94
+
95
+ ## Dependency Tracking
96
+
97
+ Migrations declare explicit dependencies. Delembic builds a DAG and runs them in topological order.
98
+
99
+ ```python
100
+ class LoadPerson(DataMigration):
101
+ revision = "D002"
102
+ depends_on = ["D001"] # waits for D001
103
+ ```
104
+
105
+ ## Alembic Integration
106
+
107
+ Point `alembic_config` at your `alembic.ini`:
108
+
109
+ ```ini
110
+ [delembic]
111
+ alembic_config = alembic.ini
112
+ ```
113
+
114
+ When you create a migration, Delembic automatically captures the current Alembic head:
115
+
116
+ ```bash
117
+ delembic revision -m "load person"
118
+ # → depends_on = ['3d1e3e6abc12'] (current alembic head)
119
+ ```
120
+
121
+ At upgrade time, Delembic verifies the required Alembic revision has been applied before running:
122
+
123
+ ```
124
+ BLOCKED: Migration D002 requires Alembic revision(s) 3d1e3e6abc12 to be applied first.
125
+ Run 'alembic upgrade head' before retrying.
126
+ ```
127
+
128
+ ## CLI Reference
129
+
130
+ | Command | Description |
131
+ |---|---|
132
+ | `delembic init [DIR]` | Initialize project. DIR defaults to `delembic` |
133
+ | `delembic revision -m "msg"` | Generate new migration file |
134
+ | `delembic upgrade head` | Run all pending migrations |
135
+ | `delembic upgrade D003` | Run migrations up to D003 |
136
+ | `delembic current` | Show last applied revision |
137
+ | `delembic history` | List all migrations with status |
138
+
139
+ ## Metadata Tables
140
+
141
+ Delembic creates two tables:
142
+
143
+ ```sql
144
+ delembic_version -- current status per revision
145
+ delembic_run_history -- full audit log (start/end time, duration, exception, user, host)
146
+ ```
147
+
148
+ Failed migration work is rolled back. The failure record is always committed — audit trail survives transaction failures.
149
+
150
+ ## Development
151
+
152
+ ```bash
153
+ pip install -e ".[dev]"
154
+ pytest
155
+ ```
@@ -0,0 +1,137 @@
1
+ # Delembic
2
+
3
+ Data migration framework for Python — Alembic for ETL and data operations.
4
+
5
+ Alembic versions schema changes. Delembic versions **data** changes: vocabulary loads, ETL runs, reference data inserts, corrections. Together they describe the complete database state.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ pip install delembic
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```bash
16
+ # 1. Initialize in your project
17
+ delembic init
18
+
19
+ # 2. Edit delembic.ini — set your database URL
20
+ # sqlalchemy.url = postgresql+psycopg://user:pass@host/dbname
21
+
22
+ # 3. Create a migration
23
+ delembic revision -m "load vocabulary"
24
+
25
+ # 4. Fill in the generated file, then run
26
+ delembic upgrade head
27
+ ```
28
+
29
+ ## Configuration
30
+
31
+ `delembic init` creates:
32
+
33
+ ```
34
+ your-project/
35
+ ├── delembic.ini # config — commit this
36
+ └── delembic/
37
+ ├── env.py # optional connection helpers
38
+ └── versions/ # migration files live here
39
+ ```
40
+
41
+ **`delembic.ini`:**
42
+
43
+ ```ini
44
+ [delembic]
45
+ script_location = delembic
46
+ sqlalchemy.url = postgresql+psycopg://user:pass@localhost/mydb
47
+ alembic_config = alembic.ini
48
+ ```
49
+
50
+ You can name the script folder anything:
51
+
52
+ ```bash
53
+ delembic init data-migrations
54
+ ```
55
+
56
+ ## Writing Migrations
57
+
58
+ ```python
59
+ from delembic import DataMigration
60
+
61
+ class LoadVocabulary(DataMigration):
62
+
63
+ revision = "D001"
64
+ depends_on = []
65
+ description = "Load OMOP vocabulary tables"
66
+
67
+ def upgrade(self, conn):
68
+ conn.execute(...)
69
+
70
+ def validate(self, conn):
71
+ count = conn.execute("SELECT COUNT(*) FROM concept").scalar()
72
+ assert count > 0, "vocabulary load produced no rows"
73
+ ```
74
+
75
+ `conn` is a SQLAlchemy `Connection`. `validate` is optional — migration is marked failed if it raises.
76
+
77
+ ## Dependency Tracking
78
+
79
+ Migrations declare explicit dependencies. Delembic builds a DAG and runs them in topological order.
80
+
81
+ ```python
82
+ class LoadPerson(DataMigration):
83
+ revision = "D002"
84
+ depends_on = ["D001"] # waits for D001
85
+ ```
86
+
87
+ ## Alembic Integration
88
+
89
+ Point `alembic_config` at your `alembic.ini`:
90
+
91
+ ```ini
92
+ [delembic]
93
+ alembic_config = alembic.ini
94
+ ```
95
+
96
+ When you create a migration, Delembic automatically captures the current Alembic head:
97
+
98
+ ```bash
99
+ delembic revision -m "load person"
100
+ # → depends_on = ['3d1e3e6abc12'] (current alembic head)
101
+ ```
102
+
103
+ At upgrade time, Delembic verifies the required Alembic revision has been applied before running:
104
+
105
+ ```
106
+ BLOCKED: Migration D002 requires Alembic revision(s) 3d1e3e6abc12 to be applied first.
107
+ Run 'alembic upgrade head' before retrying.
108
+ ```
109
+
110
+ ## CLI Reference
111
+
112
+ | Command | Description |
113
+ |---|---|
114
+ | `delembic init [DIR]` | Initialize project. DIR defaults to `delembic` |
115
+ | `delembic revision -m "msg"` | Generate new migration file |
116
+ | `delembic upgrade head` | Run all pending migrations |
117
+ | `delembic upgrade D003` | Run migrations up to D003 |
118
+ | `delembic current` | Show last applied revision |
119
+ | `delembic history` | List all migrations with status |
120
+
121
+ ## Metadata Tables
122
+
123
+ Delembic creates two tables:
124
+
125
+ ```sql
126
+ delembic_version -- current status per revision
127
+ delembic_run_history -- full audit log (start/end time, duration, exception, user, host)
128
+ ```
129
+
130
+ Failed migration work is rolled back. The failure record is always committed — audit trail survives transaction failures.
131
+
132
+ ## Development
133
+
134
+ ```bash
135
+ pip install -e ".[dev]"
136
+ pytest
137
+ ```
@@ -0,0 +1,4 @@
1
+ # Sphinx build info version 1
2
+ # This file records the configuration used when building these files. When it is not found, a full rebuild will be done.
3
+ config: 40661e23bebe7cfbe895449f07b7020b
4
+ tags: 645f666f9bcd5a90fca523b33c5a78b7
@@ -0,0 +1,112 @@
1
+ # Alembic Integration
2
+
3
+ Delembic integrates with Alembic to enforce that schema migrations are applied before data migrations that depend on them.
4
+
5
+ ## Setup
6
+
7
+ Point `alembic_config` at your `alembic.ini`:
8
+
9
+ ```ini
10
+ [delembic]
11
+ script_location = delembic
12
+ sqlalchemy.url = postgresql+psycopg://user:pass@localhost/mydb
13
+ alembic_config = alembic.ini
14
+ ```
15
+
16
+ `alembic_config` is resolved relative to `delembic.ini`.
17
+
18
+ Install alembic if not already present:
19
+
20
+ ```bash
21
+ pip install alembic
22
+ ```
23
+
24
+ ## Auto-Capture on Revision Generation
25
+
26
+ When `alembic_config` is set, `delembic revision` automatically captures the current Alembic head revision(s) into `depends_on`:
27
+
28
+ ```bash
29
+ # Alembic is at head: 3d1e3e6abc12
30
+ delembic revision -m "load person"
31
+ # Alembic heads captured: ['3d1e3e6abc12']
32
+ # Created delembic/versions/D001_load_person.py
33
+ ```
34
+
35
+ Generated file:
36
+
37
+ ```python
38
+ class LoadPerson(DataMigration):
39
+ revision = "D001"
40
+ depends_on = ['3d1e3e6abc12'] # ← captured automatically
41
+ description = "load person"
42
+ ```
43
+
44
+ If the database is unreachable at revision-generation time, Delembic prints a warning and generates the file with `depends_on = []` — you can fill it in manually.
45
+
46
+ ## Runtime Verification
47
+
48
+ At `delembic upgrade head`, before running any migration, Delembic checks that all Alembic revisions in `depends_on` are applied:
49
+
50
+ ```
51
+ Running D001: load person
52
+ BLOCKED: Migration D001 requires Alembic revision(s) ['3d1e3e6abc12'] to be applied first.
53
+ Run 'alembic upgrade head' before retrying.
54
+ ```
55
+
56
+ The blocked migration is not attempted. Delembic exits with code 1.
57
+
58
+ ## Typical Workflow
59
+
60
+ ```bash
61
+ # 1. Run schema migrations first
62
+ alembic upgrade head
63
+
64
+ # 2. Run data migrations
65
+ delembic upgrade head
66
+ ```
67
+
68
+ In CI/CD pipelines:
69
+
70
+ ```yaml
71
+ - run: alembic upgrade head
72
+ - run: delembic upgrade head
73
+ ```
74
+
75
+ ## Multiple Alembic Heads
76
+
77
+ If your Alembic project uses multiple heads (branches), Delembic captures all current heads:
78
+
79
+ ```bash
80
+ # Alembic has two active branches
81
+ delembic revision -m "post-merge data load"
82
+ # Alembic heads captured: ['3d1e3e6abc12', 'a1b2c3d4e5f6']
83
+ ```
84
+
85
+ ```python
86
+ depends_on = ['3d1e3e6abc12', 'a1b2c3d4e5f6']
87
+ ```
88
+
89
+ Both must be applied before the migration runs.
90
+
91
+ ## Without Alembic
92
+
93
+ Alembic integration is entirely optional. If `alembic_config` is not set in `delembic.ini`:
94
+ - `delembic revision` generates files with `depends_on = []`
95
+ - `delembic upgrade` skips Alembic checks
96
+ - No alembic package needed
97
+
98
+ ## How It Works Internally
99
+
100
+ Delembic uses two Alembic APIs:
101
+
102
+ **`get_current_heads(conn)`** — reads `alembic_version` table via `MigrationContext`:
103
+
104
+ ```python
105
+ from alembic.runtime.migration import MigrationContext
106
+ ctx = MigrationContext.configure(conn)
107
+ heads = list(ctx.get_current_heads())
108
+ ```
109
+
110
+ **`get_alembic_applied_revisions(conn, alembic_ini)`** — walks script history from current heads back to base via `ScriptDirectory.iterate_revisions()`. Returns the set of all applied revision IDs (not just heads — ancestors included).
111
+
112
+ This means a migration that depends on `3d1e3e6abc12` will pass verification even if Alembic has since advanced to `a1b2c3d4e5f6`, as long as `3d1e3e6abc12` is an ancestor of the current head.
@@ -0,0 +1,11 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 — Initial Release
4
+
5
+ - `DataMigration` ABC with `upgrade()` and `validate()` hooks
6
+ - DAG-based execution with topological sort (Kahn's algorithm)
7
+ - `delembic init`, `revision`, `upgrade`, `current`, `history` CLI commands
8
+ - `delembic_version` and `delembic_run_history` metadata tables
9
+ - Dual-connection executor: audit records survive transaction rollbacks
10
+ - Alembic integration: auto-capture heads on `revision`, verify deps on `upgrade`
11
+ - `bump2version` + GitHub Actions release workflow