Release Healer Man 0.1.6

This commit is contained in:
phenom
2026-08-20 14:05:50 -04:00
parent 55cfd43d66
commit b12fb84859
96 changed files with 10874 additions and 609 deletions
+87 -1
View File
@@ -15,6 +15,7 @@ import re
import shutil
import subprocess
import sys
import tempfile
import threading
import webbrowser
from dataclasses import dataclass
@@ -226,6 +227,67 @@ def current_commit() -> str:
return ""
def validate_release_candidates(project_root: Path = PROJECT_ROOT) -> list[str]:
"""Check tracked and untracked release files without changing the real index."""
with tempfile.TemporaryDirectory(prefix="healer-man-release-index-") as temp_dir:
environment = os.environ.copy()
environment["GIT_INDEX_FILE"] = str(Path(temp_dir) / "index")
def run_temporary_index_command(*args: str) -> subprocess.CompletedProcess[bytes]:
result = subprocess.run(
["git", *args],
cwd=project_root,
env=environment,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
check=False,
)
if result.returncode != 0:
output = result.stdout.decode("utf-8", errors="replace").strip()
raise ReleaseError(
f"Release-candidate Git check failed ({result.returncode}): "
f"git {' '.join(args)}\n{output}"
)
return result
run_temporary_index_command("read-tree", "HEAD")
run_temporary_index_command("add", "-A")
raw_paths = run_temporary_index_command(
"diff", "--cached", "--name-only", "-z"
).stdout
staged_paths = [
path.decode("utf-8", errors="replace")
for path in raw_paths.split(b"\0")
if path
]
whitespace_result = subprocess.run(
["git", "diff", "--cached", "--check"],
cwd=project_root,
env=environment,
text=True,
encoding="utf-8",
errors="replace",
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
check=False,
)
if whitespace_result.returncode != 0:
detail = whitespace_result.stdout.strip()
raise ReleaseError(
"Release-candidate whitespace check failed. This check includes "
f"tracked and untracked files:\n{detail}"
)
dangerous = find_dangerous_staged_paths(staged_paths)
if dangerous:
raise ReleaseError(
"Refusing to release forbidden output or a possible secret:\n"
+ "\n".join(f" - {path}" for path in dangerous)
)
return staged_paths
def windows_powershell_environment(powershell: str) -> dict[str, str]:
environment = os.environ.copy()
if Path(powershell).name.lower() == "powershell.exe":
@@ -1003,6 +1065,15 @@ def launch_gui(*, smoke_test: bool = False) -> int:
credentials: dict[str, str],
) -> None:
self._preflight_git(require_clean=False)
self._log_event(
"\n--- Early release-candidate check ---\n"
"$ npm run release:check"
)
candidate_paths = validate_release_candidates()
self._log_event(
f"✓ Early release-candidate check passed "
f"({len(candidate_paths)} changed path(s), including untracked files)"
)
npm = shutil.which("npm")
powershell = shutil.which("powershell.exe") or shutil.which("powershell")
if not npm or not powershell:
@@ -1034,7 +1105,6 @@ def launch_gui(*, smoke_test: bool = False) -> int:
)
for command, label in checks:
self._run_command(command, label)
self._run_command(["git", "diff", "--check"], "Whitespace check")
self._run_command(["git", "add", "-A"], "Stage release")
staged = True
@@ -1371,12 +1441,28 @@ def main(argv: Sequence[str] | None = None) -> int:
action="store_true",
help="print release/version/Git readiness without opening the GUI",
)
parser.add_argument(
"--check-release",
action="store_true",
help="check all release candidates, including untracked files",
)
parser.add_argument(
"--smoke-test",
action="store_true",
help=argparse.SUPPRESS,
)
args = parser.parse_args(argv)
if args.check_release:
try:
paths = validate_release_candidates()
print(
f"Release candidate check passed: {len(paths)} changed path(s), "
"including untracked files."
)
except Exception as exc:
print(f"Release candidate check failed: {exc}", file=sys.stderr)
return 1
return 0
if args.check:
try:
print(json.dumps(check_summary(), indent=2))