half-orm-dev 0.17.3a4__tar.gz → 0.17.3a6__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.3a4/half_orm_dev.egg-info → half_orm_dev-0.17.3a6}/PKG-INFO +1 -1
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/cli/commands/release.py +103 -24
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/database.py +70 -5
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/patch_manager.py +1 -1
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/release_manager.py +352 -56
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/repo.py +94 -25
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/templates/README +36 -2
- half_orm_dev-0.17.3a6/half_orm_dev/version.txt +1 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6/half_orm_dev.egg-info}/PKG-INFO +1 -1
- half_orm_dev-0.17.3a4/half_orm_dev/version.txt +0 -1
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/AUTHORS +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/LICENSE +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/README.md +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/__init__.py +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/cli/__init__.py +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/cli/commands/__init__.py +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/cli/commands/apply.py +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/cli/commands/check.py +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/cli/commands/clone.py +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/cli/commands/init.py +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/cli/commands/migrate.py +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/cli/commands/patch.py +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/cli/commands/restore.py +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/cli/commands/sync.py +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/cli/commands/todo.py +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/cli/commands/undo.py +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/cli/commands/update.py +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/cli/commands/upgrade.py +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/cli/main.py +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/cli_extension.py +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/decorators.py +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/hgit.py +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/migration_manager.py +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/migrations/0/17/1/00_move_to_hop.py +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/migrations/0/17/1/01_txt_to_toml.py +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/modules.py +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/patch_validator.py +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/patches/0/1/0/00_half_orm_meta.database.sql +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/patches/0/1/0/01_alter_half_orm_meta.hop_release.sql +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/patches/0/1/0/02_half_orm_meta.view.hop_penultimate_release.sql +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/patches/log +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/patches/sql/half_orm_meta.sql +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/release_file.py +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/templates/.gitignore +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/templates/MANIFEST.in +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/templates/Pipfile +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/templates/conftest_template +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/templates/git-hooks/pre-commit +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/templates/git-hooks/prepare-commit-msg +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/templates/init_module_template +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/templates/module_template_1 +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/templates/module_template_2 +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/templates/module_template_3 +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/templates/pyproject.toml +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/templates/relation_test +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/templates/sql_adapter +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/templates/warning +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev/utils.py +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev.egg-info/SOURCES.txt +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev.egg-info/dependency_links.txt +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev.egg-info/requires.txt +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/half_orm_dev.egg-info/top_level.txt +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/pyproject.toml +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/setup.cfg +0 -0
- {half_orm_dev-0.17.3a4 → half_orm_dev-0.17.3a6}/setup.py +0 -0
|
@@ -369,39 +369,118 @@ def release_hotfix(version: Optional[str] = None) -> None:
|
|
|
369
369
|
|
|
370
370
|
|
|
371
371
|
@release.command('apply')
|
|
372
|
-
@click.
|
|
373
|
-
|
|
372
|
+
@click.option(
|
|
373
|
+
'--skip-tests',
|
|
374
|
+
is_flag=True,
|
|
375
|
+
help='Skip running pytest after applying patches'
|
|
376
|
+
)
|
|
377
|
+
def release_apply(skip_tests: bool) -> None:
|
|
374
378
|
"""
|
|
375
|
-
|
|
379
|
+
Apply all patches for integration testing.
|
|
380
|
+
|
|
381
|
+
Restores the database from production schema and applies ALL patches
|
|
382
|
+
(candidates + staged) to test the complete release integration.
|
|
383
|
+
Optionally runs pytest to validate the release.
|
|
376
384
|
|
|
377
|
-
|
|
378
|
-
|
|
385
|
+
Unlike 'patch apply' which only applies validated (staged) patches,
|
|
386
|
+
this command applies ALL patches including candidates that haven't
|
|
387
|
+
passed individual validation yet. This enables testing the complete
|
|
388
|
+
release before promotion.
|
|
379
389
|
|
|
380
390
|
\b
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
391
|
+
Workflow:
|
|
392
|
+
1. Validate on release branch (ho-release/X.Y.Z)
|
|
393
|
+
2. Restore database from model/schema.sql
|
|
394
|
+
3. Apply all RC patches (if any)
|
|
395
|
+
4. Apply ALL TOML patches (candidates + staged)
|
|
396
|
+
5. Generate Python code
|
|
397
|
+
6. Run pytest (unless --skip-tests)
|
|
398
|
+
|
|
399
|
+
\b
|
|
400
|
+
Requirements:
|
|
401
|
+
- Must be on ho-release/X.Y.Z branch
|
|
402
|
+
- Development release must exist
|
|
384
403
|
|
|
385
404
|
\b
|
|
386
405
|
Examples:
|
|
387
|
-
|
|
406
|
+
Apply all patches and run tests:
|
|
388
407
|
$ half_orm dev release apply
|
|
389
408
|
|
|
390
|
-
|
|
391
|
-
$ half_orm dev release apply
|
|
392
|
-
|
|
393
|
-
Test stage release:
|
|
394
|
-
$ half_orm dev release apply 1.3.5-stage
|
|
409
|
+
Apply patches without running tests:
|
|
410
|
+
$ half_orm dev release apply --skip-tests
|
|
395
411
|
|
|
396
412
|
\b
|
|
397
|
-
|
|
413
|
+
Output:
|
|
414
|
+
✓ Applied 5 patches for version 1.3.6
|
|
415
|
+
✓ Tests passed (42 tests)
|
|
416
|
+
|
|
417
|
+
Or on failure:
|
|
418
|
+
✗ Tests failed
|
|
419
|
+
<test output>
|
|
398
420
|
"""
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
421
|
+
try:
|
|
422
|
+
# Get repository instance
|
|
423
|
+
repo = Repo()
|
|
424
|
+
release_mgr = repo.release_manager
|
|
425
|
+
|
|
426
|
+
# Display context
|
|
427
|
+
click.echo("🔄 Applying all release patches for integration testing...")
|
|
428
|
+
click.echo()
|
|
429
|
+
|
|
430
|
+
# Apply release
|
|
431
|
+
result = release_mgr.apply_release(run_tests=not skip_tests)
|
|
432
|
+
|
|
433
|
+
# Display results
|
|
434
|
+
version = result['version']
|
|
435
|
+
patches = result['patches_applied']
|
|
436
|
+
candidates = result.get('candidates_merged', [])
|
|
437
|
+
patch_count = len(patches)
|
|
438
|
+
|
|
439
|
+
click.echo(f"✓ {utils.Color.green('Patches applied successfully!')}")
|
|
440
|
+
click.echo()
|
|
441
|
+
click.echo(f" Version: {utils.Color.bold(version)}")
|
|
442
|
+
click.echo(f" Patches: {utils.Color.bold(str(patch_count))}")
|
|
443
|
+
if candidates:
|
|
444
|
+
click.echo(f" Candidates merged: {utils.Color.bold(str(len(candidates)))}")
|
|
445
|
+
click.echo()
|
|
446
|
+
|
|
447
|
+
# Show candidates merged (simulated merges)
|
|
448
|
+
if candidates:
|
|
449
|
+
click.echo(" Candidate branches merged (simulated):")
|
|
450
|
+
for patch_id in candidates:
|
|
451
|
+
click.echo(f" • ho-patch/{patch_id}")
|
|
452
|
+
click.echo()
|
|
453
|
+
|
|
454
|
+
# Show patches applied
|
|
455
|
+
if patches:
|
|
456
|
+
click.echo(" Applied patches (SQL):")
|
|
457
|
+
for patch_id in patches:
|
|
458
|
+
click.echo(f" • {patch_id}")
|
|
459
|
+
click.echo()
|
|
460
|
+
|
|
461
|
+
# Show test results
|
|
462
|
+
if skip_tests:
|
|
463
|
+
click.echo(f"⚠️ {utils.Color.bold('Tests skipped')} (--skip-tests flag)")
|
|
464
|
+
elif result['tests_passed'] is None:
|
|
465
|
+
click.echo(f"⚠️ {utils.Color.bold('Tests not run')} (pytest not found)")
|
|
466
|
+
elif result['tests_passed']:
|
|
467
|
+
click.echo(f"✓ {utils.Color.green('Tests passed!')}")
|
|
468
|
+
else:
|
|
469
|
+
click.echo(f"✗ {utils.Color.red('Tests failed!')}")
|
|
470
|
+
click.echo()
|
|
471
|
+
click.echo("Test output:")
|
|
472
|
+
click.echo(result['test_output'])
|
|
473
|
+
sys.exit(1)
|
|
474
|
+
|
|
475
|
+
click.echo()
|
|
476
|
+
click.echo("📝 Next steps:")
|
|
477
|
+
if result['tests_passed'] or result['tests_passed'] is None:
|
|
478
|
+
click.echo(f" • Promote to RC: {utils.Color.bold('half_orm dev release promote rc')}")
|
|
479
|
+
else:
|
|
480
|
+
click.echo(f" • Fix failing tests")
|
|
481
|
+
click.echo(f" • Re-run: {utils.Color.bold('half_orm dev release apply')}")
|
|
482
|
+
|
|
483
|
+
except ReleaseManagerError as e:
|
|
484
|
+
click.echo(f"❌ {utils.Color.red('Release apply failed:')}", err=True)
|
|
485
|
+
click.echo(f" {str(e)}", err=True)
|
|
486
|
+
sys.exit(1)
|
|
@@ -93,6 +93,10 @@ class Database:
|
|
|
93
93
|
if get_release and self.__repo.devel:
|
|
94
94
|
self.__last_release = self.last_release
|
|
95
95
|
|
|
96
|
+
@property
|
|
97
|
+
def name(self):
|
|
98
|
+
return self.__name
|
|
99
|
+
|
|
96
100
|
@property
|
|
97
101
|
def last_release(self):
|
|
98
102
|
"Returns the last release"
|
|
@@ -177,10 +181,22 @@ class Database:
|
|
|
177
181
|
*command_args
|
|
178
182
|
)
|
|
179
183
|
|
|
180
|
-
def register_release(self, major, minor, patch, changelog=None):
|
|
181
|
-
"
|
|
184
|
+
def register_release(self, major, minor, patch, pre_release='', pre_release_num='', changelog=None):
|
|
185
|
+
"""
|
|
186
|
+
Register the release into half_orm_meta.hop_release.
|
|
187
|
+
|
|
188
|
+
Args:
|
|
189
|
+
major: Major version number
|
|
190
|
+
minor: Minor version number
|
|
191
|
+
patch: Patch version number
|
|
192
|
+
pre_release: Pre-release type ('alpha', 'beta', 'rc', or '' for production)
|
|
193
|
+
pre_release_num: Pre-release number (e.g., '1' for rc1)
|
|
194
|
+
changelog: Optional changelog text
|
|
195
|
+
"""
|
|
182
196
|
return self.__model.get_relation_class('half_orm_meta.hop_release')(
|
|
183
|
-
major=major, minor=minor, patch=patch,
|
|
197
|
+
major=major, minor=minor, patch=patch,
|
|
198
|
+
pre_release=pre_release, pre_release_num=pre_release_num,
|
|
199
|
+
changelog=changelog
|
|
184
200
|
).ho_insert()
|
|
185
201
|
|
|
186
202
|
def _generate_schema_sql(self, version: str, model_dir: Path) -> Path:
|
|
@@ -271,6 +287,7 @@ class Database:
|
|
|
271
287
|
|
|
272
288
|
# Construct versioned schema file path
|
|
273
289
|
schema_file = model_dir / f"schema-{version}.sql"
|
|
290
|
+
temp_schema_file = model_dir / f".schema-{version}.sql.tmp"
|
|
274
291
|
|
|
275
292
|
# Generate schema dump using pg_dump
|
|
276
293
|
try:
|
|
@@ -278,16 +295,45 @@ class Database:
|
|
|
278
295
|
'pg_dump',
|
|
279
296
|
self.__name,
|
|
280
297
|
'--schema-only',
|
|
298
|
+
'--no-owner',
|
|
281
299
|
'-f',
|
|
282
|
-
str(
|
|
300
|
+
str(temp_schema_file)
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
# Filter out version-specific lines for cross-version compatibility
|
|
304
|
+
content = temp_schema_file.read_text()
|
|
305
|
+
filtered_lines = []
|
|
306
|
+
# SET commands that are version-specific and should be removed
|
|
307
|
+
version_specific_sets = (
|
|
308
|
+
'SET transaction_timeout', # PG17+
|
|
283
309
|
)
|
|
310
|
+
for line in content.split('\n'):
|
|
311
|
+
# Skip \restrict and \unrestrict lines
|
|
312
|
+
if line.startswith('\\restrict') or line.startswith('\\unrestrict'):
|
|
313
|
+
continue
|
|
314
|
+
# Skip "-- Dumped from/by" comments (version-specific)
|
|
315
|
+
if line.startswith('-- Dumped from') or line.startswith('-- Dumped by'):
|
|
316
|
+
continue
|
|
317
|
+
# Skip version-specific SET commands
|
|
318
|
+
if any(line.startswith(s) for s in version_specific_sets):
|
|
319
|
+
continue
|
|
320
|
+
filtered_lines.append(line)
|
|
321
|
+
|
|
322
|
+
schema_file.write_text('\n'.join(filtered_lines))
|
|
284
323
|
except Exception as e:
|
|
285
324
|
raise Exception(f"Failed to generate schema SQL: {e}") from e
|
|
325
|
+
finally:
|
|
326
|
+
# Clean up temporary file
|
|
327
|
+
if temp_schema_file.exists():
|
|
328
|
+
temp_schema_file.unlink()
|
|
286
329
|
|
|
287
330
|
# Generate metadata dump (half_orm_meta data only)
|
|
331
|
+
# Keep only COPY statements to avoid version-specific SET commands
|
|
288
332
|
metadata_file = model_dir / f"metadata-{version}.sql"
|
|
333
|
+
temp_file = model_dir / f".metadata-{version}.sql.tmp"
|
|
289
334
|
|
|
290
335
|
try:
|
|
336
|
+
# Dump to temporary file
|
|
291
337
|
self.execute_pg_command(
|
|
292
338
|
'pg_dump',
|
|
293
339
|
self.__name,
|
|
@@ -296,10 +342,29 @@ class Database:
|
|
|
296
342
|
'--table=half_orm_meta.hop_release',
|
|
297
343
|
'--table=half_orm_meta.hop_release_issue',
|
|
298
344
|
'-f',
|
|
299
|
-
str(
|
|
345
|
+
str(temp_file)
|
|
300
346
|
)
|
|
347
|
+
|
|
348
|
+
# Filter to keep only COPY blocks (COPY ... FROM stdin; ... \.)
|
|
349
|
+
content = temp_file.read_text()
|
|
350
|
+
filtered_lines = []
|
|
351
|
+
in_copy_block = False
|
|
352
|
+
for line in content.split('\n'):
|
|
353
|
+
if line.startswith('COPY '):
|
|
354
|
+
in_copy_block = True
|
|
355
|
+
if in_copy_block:
|
|
356
|
+
filtered_lines.append(line)
|
|
357
|
+
if line == '\\.':
|
|
358
|
+
in_copy_block = False
|
|
359
|
+
filtered_lines.append('') # Empty line between blocks
|
|
360
|
+
|
|
361
|
+
metadata_file.write_text('\n'.join(filtered_lines))
|
|
301
362
|
except Exception as e:
|
|
302
363
|
raise Exception(f"Failed to generate metadata SQL: {e}") from e
|
|
364
|
+
finally:
|
|
365
|
+
# Clean up temporary file
|
|
366
|
+
if temp_file.exists():
|
|
367
|
+
temp_file.unlink()
|
|
303
368
|
|
|
304
369
|
# Create or update symlink
|
|
305
370
|
symlink_path = model_dir / "schema.sql"
|
|
@@ -1916,7 +1916,7 @@ class PatchManager:
|
|
|
1916
1916
|
# This also syncs .hop/ to all active branches automatically via decorator
|
|
1917
1917
|
try:
|
|
1918
1918
|
self._repo.commit_and_sync_to_active_branches(
|
|
1919
|
-
message=f"[HOP] move patch #{patch_id} from candidate to stage %{version}"
|
|
1919
|
+
message=f"[HOP] move patch #{patch_id} from candidate to stage %{version}\nFixes #{patch_id}."
|
|
1920
1920
|
)
|
|
1921
1921
|
except Exception as e:
|
|
1922
1922
|
raise PatchManagerError(f"Failed to commit/push changes: {e}")
|