half-orm-dev 0.17.4a2__tar.gz → 0.17.5a1__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.17.4a2/half_orm_dev.egg-info → half_orm_dev-0.17.5a1}/PKG-INFO +77 -78
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/README.md +76 -77
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/hgit.py +1 -1
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/migration_manager.py +46 -0
- half_orm_dev-0.17.5a1/half_orm_dev/migrations/0/17/5/01_update_pyproject_dependency.py +113 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/patch_manager.py +5 -1
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/repo.py +2 -9
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/templates/pyproject.toml +1 -1
- half_orm_dev-0.17.5a1/half_orm_dev/version.txt +1 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1/half_orm_dev.egg-info}/PKG-INFO +77 -78
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev.egg-info/SOURCES.txt +1 -1
- half_orm_dev-0.17.4a2/half_orm_dev/templates/Pipfile +0 -13
- half_orm_dev-0.17.4a2/half_orm_dev/version.txt +0 -1
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/AUTHORS +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/LICENSE +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/__init__.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/bootstrap_manager.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/cli/__init__.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/cli/commands/__init__.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/cli/commands/apply.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/cli/commands/bootstrap.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/cli/commands/check.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/cli/commands/clone.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/cli/commands/init.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/cli/commands/migrate.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/cli/commands/patch.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/cli/commands/release.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/cli/commands/restore.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/cli/commands/sync.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/cli/commands/todo.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/cli/commands/undo.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/cli/commands/update.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/cli/commands/upgrade.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/cli/main.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/cli_extension.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/database.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/decorators.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/file_executor.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/migrations/0/17/1/00_move_to_hop.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/migrations/0/17/1/01_txt_to_toml.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/migrations/0/17/4/00_toml_dict_format.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/migrations/0/17/4/01_add_bootstrap_table.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/migrations/0/17/4/02_move_patches_to_subdirs.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/modules.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/patch_validator.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/patches/0/1/0/00_half_orm_meta.database.sql +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/patches/0/1/0/01_alter_half_orm_meta.hop_release.sql +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/patches/0/1/0/02_half_orm_meta.view.hop_penultimate_release.sql +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/patches/log +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/patches/sql/half_orm_meta.sql +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/release_file.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/release_manager.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/scripts/repair-metadata.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/templates/.gitignore +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/templates/MANIFEST.in +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/templates/README +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/templates/conftest_template +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/templates/git-hooks/pre-commit +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/templates/git-hooks/prepare-commit-msg +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/templates/init_module_template +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/templates/module_template_1 +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/templates/module_template_2 +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/templates/module_template_3 +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/templates/relation_test +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/templates/sql_adapter +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/templates/warning +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev/utils.py +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev.egg-info/dependency_links.txt +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev.egg-info/requires.txt +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/half_orm_dev.egg-info/top_level.txt +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/pyproject.toml +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/setup.cfg +0 -0
- {half_orm_dev-0.17.4a2 → half_orm_dev-0.17.5a1}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: half_orm_dev
|
|
3
|
-
Version: 0.17.
|
|
3
|
+
Version: 0.17.5a1
|
|
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
|
|
@@ -35,7 +35,7 @@ Dynamic: requires-dist
|
|
|
35
35
|
|
|
36
36
|
> **Please report any issues at [GitHub Issues](https://github.com/half-orm/half-orm-dev/issues)**
|
|
37
37
|
|
|
38
|
-
**Git-centric patch management and database versioning for half-orm projects**
|
|
38
|
+
**Git-centric patch management and PostgreSQL database versioning for half-orm projects**
|
|
39
39
|
|
|
40
40
|
[](https://www.python.org/downloads/)
|
|
41
41
|
[](https://www.gnu.org/licenses/gpl-3.0)
|
|
@@ -53,6 +53,7 @@ Modern development workflow for PostgreSQL databases with automatic code generat
|
|
|
53
53
|
- **Git-centric workflow**: Patches stored in Git branches with semantic versioning
|
|
54
54
|
- **Test-Driven Development**: **Automatic validation** - tests run before integration, patches blocked if tests fail
|
|
55
55
|
- **Code generation**: Python classes auto-generated from schema changes
|
|
56
|
+
- **Data bootstrapping**: Initialize reference data and configurations with tracked scripts
|
|
56
57
|
- **Safe deployments**: Sequential releases with automatic backups and validation
|
|
57
58
|
- **Team collaboration**: Distributed locks, branch management, conflict prevention
|
|
58
59
|
- **Cloud-friendly**: No superuser privileges required (works on AWS RDS, Azure, GCP)
|
|
@@ -74,10 +75,11 @@ half_orm dev patch merge
|
|
|
74
75
|
|
|
75
76
|
# Behind the scenes:
|
|
76
77
|
# 1. Creates temporary validation branch
|
|
77
|
-
# 2.
|
|
78
|
-
# 3.
|
|
79
|
-
# 4.
|
|
80
|
-
# 5.
|
|
78
|
+
# 2. Restores database from production schema
|
|
79
|
+
# 3. Applies ALL release patches sequentially
|
|
80
|
+
# 4. Runs pytest automatically
|
|
81
|
+
# 5. ✅ If PASS → merges into release, status → "staged"
|
|
82
|
+
# 6. ❌ If FAIL → nothing committed, temp branch deleted
|
|
81
83
|
```
|
|
82
84
|
|
|
83
85
|
**Benefits:**
|
|
@@ -100,6 +102,7 @@ half_orm dev patch merge
|
|
|
100
102
|
- **Semantic versioning**: patch/minor/major increments
|
|
101
103
|
- **Sequential promotion**: stage → rc → production workflow
|
|
102
104
|
- **Release candidates**: RC validation before production
|
|
105
|
+
- **Hotfix support**: Reopen last released version for urgent fixes
|
|
103
106
|
- **Branch cleanup**: Automatic deletion after promotion
|
|
104
107
|
|
|
105
108
|
### 🚀 Production
|
|
@@ -115,8 +118,8 @@ half_orm dev patch merge
|
|
|
115
118
|
|
|
116
119
|
### Prerequisites
|
|
117
120
|
|
|
118
|
-
- **Python 3.9
|
|
119
|
-
- **PostgreSQL
|
|
121
|
+
- **Python**: [Active versions](https://devguide.python.org/versions/) (currently 3.9+)
|
|
122
|
+
- **PostgreSQL**: [Supported versions](https://www.postgresql.org/support/versioning/) (currently 13+)
|
|
120
123
|
- **Git** for version control
|
|
121
124
|
|
|
122
125
|
### Install
|
|
@@ -138,8 +141,8 @@ half_orm dev --help
|
|
|
138
141
|
### Initialize New Project
|
|
139
142
|
|
|
140
143
|
```bash
|
|
141
|
-
# Create project with database
|
|
142
|
-
half_orm dev init myproject --database mydb
|
|
144
|
+
# Create project with database (requires git origin)
|
|
145
|
+
half_orm dev init myproject --database mydb --git-origin git@github.com:user/myproject.git
|
|
143
146
|
cd myproject
|
|
144
147
|
```
|
|
145
148
|
|
|
@@ -235,6 +238,7 @@ ho-prod (main production branch)
|
|
|
235
238
|
├── 0.17.0-patches.toml # Development (mutable: candidate/staged status)
|
|
236
239
|
├── 0.17.0-rc1.txt # Release candidate snapshot (immutable)
|
|
237
240
|
├── 0.17.0.txt # Production snapshot (immutable)
|
|
241
|
+
├── 0.17.0-hotfix1.txt # Hotfix snapshot (immutable)
|
|
238
242
|
└── 0.18.0-patches.toml # Next version in progress
|
|
239
243
|
```
|
|
240
244
|
|
|
@@ -249,7 +253,7 @@ ho-prod (main production branch)
|
|
|
249
253
|
┌─────────────────────────────────────────────────────────────┐
|
|
250
254
|
│ DEVELOPMENT WORKFLOW │
|
|
251
255
|
├─────────────────────────────────────────────────────────────┤
|
|
252
|
-
│ 1. release create <level> Create ho-release/X.Y.Z
|
|
256
|
+
│ 1. release create <level> Create ho-release/X.Y.Z │
|
|
253
257
|
│ 2. patch create <id> Create patch (auto-candidate) │
|
|
254
258
|
│ 3. patch apply Apply & test changes │
|
|
255
259
|
│ 4. patch merge Merge into release (TESTS!) │
|
|
@@ -263,6 +267,11 @@ ho-prod (main production branch)
|
|
|
263
267
|
│ PRODUCTION DEPLOYMENT │
|
|
264
268
|
│ 7. update Check available releases │
|
|
265
269
|
│ 8. upgrade Apply on production servers │
|
|
270
|
+
│ │
|
|
271
|
+
│ HOTFIX (urgent production fix) │
|
|
272
|
+
│ 9. release hotfix Reopen last released version │
|
|
273
|
+
│10. patch create/merge Fix and validate │
|
|
274
|
+
│11. release promote hotfix Deploy hotfix │
|
|
266
275
|
└─────────────────────────────────────────────────────────────┘
|
|
267
276
|
```
|
|
268
277
|
|
|
@@ -273,33 +282,31 @@ ho-prod (main production branch)
|
|
|
273
282
|
### Init & Clone
|
|
274
283
|
|
|
275
284
|
```bash
|
|
276
|
-
# Create new project
|
|
277
|
-
half_orm dev init <package_name> --database <db_name>
|
|
285
|
+
# Create new project (requires git origin)
|
|
286
|
+
half_orm dev init <package_name> --database <db_name> --git-origin <url>
|
|
278
287
|
|
|
279
288
|
# Clone existing project
|
|
280
289
|
half_orm dev clone <git_origin>
|
|
281
290
|
```
|
|
282
291
|
|
|
283
|
-
###
|
|
292
|
+
### Check
|
|
284
293
|
|
|
285
294
|
```bash
|
|
286
|
-
#
|
|
287
|
-
half_orm dev
|
|
288
|
-
|
|
289
|
-
# Apply current patch (must be on ho-patch/* branch)
|
|
290
|
-
half_orm dev patch apply
|
|
295
|
+
# Verify and update project configuration
|
|
296
|
+
half_orm dev check
|
|
291
297
|
|
|
292
|
-
#
|
|
293
|
-
|
|
294
|
-
half_orm dev patch merge
|
|
298
|
+
# Preview what would be done
|
|
299
|
+
half_orm dev check --dry-run
|
|
295
300
|
```
|
|
296
301
|
|
|
297
|
-
**
|
|
302
|
+
**Note:** This command runs automatically before other commands (git hooks, configuration, stale branches cleanup).
|
|
298
303
|
|
|
299
304
|
### Release Commands
|
|
300
305
|
|
|
306
|
+
A release must be created before creating patches.
|
|
307
|
+
|
|
301
308
|
```bash
|
|
302
|
-
# Create new release
|
|
309
|
+
# Create new release (must be on ho-prod branch)
|
|
303
310
|
half_orm dev release create patch # X.Y.(Z+1)
|
|
304
311
|
half_orm dev release create minor # X.(Y+1).0
|
|
305
312
|
half_orm dev release create major # (X+1).0.0
|
|
@@ -315,6 +322,24 @@ half_orm dev release hotfix # Reopen production version
|
|
|
315
322
|
half_orm dev release promote hotfix # Deploy hotfix
|
|
316
323
|
```
|
|
317
324
|
|
|
325
|
+
### Patch Commands
|
|
326
|
+
|
|
327
|
+
```bash
|
|
328
|
+
# Create new patch (must be on ho-release/* branch)
|
|
329
|
+
half_orm dev patch create <patch_id>
|
|
330
|
+
|
|
331
|
+
# Apply current patch (must be on ho-patch/* branch)
|
|
332
|
+
half_orm dev patch apply
|
|
333
|
+
|
|
334
|
+
# Merge patch into release (AUTOMATIC VALIDATION!)
|
|
335
|
+
# Must be on ho-patch/* branch
|
|
336
|
+
half_orm dev patch merge
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
**Tip:** Patch IDs must start with a number (e.g., `123-add-users`). This number automatically closes the corresponding GitHub/GitLab issue #123 when the patch is merged.
|
|
340
|
+
|
|
341
|
+
**Patch files:** SQL (`.sql`) or Python (`.py`) files in `Patches/<patch_id>/`, executed in lexicographic order.
|
|
342
|
+
|
|
318
343
|
### Production Commands
|
|
319
344
|
|
|
320
345
|
```bash
|
|
@@ -328,6 +353,20 @@ half_orm dev upgrade [--to-release X.Y.Z]
|
|
|
328
353
|
half_orm dev upgrade --dry-run
|
|
329
354
|
```
|
|
330
355
|
|
|
356
|
+
### Data Bootstrap
|
|
357
|
+
|
|
358
|
+
Mark patch files with `-- @HOP:bootstrap` (SQL) or `# @HOP:bootstrap` (Python) to declare reference data:
|
|
359
|
+
|
|
360
|
+
```sql
|
|
361
|
+
-- @HOP:bootstrap
|
|
362
|
+
INSERT INTO roles (name) VALUES ('admin'), ('user') ON CONFLICT DO NOTHING;
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
These files are automatically:
|
|
366
|
+
- Copied to `bootstrap/` during `patch merge`
|
|
367
|
+
- Executed during production `upgrade`
|
|
368
|
+
- Tracked in database (each script runs once)
|
|
369
|
+
|
|
331
370
|
**Note:** Use `half_orm dev <command> --help` for detailed help on each command.
|
|
332
371
|
|
|
333
372
|
---
|
|
@@ -360,47 +399,17 @@ half_orm dev patch merge
|
|
|
360
399
|
|
|
361
400
|
---
|
|
362
401
|
|
|
363
|
-
## 🎓
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
-
|
|
368
|
-
-
|
|
369
|
-
-
|
|
370
|
-
-
|
|
371
|
-
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
- Skip writing tests (validation will fail anyway)
|
|
375
|
-
- Mix multiple features in one patch
|
|
376
|
-
- Bypass test validation (it's there for safety)
|
|
377
|
-
- Modify files outside your patch directory
|
|
378
|
-
|
|
379
|
-
### Release Management
|
|
380
|
-
✅ **DO:**
|
|
381
|
-
- Trust the automatic test validation system
|
|
382
|
-
- Test RC thoroughly before promoting to production
|
|
383
|
-
- Use semantic versioning consistently
|
|
384
|
-
- Review test failures carefully before retrying
|
|
385
|
-
|
|
386
|
-
❌ **DON'T:**
|
|
387
|
-
- Skip RC validation
|
|
388
|
-
- Force promote without fixing issues
|
|
389
|
-
- Bypass test validation
|
|
390
|
-
- Ignore test failures
|
|
391
|
-
|
|
392
|
-
### Production Deployment
|
|
393
|
-
✅ **DO:**
|
|
394
|
-
- Always run `update` first to check available releases
|
|
395
|
-
- Use `--dry-run` to preview changes
|
|
396
|
-
- Verify backups exist before upgrade
|
|
397
|
-
- Verify all tests passed in RC before promoting
|
|
398
|
-
|
|
399
|
-
❌ **DON'T:**
|
|
400
|
-
- Deploy without testing in RC first
|
|
401
|
-
- Skip backup verification
|
|
402
|
-
- Promote to production if RC tests failed
|
|
403
|
-
- Apply patches directly without releases
|
|
402
|
+
## 🎓 Development Philosophy
|
|
403
|
+
|
|
404
|
+
half-orm-dev combines **Domain-Driven Design** with **Test-Driven Development**, integrated into Git:
|
|
405
|
+
|
|
406
|
+
1. **Schema as domain model** - The PostgreSQL schema defines your domain; Python classes are auto-generated
|
|
407
|
+
2. **Write tests first** - Define expected behavior before implementation
|
|
408
|
+
3. **Develop in isolation** - Each patch has its own branch and directory
|
|
409
|
+
4. **Validate automatically** - Tests run during `patch merge`, blocking integration if they fail
|
|
410
|
+
5. **Deploy with confidence** - Only validated code reaches production
|
|
411
|
+
|
|
412
|
+
This approach ensures that every schema change is tested in the full release context before integration.
|
|
404
413
|
|
|
405
414
|
---
|
|
406
415
|
|
|
@@ -463,11 +472,11 @@ git stash
|
|
|
463
472
|
git pull origin ho-prod
|
|
464
473
|
```
|
|
465
474
|
|
|
466
|
-
### Error: "No
|
|
475
|
+
### Error: "No staged releases found"
|
|
467
476
|
|
|
468
477
|
```bash
|
|
469
|
-
# Solution:
|
|
470
|
-
half_orm dev release
|
|
478
|
+
# Solution: Create a release first
|
|
479
|
+
half_orm dev release create patch
|
|
471
480
|
```
|
|
472
481
|
|
|
473
482
|
### Error: "Active RC exists"
|
|
@@ -496,16 +505,6 @@ git checkout ho-patch/123-feature
|
|
|
496
505
|
half_orm dev patch merge # Tests will run again
|
|
497
506
|
```
|
|
498
507
|
|
|
499
|
-
### Error: "Repository is not clean"
|
|
500
|
-
```bash
|
|
501
|
-
# Commit or stash changes
|
|
502
|
-
git status
|
|
503
|
-
git add .
|
|
504
|
-
git commit -m "Your message"
|
|
505
|
-
# or
|
|
506
|
-
git stash
|
|
507
|
-
```
|
|
508
|
-
|
|
509
508
|
For more troubleshooting, see [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
|
|
510
509
|
|
|
511
510
|
---
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
> **Please report any issues at [GitHub Issues](https://github.com/half-orm/half-orm-dev/issues)**
|
|
6
6
|
|
|
7
|
-
**Git-centric patch management and database versioning for half-orm projects**
|
|
7
|
+
**Git-centric patch management and PostgreSQL database versioning for half-orm projects**
|
|
8
8
|
|
|
9
9
|
[](https://www.python.org/downloads/)
|
|
10
10
|
[](https://www.gnu.org/licenses/gpl-3.0)
|
|
@@ -22,6 +22,7 @@ Modern development workflow for PostgreSQL databases with automatic code generat
|
|
|
22
22
|
- **Git-centric workflow**: Patches stored in Git branches with semantic versioning
|
|
23
23
|
- **Test-Driven Development**: **Automatic validation** - tests run before integration, patches blocked if tests fail
|
|
24
24
|
- **Code generation**: Python classes auto-generated from schema changes
|
|
25
|
+
- **Data bootstrapping**: Initialize reference data and configurations with tracked scripts
|
|
25
26
|
- **Safe deployments**: Sequential releases with automatic backups and validation
|
|
26
27
|
- **Team collaboration**: Distributed locks, branch management, conflict prevention
|
|
27
28
|
- **Cloud-friendly**: No superuser privileges required (works on AWS RDS, Azure, GCP)
|
|
@@ -43,10 +44,11 @@ half_orm dev patch merge
|
|
|
43
44
|
|
|
44
45
|
# Behind the scenes:
|
|
45
46
|
# 1. Creates temporary validation branch
|
|
46
|
-
# 2.
|
|
47
|
-
# 3.
|
|
48
|
-
# 4.
|
|
49
|
-
# 5.
|
|
47
|
+
# 2. Restores database from production schema
|
|
48
|
+
# 3. Applies ALL release patches sequentially
|
|
49
|
+
# 4. Runs pytest automatically
|
|
50
|
+
# 5. ✅ If PASS → merges into release, status → "staged"
|
|
51
|
+
# 6. ❌ If FAIL → nothing committed, temp branch deleted
|
|
50
52
|
```
|
|
51
53
|
|
|
52
54
|
**Benefits:**
|
|
@@ -69,6 +71,7 @@ half_orm dev patch merge
|
|
|
69
71
|
- **Semantic versioning**: patch/minor/major increments
|
|
70
72
|
- **Sequential promotion**: stage → rc → production workflow
|
|
71
73
|
- **Release candidates**: RC validation before production
|
|
74
|
+
- **Hotfix support**: Reopen last released version for urgent fixes
|
|
72
75
|
- **Branch cleanup**: Automatic deletion after promotion
|
|
73
76
|
|
|
74
77
|
### 🚀 Production
|
|
@@ -84,8 +87,8 @@ half_orm dev patch merge
|
|
|
84
87
|
|
|
85
88
|
### Prerequisites
|
|
86
89
|
|
|
87
|
-
- **Python 3.9
|
|
88
|
-
- **PostgreSQL
|
|
90
|
+
- **Python**: [Active versions](https://devguide.python.org/versions/) (currently 3.9+)
|
|
91
|
+
- **PostgreSQL**: [Supported versions](https://www.postgresql.org/support/versioning/) (currently 13+)
|
|
89
92
|
- **Git** for version control
|
|
90
93
|
|
|
91
94
|
### Install
|
|
@@ -107,8 +110,8 @@ half_orm dev --help
|
|
|
107
110
|
### Initialize New Project
|
|
108
111
|
|
|
109
112
|
```bash
|
|
110
|
-
# Create project with database
|
|
111
|
-
half_orm dev init myproject --database mydb
|
|
113
|
+
# Create project with database (requires git origin)
|
|
114
|
+
half_orm dev init myproject --database mydb --git-origin git@github.com:user/myproject.git
|
|
112
115
|
cd myproject
|
|
113
116
|
```
|
|
114
117
|
|
|
@@ -204,6 +207,7 @@ ho-prod (main production branch)
|
|
|
204
207
|
├── 0.17.0-patches.toml # Development (mutable: candidate/staged status)
|
|
205
208
|
├── 0.17.0-rc1.txt # Release candidate snapshot (immutable)
|
|
206
209
|
├── 0.17.0.txt # Production snapshot (immutable)
|
|
210
|
+
├── 0.17.0-hotfix1.txt # Hotfix snapshot (immutable)
|
|
207
211
|
└── 0.18.0-patches.toml # Next version in progress
|
|
208
212
|
```
|
|
209
213
|
|
|
@@ -218,7 +222,7 @@ ho-prod (main production branch)
|
|
|
218
222
|
┌─────────────────────────────────────────────────────────────┐
|
|
219
223
|
│ DEVELOPMENT WORKFLOW │
|
|
220
224
|
├─────────────────────────────────────────────────────────────┤
|
|
221
|
-
│ 1. release create <level> Create ho-release/X.Y.Z
|
|
225
|
+
│ 1. release create <level> Create ho-release/X.Y.Z │
|
|
222
226
|
│ 2. patch create <id> Create patch (auto-candidate) │
|
|
223
227
|
│ 3. patch apply Apply & test changes │
|
|
224
228
|
│ 4. patch merge Merge into release (TESTS!) │
|
|
@@ -232,6 +236,11 @@ ho-prod (main production branch)
|
|
|
232
236
|
│ PRODUCTION DEPLOYMENT │
|
|
233
237
|
│ 7. update Check available releases │
|
|
234
238
|
│ 8. upgrade Apply on production servers │
|
|
239
|
+
│ │
|
|
240
|
+
│ HOTFIX (urgent production fix) │
|
|
241
|
+
│ 9. release hotfix Reopen last released version │
|
|
242
|
+
│10. patch create/merge Fix and validate │
|
|
243
|
+
│11. release promote hotfix Deploy hotfix │
|
|
235
244
|
└─────────────────────────────────────────────────────────────┘
|
|
236
245
|
```
|
|
237
246
|
|
|
@@ -242,33 +251,31 @@ ho-prod (main production branch)
|
|
|
242
251
|
### Init & Clone
|
|
243
252
|
|
|
244
253
|
```bash
|
|
245
|
-
# Create new project
|
|
246
|
-
half_orm dev init <package_name> --database <db_name>
|
|
254
|
+
# Create new project (requires git origin)
|
|
255
|
+
half_orm dev init <package_name> --database <db_name> --git-origin <url>
|
|
247
256
|
|
|
248
257
|
# Clone existing project
|
|
249
258
|
half_orm dev clone <git_origin>
|
|
250
259
|
```
|
|
251
260
|
|
|
252
|
-
###
|
|
261
|
+
### Check
|
|
253
262
|
|
|
254
263
|
```bash
|
|
255
|
-
#
|
|
256
|
-
half_orm dev
|
|
257
|
-
|
|
258
|
-
# Apply current patch (must be on ho-patch/* branch)
|
|
259
|
-
half_orm dev patch apply
|
|
264
|
+
# Verify and update project configuration
|
|
265
|
+
half_orm dev check
|
|
260
266
|
|
|
261
|
-
#
|
|
262
|
-
|
|
263
|
-
half_orm dev patch merge
|
|
267
|
+
# Preview what would be done
|
|
268
|
+
half_orm dev check --dry-run
|
|
264
269
|
```
|
|
265
270
|
|
|
266
|
-
**
|
|
271
|
+
**Note:** This command runs automatically before other commands (git hooks, configuration, stale branches cleanup).
|
|
267
272
|
|
|
268
273
|
### Release Commands
|
|
269
274
|
|
|
275
|
+
A release must be created before creating patches.
|
|
276
|
+
|
|
270
277
|
```bash
|
|
271
|
-
# Create new release
|
|
278
|
+
# Create new release (must be on ho-prod branch)
|
|
272
279
|
half_orm dev release create patch # X.Y.(Z+1)
|
|
273
280
|
half_orm dev release create minor # X.(Y+1).0
|
|
274
281
|
half_orm dev release create major # (X+1).0.0
|
|
@@ -284,6 +291,24 @@ half_orm dev release hotfix # Reopen production version
|
|
|
284
291
|
half_orm dev release promote hotfix # Deploy hotfix
|
|
285
292
|
```
|
|
286
293
|
|
|
294
|
+
### Patch Commands
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
# Create new patch (must be on ho-release/* branch)
|
|
298
|
+
half_orm dev patch create <patch_id>
|
|
299
|
+
|
|
300
|
+
# Apply current patch (must be on ho-patch/* branch)
|
|
301
|
+
half_orm dev patch apply
|
|
302
|
+
|
|
303
|
+
# Merge patch into release (AUTOMATIC VALIDATION!)
|
|
304
|
+
# Must be on ho-patch/* branch
|
|
305
|
+
half_orm dev patch merge
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
**Tip:** Patch IDs must start with a number (e.g., `123-add-users`). This number automatically closes the corresponding GitHub/GitLab issue #123 when the patch is merged.
|
|
309
|
+
|
|
310
|
+
**Patch files:** SQL (`.sql`) or Python (`.py`) files in `Patches/<patch_id>/`, executed in lexicographic order.
|
|
311
|
+
|
|
287
312
|
### Production Commands
|
|
288
313
|
|
|
289
314
|
```bash
|
|
@@ -297,6 +322,20 @@ half_orm dev upgrade [--to-release X.Y.Z]
|
|
|
297
322
|
half_orm dev upgrade --dry-run
|
|
298
323
|
```
|
|
299
324
|
|
|
325
|
+
### Data Bootstrap
|
|
326
|
+
|
|
327
|
+
Mark patch files with `-- @HOP:bootstrap` (SQL) or `# @HOP:bootstrap` (Python) to declare reference data:
|
|
328
|
+
|
|
329
|
+
```sql
|
|
330
|
+
-- @HOP:bootstrap
|
|
331
|
+
INSERT INTO roles (name) VALUES ('admin'), ('user') ON CONFLICT DO NOTHING;
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
These files are automatically:
|
|
335
|
+
- Copied to `bootstrap/` during `patch merge`
|
|
336
|
+
- Executed during production `upgrade`
|
|
337
|
+
- Tracked in database (each script runs once)
|
|
338
|
+
|
|
300
339
|
**Note:** Use `half_orm dev <command> --help` for detailed help on each command.
|
|
301
340
|
|
|
302
341
|
---
|
|
@@ -329,47 +368,17 @@ half_orm dev patch merge
|
|
|
329
368
|
|
|
330
369
|
---
|
|
331
370
|
|
|
332
|
-
## 🎓
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
-
|
|
337
|
-
-
|
|
338
|
-
-
|
|
339
|
-
-
|
|
340
|
-
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
- Skip writing tests (validation will fail anyway)
|
|
344
|
-
- Mix multiple features in one patch
|
|
345
|
-
- Bypass test validation (it's there for safety)
|
|
346
|
-
- Modify files outside your patch directory
|
|
347
|
-
|
|
348
|
-
### Release Management
|
|
349
|
-
✅ **DO:**
|
|
350
|
-
- Trust the automatic test validation system
|
|
351
|
-
- Test RC thoroughly before promoting to production
|
|
352
|
-
- Use semantic versioning consistently
|
|
353
|
-
- Review test failures carefully before retrying
|
|
354
|
-
|
|
355
|
-
❌ **DON'T:**
|
|
356
|
-
- Skip RC validation
|
|
357
|
-
- Force promote without fixing issues
|
|
358
|
-
- Bypass test validation
|
|
359
|
-
- Ignore test failures
|
|
360
|
-
|
|
361
|
-
### Production Deployment
|
|
362
|
-
✅ **DO:**
|
|
363
|
-
- Always run `update` first to check available releases
|
|
364
|
-
- Use `--dry-run` to preview changes
|
|
365
|
-
- Verify backups exist before upgrade
|
|
366
|
-
- Verify all tests passed in RC before promoting
|
|
367
|
-
|
|
368
|
-
❌ **DON'T:**
|
|
369
|
-
- Deploy without testing in RC first
|
|
370
|
-
- Skip backup verification
|
|
371
|
-
- Promote to production if RC tests failed
|
|
372
|
-
- Apply patches directly without releases
|
|
371
|
+
## 🎓 Development Philosophy
|
|
372
|
+
|
|
373
|
+
half-orm-dev combines **Domain-Driven Design** with **Test-Driven Development**, integrated into Git:
|
|
374
|
+
|
|
375
|
+
1. **Schema as domain model** - The PostgreSQL schema defines your domain; Python classes are auto-generated
|
|
376
|
+
2. **Write tests first** - Define expected behavior before implementation
|
|
377
|
+
3. **Develop in isolation** - Each patch has its own branch and directory
|
|
378
|
+
4. **Validate automatically** - Tests run during `patch merge`, blocking integration if they fail
|
|
379
|
+
5. **Deploy with confidence** - Only validated code reaches production
|
|
380
|
+
|
|
381
|
+
This approach ensures that every schema change is tested in the full release context before integration.
|
|
373
382
|
|
|
374
383
|
---
|
|
375
384
|
|
|
@@ -432,11 +441,11 @@ git stash
|
|
|
432
441
|
git pull origin ho-prod
|
|
433
442
|
```
|
|
434
443
|
|
|
435
|
-
### Error: "No
|
|
444
|
+
### Error: "No staged releases found"
|
|
436
445
|
|
|
437
446
|
```bash
|
|
438
|
-
# Solution:
|
|
439
|
-
half_orm dev release
|
|
447
|
+
# Solution: Create a release first
|
|
448
|
+
half_orm dev release create patch
|
|
440
449
|
```
|
|
441
450
|
|
|
442
451
|
### Error: "Active RC exists"
|
|
@@ -465,16 +474,6 @@ git checkout ho-patch/123-feature
|
|
|
465
474
|
half_orm dev patch merge # Tests will run again
|
|
466
475
|
```
|
|
467
476
|
|
|
468
|
-
### Error: "Repository is not clean"
|
|
469
|
-
```bash
|
|
470
|
-
# Commit or stash changes
|
|
471
|
-
git status
|
|
472
|
-
git add .
|
|
473
|
-
git commit -m "Your message"
|
|
474
|
-
# or
|
|
475
|
-
git stash
|
|
476
|
-
```
|
|
477
|
-
|
|
478
477
|
For more troubleshooting, see [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
|
|
479
478
|
|
|
480
479
|
---
|
|
@@ -925,7 +925,7 @@ class HGit:
|
|
|
925
925
|
match = re.search(r'-(\d+)$', existing_locks[0])
|
|
926
926
|
if match:
|
|
927
927
|
lock_timestamp_ms = int(match.group(1))
|
|
928
|
-
lock_time = datetime.
|
|
928
|
+
lock_time = datetime.fromtimestamp(lock_timestamp_ms / 1000.0, tz=timezone.utc)
|
|
929
929
|
current_time = datetime.now(timezone.utc)
|
|
930
930
|
|
|
931
931
|
# Check if lock is stale
|
|
@@ -302,6 +302,9 @@ class MigrationManager:
|
|
|
302
302
|
self._repo._Repo__config.hop_version = target_version
|
|
303
303
|
self._repo._Repo__config.write()
|
|
304
304
|
|
|
305
|
+
# Update half_orm_dev version in pyproject.toml
|
|
306
|
+
self._update_pyproject_dependency_version(target_version)
|
|
307
|
+
|
|
305
308
|
# Create Git commit if requested
|
|
306
309
|
if create_commit and self._repo.hgit:
|
|
307
310
|
try:
|
|
@@ -367,6 +370,49 @@ class MigrationManager:
|
|
|
367
370
|
|
|
368
371
|
return '\n'.join(lines)
|
|
369
372
|
|
|
373
|
+
def _update_pyproject_dependency_version(self, target_version: str) -> None:
|
|
374
|
+
"""
|
|
375
|
+
Update half_orm_dev version in pyproject.toml.
|
|
376
|
+
|
|
377
|
+
This ensures the project's dependency on half_orm_dev always matches
|
|
378
|
+
the current tool version after each migration.
|
|
379
|
+
|
|
380
|
+
Handles both == and >= version specifiers.
|
|
381
|
+
|
|
382
|
+
Args:
|
|
383
|
+
target_version: New version to set for half_orm_dev dependency
|
|
384
|
+
"""
|
|
385
|
+
import re
|
|
386
|
+
|
|
387
|
+
pyproject_path = Path(self._repo.base_dir) / "pyproject.toml"
|
|
388
|
+
|
|
389
|
+
if not pyproject_path.exists():
|
|
390
|
+
return
|
|
391
|
+
|
|
392
|
+
try:
|
|
393
|
+
content = pyproject_path.read_text()
|
|
394
|
+
|
|
395
|
+
# Only update if half_orm_dev dependency exists (== or >=)
|
|
396
|
+
if 'half_orm_dev==' not in content and 'half_orm_dev>=' not in content:
|
|
397
|
+
return
|
|
398
|
+
|
|
399
|
+
# Update the version (handles both == and >=)
|
|
400
|
+
new_content = re.sub(
|
|
401
|
+
r'half_orm_dev[>=]=[\d.a-zA-Z-]+',
|
|
402
|
+
f'half_orm_dev=={target_version}',
|
|
403
|
+
content
|
|
404
|
+
)
|
|
405
|
+
|
|
406
|
+
if new_content != content:
|
|
407
|
+
pyproject_path.write_text(new_content)
|
|
408
|
+
if self._repo.hgit:
|
|
409
|
+
self._repo.hgit.add(str(pyproject_path))
|
|
410
|
+
print(f" Updated pyproject.toml: half_orm_dev=={target_version}")
|
|
411
|
+
|
|
412
|
+
except Exception as e:
|
|
413
|
+
# Non-critical - don't fail migration
|
|
414
|
+
print(f" Warning: Could not update pyproject.toml: {e}")
|
|
415
|
+
|
|
370
416
|
def check_migration_needed(self, current_tool_version: str) -> bool:
|
|
371
417
|
"""
|
|
372
418
|
Check if migration is needed.
|