60 lines
1.7 KiB
Python
60 lines
1.7 KiB
Python
"""Git operations for myclaude using GitPython."""
|
|
|
|
import shutil
|
|
import tempfile
|
|
from contextlib import contextmanager
|
|
from pathlib import Path
|
|
from typing import Generator
|
|
|
|
from git import GitCommandError, Repo
|
|
|
|
|
|
@contextmanager
|
|
def temp_clone(repo_url: str, keep: bool = False) -> Generator[tuple[Path, Repo], None, None]:
|
|
"""Clone a git repository into a temporary directory.
|
|
|
|
The temporary directory is automatically cleaned up on exit unless
|
|
keep is True, in which case it is preserved for inspection.
|
|
|
|
Args:
|
|
repo_url: The SSH URL of the repository to clone.
|
|
keep: If True, the temporary directory is not deleted after use.
|
|
|
|
Yields:
|
|
A tuple of (path to the cloned repo, Repo object).
|
|
|
|
Raises:
|
|
RuntimeError: If the clone operation fails.
|
|
"""
|
|
tmp_dir = tempfile.mkdtemp()
|
|
try:
|
|
try:
|
|
repo = Repo.clone_from(repo_url, tmp_dir)
|
|
except GitCommandError as e:
|
|
raise RuntimeError(
|
|
f"Failed to clone repository '{repo_url}': {e}"
|
|
) from e
|
|
yield Path(tmp_dir), repo
|
|
finally:
|
|
if keep:
|
|
print(f"[debug] Temporary directory kept at: {tmp_dir}")
|
|
else:
|
|
shutil.rmtree(tmp_dir, ignore_errors=True)
|
|
|
|
|
|
def commit_and_push(repo: Repo, message: str) -> None:
|
|
"""Stage all changes, commit, and push to the remote origin.
|
|
|
|
Args:
|
|
repo: A GitPython Repo object with an 'origin' remote configured.
|
|
message: The commit message.
|
|
|
|
Raises:
|
|
RuntimeError: If there are no changes to commit.
|
|
"""
|
|
repo.git.add(A=True)
|
|
if not repo.is_dirty(index=True, working_tree=False):
|
|
raise RuntimeError("Nothing to commit: no changes detected.")
|
|
repo.index.commit(message)
|
|
repo.remotes.origin.push()
|