half-orm-dev 0.18.0a2__tar.gz → 1.0.0a4__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.
- {half_orm_dev-0.18.0a2/half_orm_dev.egg-info → half_orm_dev-1.0.0a4}/PKG-INFO +59 -31
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/README.md +57 -29
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/cli/commands/__init__.py +2 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/cli/commands/check.py +3 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/cli/commands/migrate.py +40 -2
- half_orm_dev-1.0.0a4/half_orm_dev/cli/commands/revert_migration.py +49 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/cli/main.py +2 -1
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/hgit.py +95 -28
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/migration_manager.py +189 -6
- half_orm_dev-1.0.0a4/half_orm_dev/migrations/hop/BREAKING_CHANGES-1.0.0.md +18 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/modules.py +167 -1
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/patch_manager.py +30 -19
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/release_manager.py +31 -1
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/repo.py +21 -4
- half_orm_dev-1.0.0a4/half_orm_dev/version.txt +1 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4/half_orm_dev.egg-info}/PKG-INFO +59 -31
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev.egg-info/SOURCES.txt +3 -0
- half_orm_dev-1.0.0a4/half_orm_dev.egg-info/entry_points.txt +2 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev.egg-info/requires.txt +1 -1
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/pyproject.toml +5 -1
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/setup.py +16 -4
- half_orm_dev-0.18.0a2/half_orm_dev/version.txt +0 -1
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/AUTHORS +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/LICENSE +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/__init__.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/bootstrap_manager.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/cli/__init__.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/cli/commands/apply.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/cli/commands/bootstrap.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/cli/commands/clone.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/cli/commands/init.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/cli/commands/patch.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/cli/commands/release.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/cli/commands/restore.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/cli/commands/set_git_origin.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/cli/commands/sync.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/cli/commands/todo.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/cli/commands/undo.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/cli/commands/update.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/cli/commands/upgrade.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/cli_extension.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/database.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/decorators.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/file_executor.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/migrations/0/17/1/00_move_to_hop.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/migrations/0/17/1/01_txt_to_toml.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/migrations/0/17/4/00_toml_dict_format.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/migrations/0/17/4/01_add_bootstrap_table.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/migrations/0/17/4/02_move_patches_to_subdirs.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/migrations/0/17/5/01_update_pyproject_dependency.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/migrations/0/18/0/00_add_async_support.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/migrations/0/18/0/01_update_default_tests.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/patch_validator.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/patches/0/1/0/00_half_orm_meta.database.sql +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/patches/0/1/0/01_alter_half_orm_meta.hop_release.sql +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/patches/0/1/0/02_half_orm_meta.view.hop_penultimate_release.sql +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/patches/log +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/patches/sql/half_orm_meta.sql +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/release_file.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/scripts/repair-metadata.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/templates/.gitignore +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/templates/MANIFEST.in +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/templates/README +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/templates/conftest_template +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/templates/git-hooks/pre-commit +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/templates/git-hooks/prepare-commit-msg +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/templates/init_module_template +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/templates/module_template_1 +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/templates/module_template_2 +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/templates/module_template_3 +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/templates/pyproject.toml +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/templates/relation_test +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/templates/sql_adapter +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/templates/warning +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev/utils.py +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev.egg-info/dependency_links.txt +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/half_orm_dev.egg-info/top_level.txt +0 -0
- {half_orm_dev-0.18.0a2 → half_orm_dev-1.0.0a4}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: half_orm_dev
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.0a4
|
|
4
4
|
Summary: half_orm development Framework.
|
|
5
5
|
Author-email: Joël Maïzi <joel.maizi@collorg.org>
|
|
6
6
|
License-Expression: GPL-3.0-or-later
|
|
@@ -23,7 +23,7 @@ Requires-Dist: GitPython
|
|
|
23
23
|
Requires-Dist: click
|
|
24
24
|
Requires-Dist: pydash
|
|
25
25
|
Requires-Dist: pytest
|
|
26
|
-
Requires-Dist: half_orm<
|
|
26
|
+
Requires-Dist: half_orm<1.1.0,>=1.0.0a1
|
|
27
27
|
Requires-Dist: tomli>=2.0.0; python_version < "3.11"
|
|
28
28
|
Requires-Dist: tomli_w>=1.0.0
|
|
29
29
|
Dynamic: license-file
|
|
@@ -46,7 +46,7 @@ Modern development workflow for PostgreSQL databases with automatic code generat
|
|
|
46
46
|
|
|
47
47
|
---
|
|
48
48
|
|
|
49
|
-
##
|
|
49
|
+
## What is half-orm-dev?
|
|
50
50
|
|
|
51
51
|
`half-orm-dev` provides a complete development lifecycle for database-driven applications:
|
|
52
52
|
|
|
@@ -62,9 +62,9 @@ Perfect for teams managing evolving PostgreSQL schemas with Python applications.
|
|
|
62
62
|
|
|
63
63
|
---
|
|
64
64
|
|
|
65
|
-
##
|
|
65
|
+
## Key Features
|
|
66
66
|
|
|
67
|
-
###
|
|
67
|
+
### Systematic Test Validation (Core Safety Feature)
|
|
68
68
|
|
|
69
69
|
**Tests run automatically before patch integration and block merges if they fail.**
|
|
70
70
|
|
|
@@ -90,22 +90,22 @@ half_orm dev patch merge
|
|
|
90
90
|
|
|
91
91
|
**Cannot be disabled** - it's a core safety feature.
|
|
92
92
|
|
|
93
|
-
###
|
|
93
|
+
### Development Workflow
|
|
94
94
|
|
|
95
95
|
- **Patch-based development**: Isolated branches for each database change
|
|
96
96
|
- **Automatic code generation**: half-orm Python classes from schema
|
|
97
97
|
- **Complete testing**: Apply patches with full release context
|
|
98
98
|
- **Conflict detection**: Distributed locks prevent concurrent modifications
|
|
99
99
|
|
|
100
|
-
###
|
|
100
|
+
### Release Management
|
|
101
101
|
|
|
102
102
|
- **Semantic versioning**: patch/minor/major increments
|
|
103
103
|
- **Sequential promotion**: stage → rc → production workflow
|
|
104
104
|
- **Release candidates**: RC validation before production
|
|
105
105
|
- **Hotfix support**: Reopen last released version for urgent fixes
|
|
106
|
-
- **Branch cleanup**:
|
|
106
|
+
- **Branch cleanup**: `ho-staged/ID` branches deleted automatically at `release promote prod`
|
|
107
107
|
|
|
108
|
-
###
|
|
108
|
+
### Production
|
|
109
109
|
|
|
110
110
|
- **Safe upgrades**: Automatic database backups before changes
|
|
111
111
|
- **Incremental deployment**: Apply releases sequentially
|
|
@@ -114,7 +114,7 @@ half_orm dev patch merge
|
|
|
114
114
|
|
|
115
115
|
---
|
|
116
116
|
|
|
117
|
-
##
|
|
117
|
+
## Installation
|
|
118
118
|
|
|
119
119
|
### Prerequisites
|
|
120
120
|
|
|
@@ -136,7 +136,7 @@ half_orm dev --help
|
|
|
136
136
|
|
|
137
137
|
---
|
|
138
138
|
|
|
139
|
-
##
|
|
139
|
+
## Quick Start
|
|
140
140
|
|
|
141
141
|
### Initialize New Project
|
|
142
142
|
|
|
@@ -201,6 +201,7 @@ half_orm dev patch merge
|
|
|
201
201
|
# → Creates temp validation branch
|
|
202
202
|
# → Runs pytest automatically
|
|
203
203
|
# → If tests pass: merges into ho-release/0.1.0, status → "staged"
|
|
204
|
+
# branch renamed: ho-patch/1-users → ho-staged/1-users
|
|
204
205
|
# → If tests fail: aborts, nothing committed
|
|
205
206
|
|
|
206
207
|
# 9. Promote to production
|
|
@@ -210,7 +211,7 @@ half_orm dev release promote prod # Merge to ho-prod + create tag
|
|
|
210
211
|
|
|
211
212
|
---
|
|
212
213
|
|
|
213
|
-
##
|
|
214
|
+
## Core Workflow
|
|
214
215
|
|
|
215
216
|
### Branch Strategy
|
|
216
217
|
|
|
@@ -218,18 +219,19 @@ half_orm dev release promote prod # Merge to ho-prod + create tag
|
|
|
218
219
|
ho-prod (main production branch)
|
|
219
220
|
│
|
|
220
221
|
├── ho-release/0.17.0 (integration branch, deleted after prod)
|
|
221
|
-
│ ├── ho-patch/6-feature-x (
|
|
222
|
-
│ ├── ho-patch/7-bugfix-y (
|
|
223
|
-
│ └── ho-patch/8-auth-z (
|
|
222
|
+
│ ├── ho-patch/6-feature-x → ho-staged/6-feature-x (after merge)
|
|
223
|
+
│ ├── ho-patch/7-bugfix-y → ho-staged/7-bugfix-y (after merge)
|
|
224
|
+
│ └── ho-patch/8-auth-z → ho-staged/8-auth-z (after merge)
|
|
224
225
|
│
|
|
225
226
|
└── ho-release/0.18.0 (next version in parallel)
|
|
226
|
-
└── ho-patch/10-new-api (
|
|
227
|
+
└── ho-patch/10-new-api (in development)
|
|
227
228
|
```
|
|
228
229
|
|
|
229
230
|
**Branch Types:**
|
|
230
231
|
- **ho-prod**: Stable production branch (source of truth)
|
|
231
|
-
- **ho-release/X.Y.Z**: Integration branches (temporary)
|
|
232
|
-
- **ho-patch/ID**: Patch development branches (
|
|
232
|
+
- **ho-release/X.Y.Z**: Integration branches (temporary, deleted after prod)
|
|
233
|
+
- **ho-patch/ID**: Patch development branches (renamed to `ho-staged/ID` after merge)
|
|
234
|
+
- **ho-staged/ID**: Staged patch branches (preserved for debugging, deleted at `release promote prod`)
|
|
233
235
|
|
|
234
236
|
### Release Files
|
|
235
237
|
|
|
@@ -258,6 +260,8 @@ ho-prod (main production branch)
|
|
|
258
260
|
│ 3. patch apply Apply & test changes │
|
|
259
261
|
│ 4. patch merge Merge into release (TESTS!) │
|
|
260
262
|
│ ✅ Tests pass → integrated │
|
|
263
|
+
│ branch: ho-patch/X → │
|
|
264
|
+
│ ho-staged/X │
|
|
261
265
|
│ ❌ Tests fail → aborted │
|
|
262
266
|
│ │
|
|
263
267
|
│ RELEASE PROMOTION │
|
|
@@ -277,7 +281,7 @@ ho-prod (main production branch)
|
|
|
277
281
|
|
|
278
282
|
---
|
|
279
283
|
|
|
280
|
-
##
|
|
284
|
+
## Command Reference
|
|
281
285
|
|
|
282
286
|
### Init & Clone
|
|
283
287
|
|
|
@@ -301,6 +305,33 @@ half_orm dev check --dry-run
|
|
|
301
305
|
|
|
302
306
|
**Note:** This command runs automatically before other commands (git hooks, configuration, stale branches cleanup).
|
|
303
307
|
|
|
308
|
+
When a newer version of `half-orm-dev` is available, the output includes a link to the PyPI release page where you can review breaking changes before upgrading.
|
|
309
|
+
|
|
310
|
+
### Migrate
|
|
311
|
+
|
|
312
|
+
When `half-orm-dev` is updated, run `migrate` once to apply any repository migrations:
|
|
313
|
+
|
|
314
|
+
```bash
|
|
315
|
+
half_orm dev migrate
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
If the new version introduces **breaking changes**, they are displayed before the confirmation prompt and you must type `yes` (not just `y`) to proceed:
|
|
319
|
+
|
|
320
|
+
```
|
|
321
|
+
╔══════════════════════════════════════════════════╗
|
|
322
|
+
║ BREAKING CHANGES ║
|
|
323
|
+
╚══════════════════════════════════════════════════╝
|
|
324
|
+
|
|
325
|
+
--- half-orm-dev 1.0.0 ---
|
|
326
|
+
# hop 1.0.0 — Breaking Changes
|
|
327
|
+
...
|
|
328
|
+
|
|
329
|
+
Type "yes" to confirm you have read the breaking changes and want to proceed.
|
|
330
|
+
Proceed? [no]:
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
For non-breaking upgrades a standard `y/n` prompt is shown instead.
|
|
334
|
+
|
|
304
335
|
### Release Commands
|
|
305
336
|
|
|
306
337
|
A release must be created before creating patches.
|
|
@@ -381,7 +412,7 @@ These files are automatically:
|
|
|
381
412
|
|
|
382
413
|
---
|
|
383
414
|
|
|
384
|
-
##
|
|
415
|
+
## Example: Team Collaboration
|
|
385
416
|
|
|
386
417
|
```bash
|
|
387
418
|
# Integration Manager: Create release
|
|
@@ -394,6 +425,7 @@ half_orm dev patch create 456-dashboard
|
|
|
394
425
|
git checkout ho-patch/456-dashboard
|
|
395
426
|
half_orm dev patch merge # Tests run automatically
|
|
396
427
|
# → Status: "staged" in 0.17.0-patches.toml
|
|
428
|
+
# → Branch renamed: ho-patch/456-dashboard → ho-staged/456-dashboard
|
|
397
429
|
|
|
398
430
|
# Developer B: Sync and create patch
|
|
399
431
|
git checkout ho-release/0.17.0
|
|
@@ -409,7 +441,7 @@ half_orm dev patch merge
|
|
|
409
441
|
|
|
410
442
|
---
|
|
411
443
|
|
|
412
|
-
##
|
|
444
|
+
## Development Philosophy
|
|
413
445
|
|
|
414
446
|
half-orm-dev combines **Domain-Driven Design** with **Test-Driven Development**, integrated into Git:
|
|
415
447
|
|
|
@@ -423,7 +455,7 @@ This approach ensures that every schema change is tested in the full release con
|
|
|
423
455
|
|
|
424
456
|
---
|
|
425
457
|
|
|
426
|
-
##
|
|
458
|
+
## Documentation
|
|
427
459
|
|
|
428
460
|
- **[CONTRIBUTING.md](CONTRIBUTING.md)** - Development setup, testing, contribution guidelines
|
|
429
461
|
- **[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)** - Technical architecture and implementation details
|
|
@@ -433,7 +465,7 @@ For detailed technical documentation, see [docs/ARCHITECTURE.md](docs/ARCHITECTU
|
|
|
433
465
|
|
|
434
466
|
---
|
|
435
467
|
|
|
436
|
-
##
|
|
468
|
+
## Troubleshooting
|
|
437
469
|
|
|
438
470
|
### Error: "Must be on ho-release/* branch"
|
|
439
471
|
```bash
|
|
@@ -519,7 +551,7 @@ For more troubleshooting, see [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
|
|
|
519
551
|
|
|
520
552
|
---
|
|
521
553
|
|
|
522
|
-
##
|
|
554
|
+
## Contributing
|
|
523
555
|
|
|
524
556
|
Contributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and guidelines.
|
|
525
557
|
|
|
@@ -545,7 +577,7 @@ pytest -m integration # Integration tests only
|
|
|
545
577
|
|
|
546
578
|
---
|
|
547
579
|
|
|
548
|
-
##
|
|
580
|
+
## Getting Help
|
|
549
581
|
|
|
550
582
|
- **Issues**: [GitHub Issues](https://github.com/half-orm/half-orm-dev/issues)
|
|
551
583
|
- **Documentation**: [CONTRIBUTING.md](CONTRIBUTING.md) and [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)
|
|
@@ -553,10 +585,6 @@ pytest -m integration # Integration tests only
|
|
|
553
585
|
|
|
554
586
|
---
|
|
555
587
|
|
|
556
|
-
##
|
|
557
|
-
|
|
558
|
-
This project is licensed under the GNU General Public License v3.0 - see the [LICENSE](LICENSE) file for details.
|
|
559
|
-
|
|
560
|
-
---
|
|
588
|
+
## License
|
|
561
589
|
|
|
562
|
-
|
|
590
|
+
This project is licensed under the [GPL-3.0](LICENSE) license.
|
|
@@ -15,7 +15,7 @@ Modern development workflow for PostgreSQL databases with automatic code generat
|
|
|
15
15
|
|
|
16
16
|
---
|
|
17
17
|
|
|
18
|
-
##
|
|
18
|
+
## What is half-orm-dev?
|
|
19
19
|
|
|
20
20
|
`half-orm-dev` provides a complete development lifecycle for database-driven applications:
|
|
21
21
|
|
|
@@ -31,9 +31,9 @@ Perfect for teams managing evolving PostgreSQL schemas with Python applications.
|
|
|
31
31
|
|
|
32
32
|
---
|
|
33
33
|
|
|
34
|
-
##
|
|
34
|
+
## Key Features
|
|
35
35
|
|
|
36
|
-
###
|
|
36
|
+
### Systematic Test Validation (Core Safety Feature)
|
|
37
37
|
|
|
38
38
|
**Tests run automatically before patch integration and block merges if they fail.**
|
|
39
39
|
|
|
@@ -59,22 +59,22 @@ half_orm dev patch merge
|
|
|
59
59
|
|
|
60
60
|
**Cannot be disabled** - it's a core safety feature.
|
|
61
61
|
|
|
62
|
-
###
|
|
62
|
+
### Development Workflow
|
|
63
63
|
|
|
64
64
|
- **Patch-based development**: Isolated branches for each database change
|
|
65
65
|
- **Automatic code generation**: half-orm Python classes from schema
|
|
66
66
|
- **Complete testing**: Apply patches with full release context
|
|
67
67
|
- **Conflict detection**: Distributed locks prevent concurrent modifications
|
|
68
68
|
|
|
69
|
-
###
|
|
69
|
+
### Release Management
|
|
70
70
|
|
|
71
71
|
- **Semantic versioning**: patch/minor/major increments
|
|
72
72
|
- **Sequential promotion**: stage → rc → production workflow
|
|
73
73
|
- **Release candidates**: RC validation before production
|
|
74
74
|
- **Hotfix support**: Reopen last released version for urgent fixes
|
|
75
|
-
- **Branch cleanup**:
|
|
75
|
+
- **Branch cleanup**: `ho-staged/ID` branches deleted automatically at `release promote prod`
|
|
76
76
|
|
|
77
|
-
###
|
|
77
|
+
### Production
|
|
78
78
|
|
|
79
79
|
- **Safe upgrades**: Automatic database backups before changes
|
|
80
80
|
- **Incremental deployment**: Apply releases sequentially
|
|
@@ -83,7 +83,7 @@ half_orm dev patch merge
|
|
|
83
83
|
|
|
84
84
|
---
|
|
85
85
|
|
|
86
|
-
##
|
|
86
|
+
## Installation
|
|
87
87
|
|
|
88
88
|
### Prerequisites
|
|
89
89
|
|
|
@@ -105,7 +105,7 @@ half_orm dev --help
|
|
|
105
105
|
|
|
106
106
|
---
|
|
107
107
|
|
|
108
|
-
##
|
|
108
|
+
## Quick Start
|
|
109
109
|
|
|
110
110
|
### Initialize New Project
|
|
111
111
|
|
|
@@ -170,6 +170,7 @@ half_orm dev patch merge
|
|
|
170
170
|
# → Creates temp validation branch
|
|
171
171
|
# → Runs pytest automatically
|
|
172
172
|
# → If tests pass: merges into ho-release/0.1.0, status → "staged"
|
|
173
|
+
# branch renamed: ho-patch/1-users → ho-staged/1-users
|
|
173
174
|
# → If tests fail: aborts, nothing committed
|
|
174
175
|
|
|
175
176
|
# 9. Promote to production
|
|
@@ -179,7 +180,7 @@ half_orm dev release promote prod # Merge to ho-prod + create tag
|
|
|
179
180
|
|
|
180
181
|
---
|
|
181
182
|
|
|
182
|
-
##
|
|
183
|
+
## Core Workflow
|
|
183
184
|
|
|
184
185
|
### Branch Strategy
|
|
185
186
|
|
|
@@ -187,18 +188,19 @@ half_orm dev release promote prod # Merge to ho-prod + create tag
|
|
|
187
188
|
ho-prod (main production branch)
|
|
188
189
|
│
|
|
189
190
|
├── ho-release/0.17.0 (integration branch, deleted after prod)
|
|
190
|
-
│ ├── ho-patch/6-feature-x (
|
|
191
|
-
│ ├── ho-patch/7-bugfix-y (
|
|
192
|
-
│ └── ho-patch/8-auth-z (
|
|
191
|
+
│ ├── ho-patch/6-feature-x → ho-staged/6-feature-x (after merge)
|
|
192
|
+
│ ├── ho-patch/7-bugfix-y → ho-staged/7-bugfix-y (after merge)
|
|
193
|
+
│ └── ho-patch/8-auth-z → ho-staged/8-auth-z (after merge)
|
|
193
194
|
│
|
|
194
195
|
└── ho-release/0.18.0 (next version in parallel)
|
|
195
|
-
└── ho-patch/10-new-api (
|
|
196
|
+
└── ho-patch/10-new-api (in development)
|
|
196
197
|
```
|
|
197
198
|
|
|
198
199
|
**Branch Types:**
|
|
199
200
|
- **ho-prod**: Stable production branch (source of truth)
|
|
200
|
-
- **ho-release/X.Y.Z**: Integration branches (temporary)
|
|
201
|
-
- **ho-patch/ID**: Patch development branches (
|
|
201
|
+
- **ho-release/X.Y.Z**: Integration branches (temporary, deleted after prod)
|
|
202
|
+
- **ho-patch/ID**: Patch development branches (renamed to `ho-staged/ID` after merge)
|
|
203
|
+
- **ho-staged/ID**: Staged patch branches (preserved for debugging, deleted at `release promote prod`)
|
|
202
204
|
|
|
203
205
|
### Release Files
|
|
204
206
|
|
|
@@ -227,6 +229,8 @@ ho-prod (main production branch)
|
|
|
227
229
|
│ 3. patch apply Apply & test changes │
|
|
228
230
|
│ 4. patch merge Merge into release (TESTS!) │
|
|
229
231
|
│ ✅ Tests pass → integrated │
|
|
232
|
+
│ branch: ho-patch/X → │
|
|
233
|
+
│ ho-staged/X │
|
|
230
234
|
│ ❌ Tests fail → aborted │
|
|
231
235
|
│ │
|
|
232
236
|
│ RELEASE PROMOTION │
|
|
@@ -246,7 +250,7 @@ ho-prod (main production branch)
|
|
|
246
250
|
|
|
247
251
|
---
|
|
248
252
|
|
|
249
|
-
##
|
|
253
|
+
## Command Reference
|
|
250
254
|
|
|
251
255
|
### Init & Clone
|
|
252
256
|
|
|
@@ -270,6 +274,33 @@ half_orm dev check --dry-run
|
|
|
270
274
|
|
|
271
275
|
**Note:** This command runs automatically before other commands (git hooks, configuration, stale branches cleanup).
|
|
272
276
|
|
|
277
|
+
When a newer version of `half-orm-dev` is available, the output includes a link to the PyPI release page where you can review breaking changes before upgrading.
|
|
278
|
+
|
|
279
|
+
### Migrate
|
|
280
|
+
|
|
281
|
+
When `half-orm-dev` is updated, run `migrate` once to apply any repository migrations:
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
half_orm dev migrate
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
If the new version introduces **breaking changes**, they are displayed before the confirmation prompt and you must type `yes` (not just `y`) to proceed:
|
|
288
|
+
|
|
289
|
+
```
|
|
290
|
+
╔══════════════════════════════════════════════════╗
|
|
291
|
+
║ BREAKING CHANGES ║
|
|
292
|
+
╚══════════════════════════════════════════════════╝
|
|
293
|
+
|
|
294
|
+
--- half-orm-dev 1.0.0 ---
|
|
295
|
+
# hop 1.0.0 — Breaking Changes
|
|
296
|
+
...
|
|
297
|
+
|
|
298
|
+
Type "yes" to confirm you have read the breaking changes and want to proceed.
|
|
299
|
+
Proceed? [no]:
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
For non-breaking upgrades a standard `y/n` prompt is shown instead.
|
|
303
|
+
|
|
273
304
|
### Release Commands
|
|
274
305
|
|
|
275
306
|
A release must be created before creating patches.
|
|
@@ -350,7 +381,7 @@ These files are automatically:
|
|
|
350
381
|
|
|
351
382
|
---
|
|
352
383
|
|
|
353
|
-
##
|
|
384
|
+
## Example: Team Collaboration
|
|
354
385
|
|
|
355
386
|
```bash
|
|
356
387
|
# Integration Manager: Create release
|
|
@@ -363,6 +394,7 @@ half_orm dev patch create 456-dashboard
|
|
|
363
394
|
git checkout ho-patch/456-dashboard
|
|
364
395
|
half_orm dev patch merge # Tests run automatically
|
|
365
396
|
# → Status: "staged" in 0.17.0-patches.toml
|
|
397
|
+
# → Branch renamed: ho-patch/456-dashboard → ho-staged/456-dashboard
|
|
366
398
|
|
|
367
399
|
# Developer B: Sync and create patch
|
|
368
400
|
git checkout ho-release/0.17.0
|
|
@@ -378,7 +410,7 @@ half_orm dev patch merge
|
|
|
378
410
|
|
|
379
411
|
---
|
|
380
412
|
|
|
381
|
-
##
|
|
413
|
+
## Development Philosophy
|
|
382
414
|
|
|
383
415
|
half-orm-dev combines **Domain-Driven Design** with **Test-Driven Development**, integrated into Git:
|
|
384
416
|
|
|
@@ -392,7 +424,7 @@ This approach ensures that every schema change is tested in the full release con
|
|
|
392
424
|
|
|
393
425
|
---
|
|
394
426
|
|
|
395
|
-
##
|
|
427
|
+
## Documentation
|
|
396
428
|
|
|
397
429
|
- **[CONTRIBUTING.md](CONTRIBUTING.md)** - Development setup, testing, contribution guidelines
|
|
398
430
|
- **[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)** - Technical architecture and implementation details
|
|
@@ -402,7 +434,7 @@ For detailed technical documentation, see [docs/ARCHITECTURE.md](docs/ARCHITECTU
|
|
|
402
434
|
|
|
403
435
|
---
|
|
404
436
|
|
|
405
|
-
##
|
|
437
|
+
## Troubleshooting
|
|
406
438
|
|
|
407
439
|
### Error: "Must be on ho-release/* branch"
|
|
408
440
|
```bash
|
|
@@ -488,7 +520,7 @@ For more troubleshooting, see [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
|
|
|
488
520
|
|
|
489
521
|
---
|
|
490
522
|
|
|
491
|
-
##
|
|
523
|
+
## Contributing
|
|
492
524
|
|
|
493
525
|
Contributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and guidelines.
|
|
494
526
|
|
|
@@ -514,7 +546,7 @@ pytest -m integration # Integration tests only
|
|
|
514
546
|
|
|
515
547
|
---
|
|
516
548
|
|
|
517
|
-
##
|
|
549
|
+
## Getting Help
|
|
518
550
|
|
|
519
551
|
- **Issues**: [GitHub Issues](https://github.com/half-orm/half-orm-dev/issues)
|
|
520
552
|
- **Documentation**: [CONTRIBUTING.md](CONTRIBUTING.md) and [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)
|
|
@@ -522,10 +554,6 @@ pytest -m integration # Integration tests only
|
|
|
522
554
|
|
|
523
555
|
---
|
|
524
556
|
|
|
525
|
-
##
|
|
526
|
-
|
|
527
|
-
This project is licensed under the GNU General Public License v3.0 - see the [LICENSE](LICENSE) file for details.
|
|
528
|
-
|
|
529
|
-
---
|
|
557
|
+
## License
|
|
530
558
|
|
|
531
|
-
|
|
559
|
+
This project is licensed under the [GPL-3.0](LICENSE) license.
|
|
@@ -15,6 +15,7 @@ from .upgrade import upgrade
|
|
|
15
15
|
from .check import check
|
|
16
16
|
from .set_git_origin import set_git_origin
|
|
17
17
|
from .migrate import migrate
|
|
18
|
+
from .revert_migration import revert_migration
|
|
18
19
|
from .bootstrap import bootstrap
|
|
19
20
|
from .todo import apply_release
|
|
20
21
|
from .todo import rollback
|
|
@@ -35,6 +36,7 @@ ALL_COMMANDS = {
|
|
|
35
36
|
'check': check, # Project health check and updates
|
|
36
37
|
'set-git-origin': set_git_origin, # Update git remote origin URL
|
|
37
38
|
'migrate': migrate, # Repository migration after upgrade
|
|
39
|
+
'revert-migration': revert_migration, # Revert last migration
|
|
38
40
|
'bootstrap': bootstrap, # Execute data initialization scripts
|
|
39
41
|
# 🚧 (stubs)
|
|
40
42
|
'apply_release': apply_release,
|
|
@@ -86,6 +86,9 @@ def _display_check_results(repo, result: dict, dry_run: bool, verbose: bool):
|
|
|
86
86
|
click.echo(f"Latest version: {utils.Color.green(utils.Color.bold(latest))}")
|
|
87
87
|
click.echo()
|
|
88
88
|
click.echo(f"To update, run: {utils.Color.bold('pip install --upgrade half_orm_dev')}")
|
|
89
|
+
click.echo()
|
|
90
|
+
click.echo(f"Before upgrading, check for breaking changes:")
|
|
91
|
+
click.echo(f" https://pypi.org/project/half-orm-dev/{latest}/")
|
|
89
92
|
click.echo(f"{'='*70}")
|
|
90
93
|
click.echo()
|
|
91
94
|
|
|
@@ -7,6 +7,7 @@ is newer than the repository's hop_version in .hop/config.
|
|
|
7
7
|
|
|
8
8
|
import click
|
|
9
9
|
from half_orm_dev.repo import Repo, RepoError
|
|
10
|
+
from half_orm_dev.migration_manager import MigrationManager
|
|
10
11
|
from half_orm import utils
|
|
11
12
|
|
|
12
13
|
|
|
@@ -75,15 +76,52 @@ def migrate(verbose: bool) -> None:
|
|
|
75
76
|
click.echo(f" Current branch: {current_branch}")
|
|
76
77
|
click.echo()
|
|
77
78
|
|
|
79
|
+
# Check for breaking changes between current and target version
|
|
80
|
+
mgr = MigrationManager(repo)
|
|
81
|
+
breaking_changes = mgr.get_breaking_changes(config_version, installed_version)
|
|
82
|
+
|
|
83
|
+
needs_explicit_confirm = False
|
|
84
|
+
if breaking_changes:
|
|
85
|
+
import importlib.metadata
|
|
86
|
+
try:
|
|
87
|
+
half_orm_installed = importlib.metadata.version('half-orm')
|
|
88
|
+
except importlib.metadata.PackageNotFoundError:
|
|
89
|
+
half_orm_installed = None
|
|
90
|
+
|
|
91
|
+
width = 70
|
|
92
|
+
lines = []
|
|
93
|
+
lines.append('━' * width)
|
|
94
|
+
lines.append(f" ⚠️ BREAKING CHANGES")
|
|
95
|
+
lines.append('━' * width)
|
|
96
|
+
for bc in breaking_changes:
|
|
97
|
+
if bc['component'] == 'hop':
|
|
98
|
+
label = 'half-orm-dev'
|
|
99
|
+
display_version = installed_version
|
|
100
|
+
else:
|
|
101
|
+
label = 'half-orm'
|
|
102
|
+
display_version = half_orm_installed or bc['version']
|
|
103
|
+
lines.append(f"\n ━━━ {label} {display_version} {'━' * max(0, width - len(label) - len(display_version) - 7)}")
|
|
104
|
+
for line in bc['content'].splitlines():
|
|
105
|
+
lines.append(f" {line}")
|
|
106
|
+
lines.append(f"\n{'━' * width}")
|
|
107
|
+
click.echo_via_pager('\n'.join(lines) + '\n')
|
|
108
|
+
needs_explicit_confirm = True
|
|
78
109
|
|
|
79
110
|
# Run migrations
|
|
80
|
-
if
|
|
111
|
+
if needs_explicit_confirm:
|
|
112
|
+
click.echo("Type \"yes\" to confirm you have read the breaking changes and want to proceed.")
|
|
113
|
+
answer = click.prompt("Proceed?", default="no")
|
|
114
|
+
confirmed = answer.strip().lower() == "yes"
|
|
115
|
+
else:
|
|
116
|
+
confirmed = click.confirm("Do you want to proceed?", default=False)
|
|
117
|
+
|
|
118
|
+
if not confirmed:
|
|
81
119
|
click.echo()
|
|
82
120
|
click.echo("If you want to revert half_orm_dev run:")
|
|
83
121
|
click.echo(f" pip install half-orm-dev=={config_version}")
|
|
84
122
|
else:
|
|
85
123
|
try:
|
|
86
|
-
click.echo(
|
|
124
|
+
click.echo(" Running migrations...")
|
|
87
125
|
result = repo.run_migrations_if_needed(silent=False)
|
|
88
126
|
|
|
89
127
|
if result['migration_run']:
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""
|
|
2
|
+
revert-migration command - Revert the last migration.
|
|
3
|
+
|
|
4
|
+
Uses the annotated git tag ho-migration/<version> created during migration
|
|
5
|
+
to identify the exact commits to revert on each branch.
|
|
6
|
+
|
|
7
|
+
Not available after a production promotion (the tag is deleted at that point).
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import click
|
|
11
|
+
from half_orm_dev.repo import Repo, RepoError
|
|
12
|
+
from half_orm_dev.migration_manager import MigrationManagerError
|
|
13
|
+
from half_orm import utils
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@click.command('revert-migration')
|
|
17
|
+
def revert_migration() -> None:
|
|
18
|
+
"""
|
|
19
|
+
Revert the last migration applied by 'half_orm dev migrate'.
|
|
20
|
+
|
|
21
|
+
Uses the annotated tag ho-migration/<version> to locate the exact
|
|
22
|
+
commits and runs 'git revert --no-edit' on each affected branch.
|
|
23
|
+
|
|
24
|
+
\b
|
|
25
|
+
Constraints:
|
|
26
|
+
• Must be on ho-prod branch
|
|
27
|
+
• Not possible after a production promotion
|
|
28
|
+
|
|
29
|
+
\b
|
|
30
|
+
Multiple migrations:
|
|
31
|
+
Call repeatedly to roll back a chain of migrations (LIFO order).
|
|
32
|
+
Each call reverts the migration with the highest version number.
|
|
33
|
+
"""
|
|
34
|
+
try:
|
|
35
|
+
repo = Repo()
|
|
36
|
+
|
|
37
|
+
if not repo.checked:
|
|
38
|
+
click.echo(utils.Color.red("❌ Not in a hop repository"), err=True)
|
|
39
|
+
raise click.Abort()
|
|
40
|
+
|
|
41
|
+
repo.revert_migration()
|
|
42
|
+
click.echo(f"✓ {utils.Color.green('Migration reverted successfully.')}")
|
|
43
|
+
|
|
44
|
+
except (RepoError, MigrationManagerError) as e:
|
|
45
|
+
click.echo(utils.Color.red(f"❌ {e}"), err=True)
|
|
46
|
+
raise click.Abort()
|
|
47
|
+
except Exception as e:
|
|
48
|
+
click.echo(utils.Color.red(f"❌ Unexpected error: {e}"), err=True)
|
|
49
|
+
raise click.Abort()
|
|
@@ -62,7 +62,8 @@ class Hop:
|
|
|
62
62
|
return ['update', 'upgrade', 'bootstrap']
|
|
63
63
|
else:
|
|
64
64
|
# DEVELOPMENT ENVIRONMENT - Patch development
|
|
65
|
-
return ['patch', 'release', 'check', 'bootstrap', 'set-git-origin'
|
|
65
|
+
return ['patch', 'release', 'check', 'bootstrap', 'set-git-origin',
|
|
66
|
+
'revert-migration']
|
|
66
67
|
|
|
67
68
|
@property
|
|
68
69
|
def repo_checked(self):
|