half-orm-dev 1.0.0a31__tar.gz → 1.0.0a32__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-1.0.0a31/half_orm_dev.egg-info → half_orm_dev-1.0.0a32}/PKG-INFO +22 -18
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/README.md +19 -17
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/cli/commands/__init__.py +0 -3
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/cli/commands/check.py +1 -1
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/cli/commands/recover.py +1 -1
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/cli/main.py +1 -1
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/file_executor.py +48 -46
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/hgit.py +43 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/migration_manager.py +1 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/migrations/0/17/4/00_toml_dict_format.py +3 -3
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/patch_manager.py +231 -180
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/release_file.py +3 -4
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/release_manager.py +37 -70
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/repo.py +157 -114
- half_orm_dev-1.0.0a32/half_orm_dev/version.txt +1 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32/half_orm_dev.egg-info}/PKG-INFO +22 -18
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev.egg-info/SOURCES.txt +0 -3
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev.egg-info/requires.txt +2 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/setup.py +2 -0
- half_orm_dev-1.0.0a31/half_orm_dev/bootstrap_manager.py +0 -392
- half_orm_dev-1.0.0a31/half_orm_dev/cli/commands/bootstrap.py +0 -139
- half_orm_dev-1.0.0a31/half_orm_dev/migrations/0/17/4/01_add_bootstrap_table.py +0 -103
- half_orm_dev-1.0.0a31/half_orm_dev/version.txt +0 -1
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/AUTHORS +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/LICENSE +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/__init__.py +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/cli/__init__.py +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/cli/commands/apply.py +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/cli/commands/clone.py +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/cli/commands/init.py +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/cli/commands/migrate.py +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/cli/commands/patch.py +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/cli/commands/release.py +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/cli/commands/restore.py +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/cli/commands/revert_migration.py +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/cli/commands/rollback.py +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/cli/commands/set_git_origin.py +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/cli/commands/sync.py +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/cli/commands/todo.py +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/cli/commands/undo.py +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/cli/commands/upgrade.py +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/cli_extension.py +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/database.py +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/decorators.py +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/migrations/0/17/1/00_move_to_hop.py +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/migrations/0/17/1/01_txt_to_toml.py +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/migrations/0/17/4/02_move_patches_to_subdirs.py +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/migrations/0/17/5/01_update_pyproject_dependency.py +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/migrations/0/18/0/00_add_async_support.py +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/migrations/0/18/0/01_update_default_tests.py +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/migrations/1/0/0/a20/01_update_gitignore.py +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/migrations/hop/BREAKING_CHANGES-1.0.0.md +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/modules.py +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/patch_validator.py +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/patches/0/1/0/00_half_orm_meta.database.sql +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/patches/0/1/0/01_alter_half_orm_meta.hop_release.sql +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/patches/0/1/0/02_half_orm_meta.view.hop_penultimate_release.sql +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/patches/log +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/patches/sql/half_orm_meta.sql +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/py.typed +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/scripts/repair-metadata.py +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/templates/.gitignore +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/templates/MANIFEST.in +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/templates/README +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/templates/conftest_template +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/templates/git-hooks/pre-commit +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/templates/git-hooks/pre-push +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/templates/git-hooks/prepare-commit-msg +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/templates/git-hooks/reference-transaction +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/templates/init_module_template +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/templates/module_template_1 +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/templates/module_template_2 +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/templates/module_template_3 +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/templates/pyproject.toml +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/templates/relation_test +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/templates/sql_adapter +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/templates/warning +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev/utils.py +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev.egg-info/dependency_links.txt +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev.egg-info/entry_points.txt +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/half_orm_dev.egg-info/top_level.txt +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/pyproject.toml +0 -0
- {half_orm_dev-1.0.0a31 → half_orm_dev-1.0.0a32}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: half_orm_dev
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.0a32
|
|
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
|
|
@@ -21,8 +21,10 @@ License-File: LICENSE
|
|
|
21
21
|
License-File: AUTHORS
|
|
22
22
|
Requires-Dist: GitPython
|
|
23
23
|
Requires-Dist: click
|
|
24
|
+
Requires-Dist: packaging
|
|
24
25
|
Requires-Dist: pydash
|
|
25
26
|
Requires-Dist: pytest
|
|
27
|
+
Requires-Dist: pytest-asyncio
|
|
26
28
|
Requires-Dist: half_orm<1.1.0,>=1.0.0a1
|
|
27
29
|
Requires-Dist: tomli>=2.0.0; python_version < "3.11"
|
|
28
30
|
Requires-Dist: tomli_w>=1.0.0
|
|
@@ -384,29 +386,31 @@ half_orm dev upgrade [--to-release X.Y.Z]
|
|
|
384
386
|
half_orm dev upgrade --dry-run
|
|
385
387
|
```
|
|
386
388
|
|
|
387
|
-
### Data
|
|
389
|
+
### Bootstrap - Data Initialization
|
|
388
390
|
|
|
389
|
-
|
|
390
|
-
The marker **must be on the first line** of the file:
|
|
391
|
+
Bootstrap scripts initialize application data on empty databases. Place SQL and Python files in the `bootstrap/` directory:
|
|
391
392
|
|
|
392
|
-
```sql
|
|
393
|
-
-- @HOP:bootstrap
|
|
394
|
-
INSERT INTO roles (name) VALUES ('admin'), ('user') ON CONFLICT DO NOTHING;
|
|
395
393
|
```
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
MyModel(field='value').ho_insert()
|
|
394
|
+
bootstrap/
|
|
395
|
+
├── 01-init-roles.sql
|
|
396
|
+
├── 02-seed-config.py
|
|
397
|
+
└── 03-reference-data.sql
|
|
401
398
|
```
|
|
402
399
|
|
|
403
|
-
|
|
404
|
-
-
|
|
405
|
-
-
|
|
406
|
-
|
|
400
|
+
Files are executed **alphabetically** during:
|
|
401
|
+
- **Development**: Each `patch apply` (allows iteration on bootstrap scripts)
|
|
402
|
+
- **Production**: Initial `clone` only (one-time initialization)
|
|
403
|
+
|
|
404
|
+
For production data changes, use **patches** (not bootstrap).
|
|
407
405
|
|
|
408
|
-
|
|
409
|
-
|
|
406
|
+
**Python files** can define a `run(model)` function to share the database connection:
|
|
407
|
+
|
|
408
|
+
```python
|
|
409
|
+
def run(model):
|
|
410
|
+
# model is the halfORM Model instance with active connection
|
|
411
|
+
MyModel = model.get_relation_class('schema.table')
|
|
412
|
+
MyModel(field='value').ho_insert()
|
|
413
|
+
```
|
|
410
414
|
|
|
411
415
|
**Note:** Use `half_orm dev <command> --help` for detailed help on each command.
|
|
412
416
|
|
|
@@ -353,29 +353,31 @@ half_orm dev upgrade [--to-release X.Y.Z]
|
|
|
353
353
|
half_orm dev upgrade --dry-run
|
|
354
354
|
```
|
|
355
355
|
|
|
356
|
-
### Data
|
|
356
|
+
### Bootstrap - Data Initialization
|
|
357
357
|
|
|
358
|
-
|
|
359
|
-
The marker **must be on the first line** of the file:
|
|
358
|
+
Bootstrap scripts initialize application data on empty databases. Place SQL and Python files in the `bootstrap/` directory:
|
|
360
359
|
|
|
361
|
-
```sql
|
|
362
|
-
-- @HOP:bootstrap
|
|
363
|
-
INSERT INTO roles (name) VALUES ('admin'), ('user') ON CONFLICT DO NOTHING;
|
|
364
360
|
```
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
MyModel(field='value').ho_insert()
|
|
361
|
+
bootstrap/
|
|
362
|
+
├── 01-init-roles.sql
|
|
363
|
+
├── 02-seed-config.py
|
|
364
|
+
└── 03-reference-data.sql
|
|
370
365
|
```
|
|
371
366
|
|
|
372
|
-
|
|
373
|
-
-
|
|
374
|
-
-
|
|
375
|
-
|
|
367
|
+
Files are executed **alphabetically** during:
|
|
368
|
+
- **Development**: Each `patch apply` (allows iteration on bootstrap scripts)
|
|
369
|
+
- **Production**: Initial `clone` only (one-time initialization)
|
|
370
|
+
|
|
371
|
+
For production data changes, use **patches** (not bootstrap).
|
|
376
372
|
|
|
377
|
-
|
|
378
|
-
|
|
373
|
+
**Python files** can define a `run(model)` function to share the database connection:
|
|
374
|
+
|
|
375
|
+
```python
|
|
376
|
+
def run(model):
|
|
377
|
+
# model is the halfORM Model instance with active connection
|
|
378
|
+
MyModel = model.get_relation_class('schema.table')
|
|
379
|
+
MyModel(field='value').ho_insert()
|
|
380
|
+
```
|
|
379
381
|
|
|
380
382
|
**Note:** Use `half_orm dev <command> --help` for detailed help on each command.
|
|
381
383
|
|
|
@@ -15,7 +15,6 @@ from .check import check
|
|
|
15
15
|
from .set_git_origin import set_git_origin
|
|
16
16
|
from .migrate import migrate
|
|
17
17
|
from .revert_migration import revert_migration
|
|
18
|
-
from .bootstrap import bootstrap
|
|
19
18
|
from .rollback import rollback
|
|
20
19
|
from .recover import recover
|
|
21
20
|
from .todo import apply_release
|
|
@@ -36,7 +35,6 @@ ALL_COMMANDS = {
|
|
|
36
35
|
'set-git-origin': set_git_origin, # Update git remote origin URL
|
|
37
36
|
'migrate': migrate, # Repository migration after upgrade
|
|
38
37
|
'revert-migration': revert_migration, # Revert last migration
|
|
39
|
-
'bootstrap': bootstrap, # Execute data initialization scripts
|
|
40
38
|
# 🚧 (stubs)
|
|
41
39
|
'apply_release': apply_release,
|
|
42
40
|
|
|
@@ -58,7 +56,6 @@ __all__ = [
|
|
|
58
56
|
'upgrade',
|
|
59
57
|
'check',
|
|
60
58
|
'migrate',
|
|
61
|
-
'bootstrap',
|
|
62
59
|
'rollback',
|
|
63
60
|
'recover',
|
|
64
61
|
# Adapted commands
|
|
@@ -162,7 +162,7 @@ def _display_check_results(repo, result: dict, dry_run: bool, verbose: bool):
|
|
|
162
162
|
click.echo(f"\n🔧 {utils.Color.bold('Orphaned patches')} ({len(orphaned_patches)}):")
|
|
163
163
|
for patch_id in sorted(orphaned_patches):
|
|
164
164
|
click.echo(f" • {patch_id}")
|
|
165
|
-
click.echo(f" {utils.Color.blue('(Use
|
|
165
|
+
click.echo(f""" {utils.Color.blue('(Use "half_orm dev release attach-patch <id>" to reattach)')}""")
|
|
166
166
|
|
|
167
167
|
# Show standalone patch branches (not in candidates/stage)
|
|
168
168
|
standalone_patches = [b for b in patch_branches
|
|
@@ -41,6 +41,6 @@ def recover() -> None:
|
|
|
41
41
|
|
|
42
42
|
if result['errors']:
|
|
43
43
|
for error in result['errors']:
|
|
44
|
-
click.echo(utils.Color.
|
|
44
|
+
click.echo(utils.Color.bold(f"Warning: {error}"), err=True)
|
|
45
45
|
|
|
46
46
|
click.echo(utils.Color.green("Recovery complete."))
|
|
@@ -60,7 +60,7 @@ class Hop:
|
|
|
60
60
|
return ['sync-package', 'check']
|
|
61
61
|
|
|
62
62
|
# DEVELOPMENT ENVIRONMENT - Patch development
|
|
63
|
-
return ['patch', 'release', 'check', '
|
|
63
|
+
return ['patch', 'release', 'check', 'set-git-origin',
|
|
64
64
|
'revert-migration', 'recover']
|
|
65
65
|
|
|
66
66
|
@property
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Shared utilities for executing SQL and Python files.
|
|
3
3
|
|
|
4
|
-
This module provides common file execution functionality
|
|
5
|
-
|
|
4
|
+
This module provides common file execution functionality for patch application
|
|
5
|
+
and bootstrap initialization.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
import ast
|
|
9
9
|
import importlib.util
|
|
10
|
-
import re
|
|
11
10
|
import subprocess
|
|
12
11
|
import sys
|
|
13
12
|
from pathlib import Path
|
|
@@ -166,54 +165,57 @@ def execute_python_bootstrap(file_path: Path, model, cwd: Optional[Path] = None)
|
|
|
166
165
|
sys.modules.pop(module_name, None)
|
|
167
166
|
|
|
168
167
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
def is_bootstrap_file(file_path: Path) -> bool:
|
|
168
|
+
def execute_bootstrap_files(bootstrap_dir: Path, model) -> None:
|
|
173
169
|
"""
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
The marker must be on the first line of the file:
|
|
177
|
-
- SQL files: -- @HOP:bootstrap or -- @HOP:data
|
|
178
|
-
- Python files: # @HOP:bootstrap or # @HOP:data
|
|
170
|
+
Execute all bootstrap files in alphabetic order.
|
|
179
171
|
|
|
180
|
-
|
|
172
|
+
Bootstrap files are SQL and Python files in the bootstrap/ directory that
|
|
173
|
+
initialize application data on empty databases. They are executed in
|
|
174
|
+
alphabetic order (no numeric parsing needed).
|
|
181
175
|
|
|
182
176
|
Args:
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
Returns:
|
|
186
|
-
True if file has bootstrap marker on first line, False otherwise
|
|
187
|
-
"""
|
|
188
|
-
try:
|
|
189
|
-
with file_path.open('r', encoding='utf-8') as f:
|
|
190
|
-
first_line = f.readline().strip().lower()
|
|
191
|
-
return _HOP_MARKER.match(first_line) is not None
|
|
192
|
-
except OSError:
|
|
193
|
-
return False
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
def has_misplaced_bootstrap_marker(file_path: Path) -> bool:
|
|
197
|
-
"""
|
|
198
|
-
Check if file has a @HOP:bootstrap or @HOP:data marker NOT on the first line.
|
|
177
|
+
bootstrap_dir: Path to bootstrap directory
|
|
178
|
+
model: halfORM Model instance (shared database connection)
|
|
199
179
|
|
|
200
|
-
|
|
201
|
-
|
|
180
|
+
Raises:
|
|
181
|
+
FileExecutionError: If any file execution fails
|
|
202
182
|
|
|
203
|
-
|
|
204
|
-
|
|
183
|
+
Example:
|
|
184
|
+
bootstrap_dir = Path('/path/to/project/bootstrap')
|
|
185
|
+
execute_bootstrap_files(bootstrap_dir, model)
|
|
205
186
|
|
|
206
|
-
|
|
207
|
-
|
|
187
|
+
# Executes files in order:
|
|
188
|
+
# - 01-init-users.sql
|
|
189
|
+
# - 02-seed-config.py
|
|
190
|
+
# - 03-reference-data.sql
|
|
208
191
|
"""
|
|
209
|
-
if
|
|
210
|
-
return
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
192
|
+
if not bootstrap_dir.exists():
|
|
193
|
+
return
|
|
194
|
+
|
|
195
|
+
# Collect all SQL and Python files
|
|
196
|
+
files = []
|
|
197
|
+
for file_path in bootstrap_dir.iterdir():
|
|
198
|
+
if file_path.is_file() and file_path.suffix in ('.sql', '.py'):
|
|
199
|
+
files.append(file_path)
|
|
200
|
+
|
|
201
|
+
if not files:
|
|
202
|
+
return
|
|
203
|
+
|
|
204
|
+
# Sort alphabetically by filename
|
|
205
|
+
files.sort(key=lambda f: f.name)
|
|
206
|
+
|
|
207
|
+
# Execute each file
|
|
208
|
+
for file_path in files:
|
|
209
|
+
try:
|
|
210
|
+
if file_path.suffix == '.sql':
|
|
211
|
+
execute_sql_file(file_path, model)
|
|
212
|
+
elif file_path.suffix == '.py':
|
|
213
|
+
execute_python_bootstrap(file_path, model, cwd=bootstrap_dir)
|
|
214
|
+
except FileExecutionError:
|
|
215
|
+
# Re-raise FileExecutionError as-is (already has good error message)
|
|
216
|
+
raise
|
|
217
|
+
except Exception as e:
|
|
218
|
+
# Wrap unexpected errors
|
|
219
|
+
raise FileExecutionError(
|
|
220
|
+
f"Failed to execute bootstrap file {file_path.name}: {e}"
|
|
221
|
+
) from e
|
|
@@ -560,6 +560,49 @@ class HGit:
|
|
|
560
560
|
finally:
|
|
561
561
|
marker.unlink(missing_ok=True)
|
|
562
562
|
|
|
563
|
+
def setup_production_branches(self) -> None:
|
|
564
|
+
"""
|
|
565
|
+
Create local tracking branches for all remote ho-prod-* branches.
|
|
566
|
+
|
|
567
|
+
This ensures production servers have local access to all versioned
|
|
568
|
+
production branches (ho-prod, ho-prod-X.Y.Z) for rollback support.
|
|
569
|
+
|
|
570
|
+
Workflow:
|
|
571
|
+
1. List all remote branches matching origin/ho-prod*
|
|
572
|
+
2. For each remote branch, create local tracking branch if missing
|
|
573
|
+
3. Skip if local branch already exists
|
|
574
|
+
|
|
575
|
+
Used in:
|
|
576
|
+
- Production clone: after initial checkout
|
|
577
|
+
- Production upgrade: after fetch to get new releases
|
|
578
|
+
|
|
579
|
+
Examples:
|
|
580
|
+
# After clone or fetch
|
|
581
|
+
hgit.setup_production_branches()
|
|
582
|
+
# → Creates ho-prod-0.1.0, ho-prod-0.1.1, etc. from origin
|
|
583
|
+
"""
|
|
584
|
+
# Get all remote branches matching ho-prod*
|
|
585
|
+
remote_branches = []
|
|
586
|
+
for ref in self.__git_repo.remote('origin').refs:
|
|
587
|
+
branch_name = ref.name.replace('origin/', '')
|
|
588
|
+
if branch_name.startswith('ho-prod'):
|
|
589
|
+
remote_branches.append(branch_name)
|
|
590
|
+
|
|
591
|
+
# Create local tracking branches for each remote ho-prod* branch
|
|
592
|
+
for branch_name in remote_branches:
|
|
593
|
+
try:
|
|
594
|
+
# Check if local branch already exists
|
|
595
|
+
if branch_name in [b.name for b in self.__git_repo.branches]:
|
|
596
|
+
continue
|
|
597
|
+
|
|
598
|
+
# Create local tracking branch
|
|
599
|
+
remote_ref = self.__git_repo.remote('origin').refs[branch_name]
|
|
600
|
+
self.__git_repo.create_head(branch_name, remote_ref)
|
|
601
|
+
|
|
602
|
+
except Exception:
|
|
603
|
+
# Skip branches that can't be created (shouldn't happen)
|
|
604
|
+
pass
|
|
605
|
+
|
|
563
606
|
def delete_local_branch(self, branch_name: str) -> None:
|
|
564
607
|
"""
|
|
565
608
|
Delete local branch.
|
|
@@ -543,6 +543,7 @@ class MigrationManager:
|
|
|
543
543
|
else:
|
|
544
544
|
repo.restore_database_from_schema(skip_bootstrap=True)
|
|
545
545
|
else:
|
|
546
|
+
#XXX EST-CE QUE POUR ho-patch/* on ne devrait pas utiliser from_release_schema ?
|
|
546
547
|
# ho-prod and ho-patch/*: use production schema
|
|
547
548
|
repo.restore_database_from_schema(skip_bootstrap=True)
|
|
548
549
|
|