feat: non-destructive lock recovery for pushed branches (Closes #440)
Adds structured issue-branch ownership parsing, wires it into lock adoption and gitea_lock_issue validation, documents the restart recovery workflow, and adds regression tests for adoption, durable create_pr resolution, and open-PR blocking without remote branch deletion. Built on keyed persistent lock store and own-branch adoption (#443 / #442). Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
"""Structured issue/branch ownership evidence (#440).
|
||||
|
||||
Author branches must follow ``(fix|feat|docs|chore)/issue-<n>-<desc>``. Duplicate-work
|
||||
and lock-recovery gates use this parser instead of broad substring matching on
|
||||
``issue-<n>`` so unrelated branch names cannot false-positive.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
|
||||
ISSUE_BRANCH_RE = re.compile(
|
||||
r"^(?P<prefix>fix|feat|docs|chore)/issue-(?P<num>\d+)(?:-|$)"
|
||||
)
|
||||
|
||||
|
||||
def parse_issue_branch(branch_name: str) -> int | None:
|
||||
"""Return the issue number encoded in a canonical author branch, else None."""
|
||||
match = ISSUE_BRANCH_RE.match((branch_name or "").strip())
|
||||
if not match:
|
||||
return None
|
||||
return int(match.group("num"))
|
||||
|
||||
|
||||
def branch_belongs_to_issue(branch_name: str, issue_number: int) -> bool:
|
||||
"""True when ``branch_name`` is a canonical branch for ``issue_number``."""
|
||||
parsed = parse_issue_branch(branch_name)
|
||||
return parsed is not None and parsed == issue_number
|
||||
Reference in New Issue
Block a user