Files
Gitea-Tools/tests/test_worktrees.py
T
sysadmin 46db3f73e8 feat: complete isolated-worktree helpers — worktree-review, worktree-clean, tests (#39)
Finishes the isolated-worktree standard begun in #38 (which merged the
branches/ gitignore, runbook, and scripts/worktree-start). Adds the two
remaining helpers and their tests.

- scripts/worktree-review: isolated DETACHED review worktree under
  branches/review-<branch> (fetch/prune first, refuse to overwrite, print path,
  --dry-run). Detached so a reviewer cannot accidentally commit and review work
  never blocks the author's implementation folder.
- scripts/worktree-clean: the only deleting helper — removes a branches/
  worktree after merge/close, refuses a dirty worktree (no --force), optionally
  safe-deletes a merged branch (git branch -d), fetch/prune first, --dry-run.
  Deletes nothing unless explicitly invoked.
- tests/test_worktrees.py: path generation + refuse-to-overwrite for all three
  helpers via --dry-run (no real worktrees/branches/network/deletions).
- runbook: reference worktree-review / worktree-clean and the --dry-run flag.

Checks: bash -n clean on all three scripts; git diff --check clean; full suite
286 passed, 0 failures.

Closes #39. Follow-up to #38.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 02:54:50 -04:00

105 lines
3.5 KiB
Python

"""Tests for the branch-worktree helper scripts (#38/#39).
Exercises path generation and refuse-to-overwrite via the scripts' ``--dry-run``
mode, so no real worktrees, branches, network, or deletions are involved.
"""
import os
import subprocess
import unittest
from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
SCRIPTS = REPO / "scripts"
BRANCHES = REPO / "branches"
def run(script, *args):
proc = subprocess.run(
["bash", str(SCRIPTS / script), *args],
capture_output=True, text=True, cwd=str(REPO),
)
return proc.returncode, proc.stdout, proc.stderr
class TestWorktreeStart(unittest.TestCase):
def test_dry_run_path_generation(self):
rc, out, _ = run("worktree-start", "--dry-run", "fix/issue-123-example")
self.assertEqual(rc, 0)
self.assertIn("branches/fix-issue-123-example", out)
self.assertIn("fix/issue-123-example", out)
self.assertIn("prgs/master", out) # default start-ref
def test_bad_args_exit_2(self):
rc, _, _ = run("worktree-start")
self.assertEqual(rc, 2)
def test_refuses_existing_worktree(self):
slug = f"zz-refuse-start-{os.getpid()}"
target = BRANCHES / slug
target.mkdir(parents=True, exist_ok=True)
try:
rc, _, err = run("worktree-start", "--dry-run", slug)
self.assertEqual(rc, 1)
self.assertIn("Refusing to reuse", err)
finally:
target.rmdir()
class TestWorktreeReview(unittest.TestCase):
def test_dry_run_detached_review_path(self):
rc, out, _ = run("worktree-review", "--dry-run", "fix/issue-9-x")
self.assertEqual(rc, 0)
self.assertIn("branches/review-fix-issue-9-x", out)
self.assertIn("--detach", out)
self.assertIn("prgs/fix/issue-9-x", out) # default start-ref
def test_refuses_existing_review_worktree(self):
slug = f"review-zz-refuse-rev-{os.getpid()}"
target = BRANCHES / slug
target.mkdir(parents=True, exist_ok=True)
try:
# branch name maps to the same slug: review-<branch>
rc, _, err = run("worktree-review", "--dry-run",
f"zz-refuse-rev-{os.getpid()}")
self.assertEqual(rc, 1)
self.assertIn("Refusing to reuse", err)
finally:
target.rmdir()
class TestWorktreeClean(unittest.TestCase):
def test_missing_worktree_errors(self):
rc, _, err = run("worktree-clean", "--dry-run", "does-not-exist-xyz")
self.assertEqual(rc, 1)
self.assertIn("No such worktree", err)
def test_dry_run_does_not_delete(self):
slug = f"zz-clean-{os.getpid()}"
target = BRANCHES / slug
target.mkdir(parents=True, exist_ok=True)
try:
rc, out, _ = run("worktree-clean", "--dry-run", slug)
self.assertEqual(rc, 0)
self.assertIn("worktree remove", out)
self.assertTrue(target.is_dir()) # nothing removed in dry-run
finally:
target.rmdir()
def test_dry_run_delete_branch_lists_branch_command(self):
slug = f"zz-clean-b-{os.getpid()}"
target = BRANCHES / slug
target.mkdir(parents=True, exist_ok=True)
try:
rc, out, _ = run("worktree-clean", "--dry-run", "--delete-branch", slug)
self.assertEqual(rc, 0)
self.assertIn("branch -d", out)
finally:
target.rmdir()
if __name__ == "__main__":
unittest.main()