- Writing custom git flow scripts - a start
This commit is contained in:
94
scripts/git/core/git_api.py
Normal file
94
scripts/git/core/git_api.py
Normal file
@@ -0,0 +1,94 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import subprocess
|
||||
from typing import Iterable
|
||||
|
||||
from . import output
|
||||
|
||||
|
||||
class GitError(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
def _run_git(args: Iterable[str], *, capture_output: bool = False, check: bool = True) -> subprocess.CompletedProcess:
|
||||
cmd = ["git", *args]
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
text=True,
|
||||
capture_output=capture_output,
|
||||
check=False,
|
||||
)
|
||||
if check and result.returncode != 0:
|
||||
stderr = result.stderr.strip() if result.stderr else ""
|
||||
raise GitError(f"git {' '.join(args)} failed ({result.returncode}): {stderr}")
|
||||
return result
|
||||
|
||||
|
||||
def get_current_branch() -> str:
|
||||
result = _run_git(["rev-parse", "--abbrev-ref", "HEAD"], capture_output=True)
|
||||
return (result.stdout or "").strip()
|
||||
|
||||
|
||||
def is_clean_working_tree() -> bool:
|
||||
result = _run_git(["status", "--porcelain"], capture_output=True)
|
||||
return (result.stdout or "").strip() == ""
|
||||
|
||||
|
||||
def ensure_clean_working_tree() -> None:
|
||||
if not is_clean_working_tree():
|
||||
raise GitError(
|
||||
"Working tree is niet clean. Commit of stash je wijzigingen voor je deze actie uitvoert."
|
||||
)
|
||||
|
||||
|
||||
def ensure_branch_exists(branch: str) -> None:
|
||||
try:
|
||||
_run_git(["show-ref", "--verify", f"refs/heads/{branch}"], capture_output=True)
|
||||
except GitError as exc:
|
||||
raise GitError(f"Branch '{branch}' bestaat niet lokaal.") from exc
|
||||
|
||||
|
||||
def checkout_branch(branch: str) -> None:
|
||||
_run_git(["checkout", branch])
|
||||
|
||||
|
||||
def create_branch(branch: str, base: str) -> None:
|
||||
_run_git(["checkout", base])
|
||||
_run_git(["checkout", "-b", branch])
|
||||
|
||||
|
||||
def fetch_remote(remote: str) -> None:
|
||||
_run_git(["fetch", remote])
|
||||
|
||||
|
||||
def ensure_not_behind_remote(branch: str, remote: str) -> None:
|
||||
"""Controleer of branch niet achterloopt op remote.
|
||||
|
||||
We gebruiken `git rev-list --left-right --count local...remote` om
|
||||
ahead/behind te bepalen.
|
||||
"""
|
||||
|
||||
remote_ref = f"{remote}/{branch}"
|
||||
try:
|
||||
result = _run_git(
|
||||
["rev-list", "--left-right", "--count", f"{branch}...{remote_ref}"],
|
||||
capture_output=True,
|
||||
)
|
||||
except GitError:
|
||||
# Geen tracking remote; in die gevallen doen we geen check.
|
||||
return
|
||||
|
||||
output_str = (result.stdout or "").strip()
|
||||
if not output_str:
|
||||
return
|
||||
|
||||
ahead_str, behind_str = output_str.split()
|
||||
ahead = int(ahead_str)
|
||||
behind = int(behind_str)
|
||||
|
||||
if behind > 0:
|
||||
raise GitError(
|
||||
f"Branch '{branch}' loopt {behind} commit(s) achter op {remote_ref}. "
|
||||
f"Doe eerst een 'git pull --ff-only' of werk te wijzigingen lokaal bij."
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user