dbevo 0.0.1__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.
dbevo-0.0.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Semenets V. Pavel
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.
dbevo-0.0.1/PKG-INFO ADDED
@@ -0,0 +1,352 @@
1
+ Metadata-Version: 2.4
2
+ Name: dbevo
3
+ Version: 0.0.1
4
+ Summary: Database schema migrations for Python. Inspired by Play Framework Evolutions.
5
+ License: MIT
6
+ License-File: LICENSE
7
+ Author: Semenets V. Pavel
8
+ Author-email: p.semenets@gmail.com
9
+ Requires-Python: >=3.11,<4
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Topic :: Database
20
+ Classifier: Topic :: Software Development :: Build Tools
21
+ Classifier: Typing :: Typed
22
+ Requires-Dist: asyncpg (>=0.31.0,<0.32.0)
23
+ Requires-Dist: click (>=8.3.1,<9.0.0)
24
+ Requires-Dist: jinja2 (>=3.1.6,<4.0.0)
25
+ Requires-Dist: pydantic (>=2.12.5,<3.0.0)
26
+ Requires-Dist: pydantic-settings (>=2.13.1,<3.0.0)
27
+ Requires-Dist: rich (>=14.3.3,<15.0.0)
28
+ Project-URL: Documentation, https://github.com/xDarkmanx/dbevo#readme
29
+ Project-URL: Homepage, https://github.com/xDarkmanx/dbevo
30
+ Project-URL: Repository, https://github.com/xDarkmanx/dbevo
31
+ Description-Content-Type: text/markdown
32
+
33
+ # dbevo
34
+
35
+ **Database schema migrations for Python.**
36
+
37
+ Легковесный фреймворк для управления миграциями базы данных, вдохновленный [Play Framework Evolutions](https://www.playframework.com/documentation/latest/Evolutions).
38
+
39
+ [![Python Version](https://img.shields.io/pypi/pyversions/dbevo.svg)](https://pypi.org/project/dbevo/)
40
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
41
+
42
+ ---
43
+
44
+ ## 📋 Содержание
45
+
46
+ - [Установка](#-установка)
47
+ - [Быстрый старт](#-быстрый-старт)
48
+ - [Конфигурация](#-конфигурация)
49
+ - [CLI Команды](#-cli-команды)
50
+ - [Структура миграций](#-структура-миграций)
51
+ - [Примеры](#-примеры)
52
+ - [Разработка](#-разработка)
53
+ - [Лицензия](#-лицензия)
54
+
55
+ ---
56
+
57
+ ## 🚀 Установка
58
+
59
+ ```bash
60
+ git clone https://github.com/xDarkmanx/dbevo.git
61
+ cd dbevo
62
+ ```
63
+
64
+ ```bash
65
+ poetry install
66
+ ```
67
+
68
+ ---
69
+
70
+ ## ⚡ Быстрый старт
71
+
72
+ ### 1. Настройка окружения
73
+
74
+ Создайте файл `.env` в корне проекта:
75
+
76
+ ```env
77
+ DBEVO_DATABASE_URL=postgresql://user:password@localhost:5432/mydb
78
+ DBEVO_MIGRATIONS_PATH=migrations
79
+ DBEVO_TEMPLATE_PATH=src/dbevo/templates/migration.sql.j2
80
+ ```
81
+
82
+ ### 2. Инициализация схемы отслеживания
83
+
84
+ ```bash
85
+ dbevo init
86
+ ```
87
+
88
+ Создаёт схему `dbevo` с таблицами для отслеживания применённых миграций.
89
+
90
+ ### 3. Создание новой миграции
91
+
92
+ ```bash
93
+ dbevo new add_user_table --schema core
94
+ ```
95
+
96
+ Создаёт файл: `migrations/core/000001__add_user_table.sql`
97
+
98
+ ### 4. Применение миграций
99
+
100
+ ```bash
101
+ dbevo apply
102
+ ```
103
+
104
+ ### 5. Проверка статуса
105
+
106
+ ```bash
107
+ dbevo status
108
+ ```
109
+
110
+ ---
111
+
112
+ ## ⚙️ Конфигурация
113
+
114
+ Конфигурация загружается в следующем порядке (приорет сверху вниз):
115
+
116
+ 1. **Переменные окружения** (префикс `DBEVO_`)
117
+ 2. **Файл `.env`**
118
+ 3. **Значения по умолчанию**
119
+
120
+ ### Доступные переменные
121
+
122
+ | Переменная | Описание | По умолчанию |
123
+ | ---------- | -------- | ------------ |
124
+ | `DBEVO_DATABASE_URL` | PostgreSQL DSN | - |
125
+ | `DBEVO_MIGRATIONS_PATH` | Путь к миграциям | `migrations` |
126
+ | `DBEVO_TEMPLATE_PATH` | Шаблон миграции | `src/dbevo/templates/migration.sql.j2` |
127
+ | `DBEVO_SCHEMA_NAME` | Схема БД | `dbevo` |
128
+ | `DBEVO_GENERATE_OUTPUT` | Выходная директория для генерации моделей | `src/dbevo/models` |
129
+
130
+ ---
131
+
132
+ ## 🛠 CLI Команды
133
+
134
+ ### `dbevo init`
135
+
136
+ Инициализирует схему отслеживания миграций в базе данных.
137
+
138
+ ```bash
139
+ dbevo init [--debug]
140
+ ```
141
+
142
+ ### `dbevo status`
143
+
144
+ Показывает статус всех миграций.
145
+
146
+ ```bash
147
+ dbevo status [--debug]
148
+ ```
149
+
150
+ **Пример вывода:**
151
+
152
+ ```text
153
+ dbevo status
154
+
155
+ Database: postgresql://localhost:5432/mydb
156
+ Migrations path: migrations
157
+
158
+ ┌────────────────────────────────────┬─────────────┬──────────┬────────────────┐
159
+ │ Migration │ Group │ Status │ Applied At │
160
+ ├────────────────────────────────────┼─────────────┼──────────┼────────────────┤
161
+ │ 000001__init_core_schema │ core │ applied │ 2026-03-30 10: │
162
+ │ 000002__init_utils_schema │ utils │ applied │ 2026-03-30 10: │
163
+ │ 000003__create_update_trigger_func │ utils │ pending │ - │
164
+ └────────────────────────────────────┴─────────────┴──────────┴────────────────┘
165
+
166
+ Total: 1 pending, 2 applied
167
+ ```
168
+
169
+ ### `dbevo apply`
170
+
171
+ Применяет все ожидающие миграции.
172
+
173
+ ```bash
174
+ dbevo apply [--debug] [--auto-confirm] [--dry-run]
175
+ ```
176
+
177
+ **Опции:**
178
+
179
+ | Опция | Описание |
180
+ | ----- | -------- |
181
+ | `--debug` | Включить debug вывод |
182
+ | `--auto-confirm` | Пропустить подтверждение |
183
+ | `--dry-run` | Показать SQL без выполнения |
184
+
185
+ ### `dbevo revert`
186
+
187
+ Откатывает миграции до указанной версии.
188
+
189
+ ```bash
190
+ dbevo revert --to 000002 [--debug] [--dry-run] [--auto-confirm] [--force]
191
+ ```
192
+
193
+ **Опции:**
194
+
195
+ | Опция | Описание |
196
+ | ----- | -------- |
197
+ | `--to` | Номер миграции, к которой откатиться |
198
+ | `--dry-run` | Показать SQL без выполнения |
199
+ | `--auto-confirm` | Пропустить подтверждение |
200
+ | `--force` | Принудительно, даже если файл изменён |
201
+
202
+ ### `dbevo new`
203
+
204
+ Создаёт новый файл миграции.
205
+
206
+ ```bash
207
+ dbevo new <description> [--schema <schema_name>]
208
+ ```
209
+
210
+ **Примеры:**
211
+
212
+ ```bash
213
+ dbevo new add_user_table --schema core
214
+ dbevo new add_email_column --schema utils
215
+ ```
216
+
217
+ ### `dbevo generate`
218
+
219
+ Генерирует Pydantic-модели из схемы базы данных.
220
+
221
+ ```bash
222
+ dbevo generate models [--output <path>]
223
+ ```
224
+
225
+ ---
226
+
227
+ ## 📁 Структура миграций
228
+
229
+ Миграции организованы по **группам** (схемам) и имеют **глобальный номер**.
230
+
231
+ ```text
232
+ migrations/
233
+ ├── core/
234
+ │ ├── 000001__init_core_schema.sql
235
+ │ └── 000004__add_user_table.sql
236
+ └── utils/
237
+ ├── 000002__init_utils_schema.sql
238
+ ├── 000003__create_indexes.sql
239
+ └── 000005__create_update_trigger_function.sql
240
+ ```
241
+
242
+ ### Формат имени файла
243
+
244
+ ```text
245
+ <6-digit-number>__<description>.sql
246
+ ```
247
+
248
+ - **Номер**: 6 цифр, глобальная нумерация
249
+ - **Описание**: snake_case, описывает изменения
250
+
251
+ ### Формат миграции
252
+
253
+ ```sql
254
+ ------------------------------------------------------------------------------------------------------------------------
255
+ -- Author: Semenets Pavel <p.semenets@gmail.com>
256
+ -- Project: dbevo
257
+ -- Schema: utils
258
+ -- Create: Date: 2026-03-30
259
+ -- Migration: 000002__init_utils_schema
260
+ ------------------------------------------------------------------------------------------------------------------------
261
+
262
+ -- !Ups
263
+ ------------------------------------------------------------------------------------------------------------------------
264
+ -- Desc: init_utils_schema
265
+ ------------------------------------------------------------------------------------------------------------------------
266
+ CREATE SCHEMA IF NOT EXISTS "utils";
267
+ COMMENT ON SCHEMA "utils" IS 'core schema';
268
+
269
+
270
+ -- !Ups end
271
+
272
+ -- !Downs
273
+ ------------------------------------------------------------------------------------------------------------------------
274
+ -- Desc: Rollback
275
+ ------------------------------------------------------------------------------------------------------------------------
276
+ DROP SCHEMA IF EXISTS "utils";
277
+
278
+
279
+ -- !Downs end
280
+ ```
281
+
282
+ **Секции:**
283
+
284
+ | Секция | Описание |
285
+ | ------ | -------- |
286
+ | `-- !Ups` | SQL для применения миграции |
287
+ | `-- !Downs` | SQL для отката миграции |
288
+
289
+ ### Откат до конкретной версии
290
+
291
+ ```bash
292
+ # Откат всех миграций после 000002
293
+ dbevo revert --to 2
294
+
295
+ # Откат с подтверждением
296
+ dbevo revert --to 000002 --auto-confirm
297
+ ```
298
+
299
+ ### Dry-run для проверки SQL
300
+
301
+ ```bash
302
+ # Проверка перед применением
303
+ dbevo apply --dry-run
304
+
305
+ # Проверка перед откатом
306
+ dbevo revert --to 000002 --dry-run
307
+ ```
308
+
309
+ ---
310
+
311
+ ## 🔧 Разработка
312
+
313
+ ### Зависимости
314
+
315
+ ```bash
316
+ poetry install --with lint,test,security
317
+ ```
318
+
319
+ ### Запуск тестов
320
+
321
+ ```bash
322
+ poetry run pytest
323
+ ```
324
+
325
+ ### Linting
326
+
327
+ ```bash
328
+ poetry run flake8 src/
329
+ poetry run bandit -r src/
330
+ ```
331
+
332
+ ---
333
+
334
+ ## 📄 Лицензия
335
+
336
+ MIT License. См. [`LICENSE`](LICENSE) для деталей.
337
+
338
+ ---
339
+
340
+ ## 🤝 Вклад
341
+
342
+ Приветствуются Pull Requests! Пожалуйста, сначала обсудите изменения в issue.
343
+
344
+ ---
345
+
346
+ ## 📚 См. также
347
+
348
+ - [Play Framework Evolutions](https://www.playframework.com/documentation/latest/Evolutions)
349
+ - [Alembic](https://alembic.sqlalchemy.org/)
350
+ - [Flyway](https://flywaydb.org/)
351
+ - [Liquibase](https://www.liquibase.com/)
352
+
dbevo-0.0.1/README.md ADDED
@@ -0,0 +1,319 @@
1
+ # dbevo
2
+
3
+ **Database schema migrations for Python.**
4
+
5
+ Легковесный фреймворк для управления миграциями базы данных, вдохновленный [Play Framework Evolutions](https://www.playframework.com/documentation/latest/Evolutions).
6
+
7
+ [![Python Version](https://img.shields.io/pypi/pyversions/dbevo.svg)](https://pypi.org/project/dbevo/)
8
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
9
+
10
+ ---
11
+
12
+ ## 📋 Содержание
13
+
14
+ - [Установка](#-установка)
15
+ - [Быстрый старт](#-быстрый-старт)
16
+ - [Конфигурация](#-конфигурация)
17
+ - [CLI Команды](#-cli-команды)
18
+ - [Структура миграций](#-структура-миграций)
19
+ - [Примеры](#-примеры)
20
+ - [Разработка](#-разработка)
21
+ - [Лицензия](#-лицензия)
22
+
23
+ ---
24
+
25
+ ## 🚀 Установка
26
+
27
+ ```bash
28
+ git clone https://github.com/xDarkmanx/dbevo.git
29
+ cd dbevo
30
+ ```
31
+
32
+ ```bash
33
+ poetry install
34
+ ```
35
+
36
+ ---
37
+
38
+ ## ⚡ Быстрый старт
39
+
40
+ ### 1. Настройка окружения
41
+
42
+ Создайте файл `.env` в корне проекта:
43
+
44
+ ```env
45
+ DBEVO_DATABASE_URL=postgresql://user:password@localhost:5432/mydb
46
+ DBEVO_MIGRATIONS_PATH=migrations
47
+ DBEVO_TEMPLATE_PATH=src/dbevo/templates/migration.sql.j2
48
+ ```
49
+
50
+ ### 2. Инициализация схемы отслеживания
51
+
52
+ ```bash
53
+ dbevo init
54
+ ```
55
+
56
+ Создаёт схему `dbevo` с таблицами для отслеживания применённых миграций.
57
+
58
+ ### 3. Создание новой миграции
59
+
60
+ ```bash
61
+ dbevo new add_user_table --schema core
62
+ ```
63
+
64
+ Создаёт файл: `migrations/core/000001__add_user_table.sql`
65
+
66
+ ### 4. Применение миграций
67
+
68
+ ```bash
69
+ dbevo apply
70
+ ```
71
+
72
+ ### 5. Проверка статуса
73
+
74
+ ```bash
75
+ dbevo status
76
+ ```
77
+
78
+ ---
79
+
80
+ ## ⚙️ Конфигурация
81
+
82
+ Конфигурация загружается в следующем порядке (приорет сверху вниз):
83
+
84
+ 1. **Переменные окружения** (префикс `DBEVO_`)
85
+ 2. **Файл `.env`**
86
+ 3. **Значения по умолчанию**
87
+
88
+ ### Доступные переменные
89
+
90
+ | Переменная | Описание | По умолчанию |
91
+ | ---------- | -------- | ------------ |
92
+ | `DBEVO_DATABASE_URL` | PostgreSQL DSN | - |
93
+ | `DBEVO_MIGRATIONS_PATH` | Путь к миграциям | `migrations` |
94
+ | `DBEVO_TEMPLATE_PATH` | Шаблон миграции | `src/dbevo/templates/migration.sql.j2` |
95
+ | `DBEVO_SCHEMA_NAME` | Схема БД | `dbevo` |
96
+ | `DBEVO_GENERATE_OUTPUT` | Выходная директория для генерации моделей | `src/dbevo/models` |
97
+
98
+ ---
99
+
100
+ ## 🛠 CLI Команды
101
+
102
+ ### `dbevo init`
103
+
104
+ Инициализирует схему отслеживания миграций в базе данных.
105
+
106
+ ```bash
107
+ dbevo init [--debug]
108
+ ```
109
+
110
+ ### `dbevo status`
111
+
112
+ Показывает статус всех миграций.
113
+
114
+ ```bash
115
+ dbevo status [--debug]
116
+ ```
117
+
118
+ **Пример вывода:**
119
+
120
+ ```text
121
+ dbevo status
122
+
123
+ Database: postgresql://localhost:5432/mydb
124
+ Migrations path: migrations
125
+
126
+ ┌────────────────────────────────────┬─────────────┬──────────┬────────────────┐
127
+ │ Migration │ Group │ Status │ Applied At │
128
+ ├────────────────────────────────────┼─────────────┼──────────┼────────────────┤
129
+ │ 000001__init_core_schema │ core │ applied │ 2026-03-30 10: │
130
+ │ 000002__init_utils_schema │ utils │ applied │ 2026-03-30 10: │
131
+ │ 000003__create_update_trigger_func │ utils │ pending │ - │
132
+ └────────────────────────────────────┴─────────────┴──────────┴────────────────┘
133
+
134
+ Total: 1 pending, 2 applied
135
+ ```
136
+
137
+ ### `dbevo apply`
138
+
139
+ Применяет все ожидающие миграции.
140
+
141
+ ```bash
142
+ dbevo apply [--debug] [--auto-confirm] [--dry-run]
143
+ ```
144
+
145
+ **Опции:**
146
+
147
+ | Опция | Описание |
148
+ | ----- | -------- |
149
+ | `--debug` | Включить debug вывод |
150
+ | `--auto-confirm` | Пропустить подтверждение |
151
+ | `--dry-run` | Показать SQL без выполнения |
152
+
153
+ ### `dbevo revert`
154
+
155
+ Откатывает миграции до указанной версии.
156
+
157
+ ```bash
158
+ dbevo revert --to 000002 [--debug] [--dry-run] [--auto-confirm] [--force]
159
+ ```
160
+
161
+ **Опции:**
162
+
163
+ | Опция | Описание |
164
+ | ----- | -------- |
165
+ | `--to` | Номер миграции, к которой откатиться |
166
+ | `--dry-run` | Показать SQL без выполнения |
167
+ | `--auto-confirm` | Пропустить подтверждение |
168
+ | `--force` | Принудительно, даже если файл изменён |
169
+
170
+ ### `dbevo new`
171
+
172
+ Создаёт новый файл миграции.
173
+
174
+ ```bash
175
+ dbevo new <description> [--schema <schema_name>]
176
+ ```
177
+
178
+ **Примеры:**
179
+
180
+ ```bash
181
+ dbevo new add_user_table --schema core
182
+ dbevo new add_email_column --schema utils
183
+ ```
184
+
185
+ ### `dbevo generate`
186
+
187
+ Генерирует Pydantic-модели из схемы базы данных.
188
+
189
+ ```bash
190
+ dbevo generate models [--output <path>]
191
+ ```
192
+
193
+ ---
194
+
195
+ ## 📁 Структура миграций
196
+
197
+ Миграции организованы по **группам** (схемам) и имеют **глобальный номер**.
198
+
199
+ ```text
200
+ migrations/
201
+ ├── core/
202
+ │ ├── 000001__init_core_schema.sql
203
+ │ └── 000004__add_user_table.sql
204
+ └── utils/
205
+ ├── 000002__init_utils_schema.sql
206
+ ├── 000003__create_indexes.sql
207
+ └── 000005__create_update_trigger_function.sql
208
+ ```
209
+
210
+ ### Формат имени файла
211
+
212
+ ```text
213
+ <6-digit-number>__<description>.sql
214
+ ```
215
+
216
+ - **Номер**: 6 цифр, глобальная нумерация
217
+ - **Описание**: snake_case, описывает изменения
218
+
219
+ ### Формат миграции
220
+
221
+ ```sql
222
+ ------------------------------------------------------------------------------------------------------------------------
223
+ -- Author: Semenets Pavel <p.semenets@gmail.com>
224
+ -- Project: dbevo
225
+ -- Schema: utils
226
+ -- Create: Date: 2026-03-30
227
+ -- Migration: 000002__init_utils_schema
228
+ ------------------------------------------------------------------------------------------------------------------------
229
+
230
+ -- !Ups
231
+ ------------------------------------------------------------------------------------------------------------------------
232
+ -- Desc: init_utils_schema
233
+ ------------------------------------------------------------------------------------------------------------------------
234
+ CREATE SCHEMA IF NOT EXISTS "utils";
235
+ COMMENT ON SCHEMA "utils" IS 'core schema';
236
+
237
+
238
+ -- !Ups end
239
+
240
+ -- !Downs
241
+ ------------------------------------------------------------------------------------------------------------------------
242
+ -- Desc: Rollback
243
+ ------------------------------------------------------------------------------------------------------------------------
244
+ DROP SCHEMA IF EXISTS "utils";
245
+
246
+
247
+ -- !Downs end
248
+ ```
249
+
250
+ **Секции:**
251
+
252
+ | Секция | Описание |
253
+ | ------ | -------- |
254
+ | `-- !Ups` | SQL для применения миграции |
255
+ | `-- !Downs` | SQL для отката миграции |
256
+
257
+ ### Откат до конкретной версии
258
+
259
+ ```bash
260
+ # Откат всех миграций после 000002
261
+ dbevo revert --to 2
262
+
263
+ # Откат с подтверждением
264
+ dbevo revert --to 000002 --auto-confirm
265
+ ```
266
+
267
+ ### Dry-run для проверки SQL
268
+
269
+ ```bash
270
+ # Проверка перед применением
271
+ dbevo apply --dry-run
272
+
273
+ # Проверка перед откатом
274
+ dbevo revert --to 000002 --dry-run
275
+ ```
276
+
277
+ ---
278
+
279
+ ## 🔧 Разработка
280
+
281
+ ### Зависимости
282
+
283
+ ```bash
284
+ poetry install --with lint,test,security
285
+ ```
286
+
287
+ ### Запуск тестов
288
+
289
+ ```bash
290
+ poetry run pytest
291
+ ```
292
+
293
+ ### Linting
294
+
295
+ ```bash
296
+ poetry run flake8 src/
297
+ poetry run bandit -r src/
298
+ ```
299
+
300
+ ---
301
+
302
+ ## 📄 Лицензия
303
+
304
+ MIT License. См. [`LICENSE`](LICENSE) для деталей.
305
+
306
+ ---
307
+
308
+ ## 🤝 Вклад
309
+
310
+ Приветствуются Pull Requests! Пожалуйста, сначала обсудите изменения в issue.
311
+
312
+ ---
313
+
314
+ ## 📚 См. также
315
+
316
+ - [Play Framework Evolutions](https://www.playframework.com/documentation/latest/Evolutions)
317
+ - [Alembic](https://alembic.sqlalchemy.org/)
318
+ - [Flyway](https://flywaydb.org/)
319
+ - [Liquibase](https://www.liquibase.com/)