half-orm-dev 1.0.0a7__tar.gz → 1.0.0a9__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.0a7/half_orm_dev.egg-info → half_orm_dev-1.0.0a9}/PKG-INFO +1 -1
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/cli/commands/migrate.py +4 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/migration_manager.py +86 -27
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/release_manager.py +53 -6
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/repo.py +24 -43
- half_orm_dev-1.0.0a9/half_orm_dev/version.txt +1 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9/half_orm_dev.egg-info}/PKG-INFO +1 -1
- half_orm_dev-1.0.0a7/half_orm_dev/version.txt +0 -1
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/AUTHORS +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/LICENSE +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/README.md +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/__init__.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/bootstrap_manager.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/cli/__init__.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/cli/commands/__init__.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/cli/commands/apply.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/cli/commands/bootstrap.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/cli/commands/check.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/cli/commands/clone.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/cli/commands/init.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/cli/commands/patch.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/cli/commands/release.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/cli/commands/restore.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/cli/commands/revert_migration.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/cli/commands/set_git_origin.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/cli/commands/sync.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/cli/commands/todo.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/cli/commands/undo.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/cli/commands/update.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/cli/commands/upgrade.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/cli/main.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/cli_extension.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/database.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/decorators.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/file_executor.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/hgit.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/migrations/0/17/1/00_move_to_hop.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/migrations/0/17/1/01_txt_to_toml.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/migrations/0/17/4/00_toml_dict_format.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/migrations/0/17/4/01_add_bootstrap_table.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/migrations/0/17/4/02_move_patches_to_subdirs.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/migrations/0/17/5/01_update_pyproject_dependency.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/migrations/0/18/0/00_add_async_support.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/migrations/0/18/0/01_update_default_tests.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/migrations/hop/BREAKING_CHANGES-1.0.0.md +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/modules.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/patch_manager.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/patch_validator.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/patches/0/1/0/00_half_orm_meta.database.sql +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/patches/0/1/0/01_alter_half_orm_meta.hop_release.sql +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/patches/0/1/0/02_half_orm_meta.view.hop_penultimate_release.sql +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/patches/log +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/patches/sql/half_orm_meta.sql +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/release_file.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/scripts/repair-metadata.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/templates/.gitignore +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/templates/MANIFEST.in +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/templates/README +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/templates/conftest_template +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/templates/git-hooks/pre-commit +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/templates/git-hooks/prepare-commit-msg +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/templates/init_module_template +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/templates/module_stub_template +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/templates/module_template_1 +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/templates/module_template_2 +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/templates/module_template_3 +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/templates/pyproject.toml +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/templates/relation_test +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/templates/sql_adapter +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/templates/warning +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/utils.py +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev.egg-info/SOURCES.txt +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev.egg-info/dependency_links.txt +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev.egg-info/entry_points.txt +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev.egg-info/requires.txt +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev.egg-info/top_level.txt +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/pyproject.toml +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/setup.cfg +0 -0
- {half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/setup.py +0 -0
|
@@ -134,6 +134,10 @@ def migrate(verbose: bool) -> None:
|
|
|
134
134
|
click.echo(f" • {error}")
|
|
135
135
|
|
|
136
136
|
click.echo(f"\n✓ Synced .hop/ to active branches")
|
|
137
|
+
|
|
138
|
+
deleted = result.get('orphaned_staged_deleted', [])
|
|
139
|
+
if deleted:
|
|
140
|
+
click.echo(f"✓ Deleted {len(deleted)} orphaned ho-staged branch(es)")
|
|
137
141
|
else:
|
|
138
142
|
click.echo(f"✓ {utils.Color.green('Repository is up to date')}")
|
|
139
143
|
|
|
@@ -313,6 +313,9 @@ class MigrationManager:
|
|
|
313
313
|
f"Continuing with migration attempt."
|
|
314
314
|
)
|
|
315
315
|
|
|
316
|
+
# Ensure all active branches are in sync with origin before touching anything
|
|
317
|
+
self._ensure_active_branches_synced()
|
|
318
|
+
|
|
316
319
|
# Get pending migrations
|
|
317
320
|
pending = self.get_pending_migrations(current_version, target_version)
|
|
318
321
|
|
|
@@ -452,6 +455,72 @@ class MigrationManager:
|
|
|
452
455
|
except Exception:
|
|
453
456
|
pass # remote tag may already be gone
|
|
454
457
|
|
|
458
|
+
def _ensure_active_branches_synced(self) -> None:
|
|
459
|
+
"""Verify all active branches are in sync with origin before migration.
|
|
460
|
+
|
|
461
|
+
Branches that are behind are fast-forwarded automatically (no local commits
|
|
462
|
+
at risk). Branches that are ahead or diverged block the migration — the
|
|
463
|
+
developer must push or resolve before proceeding.
|
|
464
|
+
|
|
465
|
+
Raises:
|
|
466
|
+
MigrationManagerError: if any active branch is ahead or diverged.
|
|
467
|
+
"""
|
|
468
|
+
repo = self._repo
|
|
469
|
+
git_repo = repo.hgit._HGit__git_repo
|
|
470
|
+
current_branch = git_repo.active_branch.name
|
|
471
|
+
|
|
472
|
+
try:
|
|
473
|
+
branches_status = repo.hgit.get_active_branches_status()
|
|
474
|
+
except Exception:
|
|
475
|
+
return # can't determine status, proceed cautiously
|
|
476
|
+
|
|
477
|
+
patch_branches = [b['name'] for b in branches_status.get('patch_branches', [])]
|
|
478
|
+
release_branches = [b['name'] for b in branches_status.get('release_branches', [])]
|
|
479
|
+
# ho-staged/* branches are frozen after merge — excluded from sync checks
|
|
480
|
+
active_branches = release_branches + patch_branches
|
|
481
|
+
|
|
482
|
+
blocked = []
|
|
483
|
+
for branch in active_branches:
|
|
484
|
+
try:
|
|
485
|
+
synced, status = repo.hgit.is_branch_synced(branch)
|
|
486
|
+
if synced:
|
|
487
|
+
continue
|
|
488
|
+
if status == 'behind':
|
|
489
|
+
# Fast-forward: no local commits at risk
|
|
490
|
+
repo.hgit.checkout(branch)
|
|
491
|
+
git_repo.git.merge('--ff-only', f'origin/{branch}')
|
|
492
|
+
elif status in ('ahead', 'diverged'):
|
|
493
|
+
blocked.append((branch, status))
|
|
494
|
+
except Exception:
|
|
495
|
+
pass # branch may not exist locally, skip
|
|
496
|
+
|
|
497
|
+
# Return to original branch
|
|
498
|
+
try:
|
|
499
|
+
repo.hgit.checkout(current_branch)
|
|
500
|
+
except Exception:
|
|
501
|
+
pass
|
|
502
|
+
|
|
503
|
+
if blocked:
|
|
504
|
+
ahead = [(b, s) for b, s in blocked if s == 'ahead']
|
|
505
|
+
diverged = [(b, s) for b, s in blocked if s == 'diverged']
|
|
506
|
+
parts = []
|
|
507
|
+
if ahead:
|
|
508
|
+
branch_list = ', '.join(b for b, _ in ahead)
|
|
509
|
+
parts.append(
|
|
510
|
+
f" Branches ahead of origin (unpushed commits) — push first:\n"
|
|
511
|
+
+ '\n'.join(f" git push origin {b}" for b, _ in ahead)
|
|
512
|
+
)
|
|
513
|
+
if diverged:
|
|
514
|
+
parts.append(
|
|
515
|
+
f" Branches diverged from origin (local and remote have diverged) "
|
|
516
|
+
f"— rebase or merge to resolve:\n"
|
|
517
|
+
+ '\n'.join(f" {b}" for b, _ in diverged)
|
|
518
|
+
)
|
|
519
|
+
raise MigrationManagerError(
|
|
520
|
+
f"Migration blocked: active branches are not in sync with origin.\n"
|
|
521
|
+
+ '\n'.join(parts)
|
|
522
|
+
)
|
|
523
|
+
|
|
455
524
|
def _regenerate_modules_after_migration(
|
|
456
525
|
self, from_version: str, to_version: str
|
|
457
526
|
) -> None:
|
|
@@ -468,50 +537,40 @@ class MigrationManager:
|
|
|
468
537
|
package_name = repo.name
|
|
469
538
|
package_dir = str(Path(repo.base_dir) / package_name)
|
|
470
539
|
|
|
471
|
-
# Regenerate all modules (idempotent thanks to global reset in generate())
|
|
472
|
-
_modules.generate(repo)
|
|
473
|
-
|
|
474
|
-
# Stage the entire package directory
|
|
475
|
-
repo.hgit.add(package_dir)
|
|
476
|
-
|
|
477
|
-
# Nothing changed — nothing to do
|
|
478
|
-
staged = git_repo.git.diff('--cached', '--name-only')
|
|
479
|
-
if not staged.strip():
|
|
480
|
-
return
|
|
481
|
-
|
|
482
|
-
# Commit on ho-prod
|
|
483
540
|
commit_msg = (
|
|
484
541
|
f"[HOP] Regenerate modules (migration {from_version} → {to_version})"
|
|
485
542
|
)
|
|
486
|
-
repo.hgit.commit('-m', commit_msg)
|
|
487
|
-
repo.hgit.push_branch('ho-prod')
|
|
488
543
|
|
|
489
|
-
#
|
|
544
|
+
# Collect active branches before moving around
|
|
490
545
|
try:
|
|
491
546
|
branches_status = repo.hgit.get_active_branches_status()
|
|
492
547
|
except Exception:
|
|
493
|
-
|
|
548
|
+
branches_status = {}
|
|
494
549
|
|
|
495
550
|
patch_branches = [b['name'] for b in branches_status.get('patch_branches', [])]
|
|
496
551
|
release_branches = [b['name'] for b in branches_status.get('release_branches', [])]
|
|
497
|
-
|
|
498
|
-
|
|
552
|
+
# ho-staged/* branches are frozen after merge — excluded from module regeneration
|
|
553
|
+
all_branches = ['ho-prod'] + release_branches + patch_branches
|
|
499
554
|
|
|
500
|
-
|
|
501
|
-
f"[HOP] Sync modules from ho-prod (migration {from_version} → {to_version})"
|
|
502
|
-
)
|
|
503
|
-
for branch in target_branches:
|
|
555
|
+
for branch in all_branches:
|
|
504
556
|
try:
|
|
505
557
|
repo.hgit.checkout(branch)
|
|
506
|
-
|
|
558
|
+
# generate() reads existing files and preserves developer code sections
|
|
559
|
+
_modules.generate(repo)
|
|
507
560
|
repo.hgit.add(package_dir)
|
|
508
|
-
if not git_repo.git.
|
|
561
|
+
if not git_repo.git.diff('--cached', '--name-only').strip():
|
|
509
562
|
continue
|
|
510
|
-
repo.hgit.commit('-m',
|
|
511
|
-
|
|
563
|
+
repo.hgit.commit('-m', commit_msg)
|
|
564
|
+
try:
|
|
565
|
+
repo.hgit.push_branch(branch)
|
|
566
|
+
except Exception as push_err:
|
|
567
|
+
sys.stderr.write(
|
|
568
|
+
f"Warning: could not push {branch} after module regeneration "
|
|
569
|
+
f"(diverged branch?): {push_err}\n"
|
|
570
|
+
)
|
|
512
571
|
except Exception as e:
|
|
513
572
|
sys.stderr.write(
|
|
514
|
-
f"Warning: could not
|
|
573
|
+
f"Warning: could not regenerate modules on {branch}: {e}\n"
|
|
515
574
|
)
|
|
516
575
|
|
|
517
576
|
repo.hgit.checkout('ho-prod')
|
|
@@ -2768,13 +2768,17 @@ class ReleaseManager:
|
|
|
2768
2768
|
print(f"Warning: Failed to delete release branch {release_branch}: {e}", file=sys.stderr)
|
|
2769
2769
|
|
|
2770
2770
|
# Delete ho-staged/X branches for all patches that were in this release.
|
|
2771
|
-
#
|
|
2772
|
-
#
|
|
2771
|
+
# At this point the X.Y.Z-patches.toml is already gone (replaced by
|
|
2772
|
+
# X.Y.Z.txt during production promotion), so we read the .txt file.
|
|
2773
2773
|
version = release_branch.replace('ho-release/', '')
|
|
2774
|
-
|
|
2775
|
-
if
|
|
2776
|
-
|
|
2777
|
-
|
|
2774
|
+
prod_txt = Path(self._releases_dir) / f"{version}.txt"
|
|
2775
|
+
if prod_txt.exists():
|
|
2776
|
+
patch_ids = [
|
|
2777
|
+
line.strip()
|
|
2778
|
+
for line in prod_txt.read_text(encoding='utf-8').splitlines()
|
|
2779
|
+
if line.strip()
|
|
2780
|
+
]
|
|
2781
|
+
for patch_id in patch_ids:
|
|
2778
2782
|
staged_branch = f"ho-staged/{patch_id}"
|
|
2779
2783
|
try:
|
|
2780
2784
|
if self._repo.hgit.branch_exists(staged_branch):
|
|
@@ -2786,6 +2790,49 @@ class ReleaseManager:
|
|
|
2786
2790
|
|
|
2787
2791
|
return deleted_branches
|
|
2788
2792
|
|
|
2793
|
+
def cleanup_orphaned_staged_branches(self) -> list:
|
|
2794
|
+
"""Delete every ho-staged/* branch whose patch ID is in any .txt release file.
|
|
2795
|
+
|
|
2796
|
+
A ho-staged/* branch is orphaned when its release has been promoted to
|
|
2797
|
+
production (the patch ID appears in a X.Y.Z.txt file) but the branch
|
|
2798
|
+
was never cleaned up — e.g. due to an interrupted promotion.
|
|
2799
|
+
|
|
2800
|
+
Returns:
|
|
2801
|
+
List of deleted branch names.
|
|
2802
|
+
"""
|
|
2803
|
+
releases_dir = Path(self._releases_dir)
|
|
2804
|
+
git_repo = self._repo.hgit._HGit__git_repo
|
|
2805
|
+
|
|
2806
|
+
# Collect all patch IDs that are in production (.txt files)
|
|
2807
|
+
prod_patch_ids: set = set()
|
|
2808
|
+
for txt_file in releases_dir.glob("*.txt"):
|
|
2809
|
+
for line in txt_file.read_text(encoding='utf-8').splitlines():
|
|
2810
|
+
patch_id = line.strip()
|
|
2811
|
+
if patch_id:
|
|
2812
|
+
prod_patch_ids.add(patch_id)
|
|
2813
|
+
|
|
2814
|
+
if not prod_patch_ids:
|
|
2815
|
+
return []
|
|
2816
|
+
|
|
2817
|
+
deleted = []
|
|
2818
|
+
for branch in list(git_repo.branches):
|
|
2819
|
+
if not branch.name.startswith('ho-staged/'):
|
|
2820
|
+
continue
|
|
2821
|
+
patch_id = branch.name[len('ho-staged/'):]
|
|
2822
|
+
if patch_id not in prod_patch_ids:
|
|
2823
|
+
continue
|
|
2824
|
+
try:
|
|
2825
|
+
self._repo.hgit.delete_local_branch(branch.name)
|
|
2826
|
+
self._repo.hgit.delete_remote_branch(branch.name)
|
|
2827
|
+
deleted.append(branch.name)
|
|
2828
|
+
except Exception as e:
|
|
2829
|
+
print(
|
|
2830
|
+
f"Warning: Failed to delete orphaned {branch.name}: {e}",
|
|
2831
|
+
file=sys.stderr,
|
|
2832
|
+
)
|
|
2833
|
+
|
|
2834
|
+
return deleted
|
|
2835
|
+
|
|
2789
2836
|
@with_dynamic_branch_lock(lambda self: "ho-prod")
|
|
2790
2837
|
def promote_to_rc(self) -> dict:
|
|
2791
2838
|
"""
|
|
@@ -544,6 +544,14 @@ class Repo:
|
|
|
544
544
|
result['migration_run'] = True
|
|
545
545
|
result['errors'] = migration_result.get('errors', [])
|
|
546
546
|
|
|
547
|
+
# Clean up orphaned ho-staged/* branches (patch IDs in .txt = already in production)
|
|
548
|
+
if hasattr(self, 'release_manager'):
|
|
549
|
+
try:
|
|
550
|
+
deleted = self.release_manager.cleanup_orphaned_staged_branches()
|
|
551
|
+
result['orphaned_staged_deleted'] = deleted
|
|
552
|
+
except Exception:
|
|
553
|
+
result['orphaned_staged_deleted'] = []
|
|
554
|
+
|
|
547
555
|
# Log success if not silent
|
|
548
556
|
if not silent:
|
|
549
557
|
if migration_result.get('migrations_applied'):
|
|
@@ -638,9 +646,8 @@ class Repo:
|
|
|
638
646
|
patch_branches = [b['name'] for b in branches_status.get('patch_branches', [])]
|
|
639
647
|
release_branches = [b['name'] for b in branches_status.get('release_branches', [])]
|
|
640
648
|
|
|
641
|
-
#
|
|
642
|
-
|
|
643
|
-
all_branches = ['ho-prod'] + release_branches + patch_branches + staged_branches
|
|
649
|
+
# ho-staged/* branches are frozen after merge — excluded from sync
|
|
650
|
+
all_branches = ['ho-prod'] + release_branches + patch_branches
|
|
644
651
|
|
|
645
652
|
# Filter release branches to avoid syncing to future versions
|
|
646
653
|
# Extract version from source branch if it's a release branch
|
|
@@ -690,18 +697,10 @@ class Repo:
|
|
|
690
697
|
remote_ref = f"origin/{branch}"
|
|
691
698
|
try:
|
|
692
699
|
synced, status = self.hgit.is_branch_synced(branch)
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
file=sys.stderr
|
|
698
|
-
)
|
|
699
|
-
# Only reset when the remote is ahead of local ("behind") or
|
|
700
|
-
# branches have diverged. Never reset an "ahead" branch —
|
|
701
|
-
# that would orphan local commits that have not been pushed
|
|
702
|
-
# yet (e.g. the "Create patch directory" commit from
|
|
703
|
-
# `hop patch create` before the first push).
|
|
704
|
-
if not synced and status in ("behind", "diverged"):
|
|
700
|
+
# Only fast-forward when origin is strictly ahead (no local commits
|
|
701
|
+
# at risk). Never reset on diverged branches — that would destroy
|
|
702
|
+
# unmerged local work.
|
|
703
|
+
if not synced and status == "behind":
|
|
705
704
|
self.hgit._HGit__git_repo.git.reset('--hard', remote_ref)
|
|
706
705
|
except GitCommandError:
|
|
707
706
|
# Remote branch may not exist yet, continue without reset
|
|
@@ -1528,28 +1527,8 @@ class Repo:
|
|
|
1528
1527
|
result = repo.check_and_update(force_check=True)
|
|
1529
1528
|
"""
|
|
1530
1529
|
|
|
1531
|
-
# Check cache (only if not forced and silent mode)
|
|
1532
|
-
cache_file = Path(self.__base_dir) / '.git' / '.half_orm_check_cache'
|
|
1533
|
-
cache_hit = False
|
|
1534
1530
|
|
|
1535
|
-
|
|
1536
|
-
try:
|
|
1537
|
-
last_check = float(cache_file.read_text().strip())
|
|
1538
|
-
# Check once per day (86400 seconds)
|
|
1539
|
-
if time.time() - last_check < 86400:
|
|
1540
|
-
cache_hit = True
|
|
1541
|
-
return {
|
|
1542
|
-
'hooks': {'installed': False, 'action': 'skipped'},
|
|
1543
|
-
'branches': {},
|
|
1544
|
-
'cache_hit': True
|
|
1545
|
-
}
|
|
1546
|
-
except (ValueError, IOError):
|
|
1547
|
-
pass
|
|
1548
|
-
|
|
1549
|
-
# Perform checks
|
|
1550
|
-
result = {
|
|
1551
|
-
'cache_hit': False
|
|
1552
|
-
}
|
|
1531
|
+
result = {}
|
|
1553
1532
|
|
|
1554
1533
|
# 0. Update ho-prod from remote and fetch all branches
|
|
1555
1534
|
# This ensures we have the latest hop_version and branch status
|
|
@@ -1724,19 +1703,21 @@ class Repo:
|
|
|
1724
1703
|
|
|
1725
1704
|
result['stale_branches'] = stale_branches_result
|
|
1726
1705
|
|
|
1706
|
+
# 3b. Delete orphaned ho-staged/* branches (patch in a .txt = already in production)
|
|
1707
|
+
orphaned_staged_deleted = []
|
|
1708
|
+
if not dry_run and hasattr(self, 'release_manager'):
|
|
1709
|
+
try:
|
|
1710
|
+
orphaned_staged_deleted = self.release_manager.cleanup_orphaned_staged_branches()
|
|
1711
|
+
except Exception:
|
|
1712
|
+
pass # Best effort
|
|
1713
|
+
result['orphaned_staged_deleted'] = orphaned_staged_deleted
|
|
1714
|
+
|
|
1727
1715
|
# 4. Check version (only for explicit checks, not silent)
|
|
1728
1716
|
if not silent:
|
|
1729
1717
|
result['version'] = self._check_version_update()
|
|
1730
1718
|
else:
|
|
1731
1719
|
result['version'] = None
|
|
1732
1720
|
|
|
1733
|
-
# Update cache
|
|
1734
|
-
if not dry_run and silent:
|
|
1735
|
-
try:
|
|
1736
|
-
cache_file.write_text(str(time.time()))
|
|
1737
|
-
except IOError:
|
|
1738
|
-
pass # Best effort
|
|
1739
|
-
|
|
1740
1721
|
return result
|
|
1741
1722
|
|
|
1742
1723
|
def _validate_package_name(self, package_name):
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.0.0-a9
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
1.0.0-a7
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/migrations/0/17/1/00_move_to_hop.py
RENAMED
|
File without changes
|
{half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/migrations/0/17/1/01_txt_to_toml.py
RENAMED
|
File without changes
|
{half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/migrations/0/17/4/00_toml_dict_format.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/migrations/0/18/0/00_add_async_support.py
RENAMED
|
File without changes
|
|
File without changes
|
{half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/migrations/hop/BREAKING_CHANGES-1.0.0.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{half_orm_dev-1.0.0a7 → half_orm_dev-1.0.0a9}/half_orm_dev/templates/git-hooks/prepare-commit-msg
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|