chore(repo): replace app symlink/submodule with in-repo app directory; enable committing app/Dockerfile and tooling\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
1 parent
a12270ad01
commit
ae2c674b81
25 files changed
+3417
-1
No files matched your search
@@ -0,0 +1,135 @@
|
||||
"""Git worktree + branch management for batch isolation.
|
||||
|
||||
Each batch × track combination gets its own git worktree so that:
|
||||
- Track A and Track B never share filesystem state.
|
||||
- Build directories are fully independent.
|
||||
- Every successful file migration is committed immediately to its branch.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Low-level helper
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _git(args: list[str], cwd: Path | None = None) -> tuple[int, str, str]:
|
||||
result = subprocess.run(
|
||||
["git"] + args,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
cwd=str(cwd) if cwd else None,
|
||||
)
|
||||
return result.returncode, result.stdout.strip(), result.stderr.strip()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Branch / worktree lifecycle
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def branch_name(batch_id: str, track_id: str) -> str:
|
||||
"""Canonical branch name: ``migration/<batch_id>/<track_id>``."""
|
||||
return f"migration/{batch_id}/{track_id}"
|
||||
|
||||
|
||||
def setup_worktree(
|
||||
batch_id: str,
|
||||
track_id: str,
|
||||
repo_root: Path,
|
||||
workspace_root: Path,
|
||||
) -> Path:
|
||||
"""Ensure a git worktree exists for *batch_id* × *track_id*.
|
||||
|
||||
Creates the branch (from HEAD) if it does not yet exist.
|
||||
Returns the worktree path.
|
||||
"""
|
||||
branch = branch_name(batch_id, track_id)
|
||||
worktree_path = workspace_root / batch_id / track_id
|
||||
|
||||
# Create the branch if needed.
|
||||
rc, _, _ = _git(["rev-parse", "--verify", branch], cwd=repo_root)
|
||||
if rc != 0:
|
||||
_git(["branch", branch], cwd=repo_root)
|
||||
|
||||
# Remove stale worktree entry (if the directory was deleted manually).
|
||||
_git(["worktree", "prune"], cwd=repo_root)
|
||||
|
||||
# Check whether the worktree is already registered.
|
||||
_, wt_list, _ = _git(["worktree", "list", "--porcelain"], cwd=repo_root)
|
||||
if str(worktree_path) in wt_list:
|
||||
return worktree_path
|
||||
|
||||
worktree_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
rc, out, err = _git(
|
||||
["worktree", "add", str(worktree_path), branch],
|
||||
cwd=repo_root,
|
||||
)
|
||||
if rc != 0:
|
||||
raise RuntimeError(
|
||||
f"git worktree add failed for {worktree_path}: {err}"
|
||||
)
|
||||
return worktree_path
|
||||
|
||||
|
||||
def teardown_worktree(
|
||||
batch_id: str,
|
||||
track_id: str,
|
||||
repo_root: Path,
|
||||
workspace_root: Path,
|
||||
) -> None:
|
||||
"""Remove the worktree (but keep the branch)."""
|
||||
worktree_path = workspace_root / batch_id / track_id
|
||||
_git(["worktree", "remove", "--force", str(worktree_path)], cwd=repo_root)
|
||||
_git(["worktree", "prune"], cwd=repo_root)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Per-file commit helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def commit_migrated_file(
|
||||
file_path_in_worktree: Path,
|
||||
worktree_path: Path,
|
||||
track_id: str,
|
||||
) -> None:
|
||||
"""Stage and commit a single successfully migrated file."""
|
||||
_git(["add", str(file_path_in_worktree)], cwd=worktree_path)
|
||||
rel = file_path_in_worktree.relative_to(worktree_path)
|
||||
_git(
|
||||
["commit", "-m", f"migrate({track_id}): {rel}"],
|
||||
cwd=worktree_path,
|
||||
)
|
||||
|
||||
|
||||
def commit_generated_tests(
|
||||
tests_dir: Path,
|
||||
worktree_path: Path,
|
||||
track_id: str,
|
||||
test_prefix: str,
|
||||
) -> None:
|
||||
"""Stage and commit generated test files and their CMakeLists entry."""
|
||||
_git(["add", str(tests_dir)], cwd=worktree_path)
|
||||
_git(
|
||||
["commit", "-m", f"test({track_id}): generated tests for {test_prefix}"],
|
||||
cwd=worktree_path,
|
||||
)
|
||||
|
||||
|
||||
def commit_batch_summary(
|
||||
worktree_path: Path,
|
||||
track_id: str,
|
||||
batch_id: str,
|
||||
) -> None:
|
||||
"""Final commit for a batch (quarantine files, reports, etc.)."""
|
||||
_git(["add", "-A"], cwd=worktree_path)
|
||||
rc, _, _ = _git(
|
||||
["diff", "--cached", "--quiet"], cwd=worktree_path
|
||||
)
|
||||
if rc != 0: # there are staged changes
|
||||
_git(
|
||||
["commit", "-m", f"batch({track_id}): finalise {batch_id}"],
|
||||
cwd=worktree_path,
|
||||
)
|
||||
Reference in new issue
Block a user