refactor(git): migrate repository creation to core.git commands
Some checks failed
Mark stable commit / test-unit (push) Has been cancelled
Mark stable commit / test-integration (push) Has been cancelled
Mark stable commit / test-env-virtual (push) Has been cancelled
Mark stable commit / test-env-nix (push) Has been cancelled
Mark stable commit / test-e2e (push) Has been cancelled
Mark stable commit / test-virgin-user (push) Has been cancelled
Mark stable commit / test-virgin-root (push) Has been cancelled
Mark stable commit / lint-shell (push) Has been cancelled
Mark stable commit / lint-python (push) Has been cancelled
Mark stable commit / mark-stable (push) Has been cancelled

- Replace direct subprocess git calls with core.git commands (init, add_all, commit, branch_move, push_upstream)
- Introduce add_all, init, and branch_move command wrappers with preview support
- Use git config queries via get_config_value instead of shell access
- Preserve main → master fallback logic with explicit error handling
- Improve error transparency while keeping previous non-fatal behavior

https://chatgpt.com/share/69414b77-b4d4-800f-a189-463b489664b3
This commit is contained in:
Kevin Veen-Birkenbach
2025-12-16 13:05:42 +01:00
parent 9c22c7dbb4
commit 019aa4b0d9
6 changed files with 115 additions and 44 deletions

View File

@@ -1,8 +1,8 @@
# src/pkgmgr/actions/repository/create.py
from __future__ import annotations
import os
import re
import subprocess
from dataclasses import dataclass
from typing import Any, Dict, Optional, Tuple
from urllib.parse import urlparse
@@ -14,6 +14,16 @@ from pkgmgr.actions.mirror.setup_cmd import setup_mirrors
from pkgmgr.actions.repository.scaffold import render_default_templates
from pkgmgr.core.command.alias import generate_alias
from pkgmgr.core.config.save import save_user_config
from pkgmgr.core.git.commands import (
GitCommitError,
GitPushUpstreamError,
add_all,
branch_move,
commit,
init,
push_upstream,
)
from pkgmgr.core.git.queries import get_config_value
Repository = Dict[str, Any]
@@ -28,27 +38,6 @@ class RepoParts:
name: str
def _run(cmd: str, cwd: str, preview: bool) -> None:
if preview:
print(f"[Preview] Would run in {cwd}: {cmd}")
return
subprocess.run(cmd, cwd=cwd, shell=True, check=True)
def _git_get(key: str) -> str:
try:
out = subprocess.run(
f"git config --get {key}",
shell=True,
check=False,
capture_output=True,
text=True,
)
return (out.stdout or "").strip()
except Exception:
return ""
def _split_host_port(host_with_port: str) -> Tuple[str, Optional[str]]:
if ":" in host_with_port:
host, port = host_with_port.split(":", 1)
@@ -116,28 +105,27 @@ def _write_default_mirrors(repo_dir: str, primary: str, name: str, preview: bool
def _git_init_and_initial_commit(repo_dir: str, preview: bool) -> None:
_run("git init", cwd=repo_dir, preview=preview)
_run("git add -A", cwd=repo_dir, preview=preview)
init(cwd=repo_dir, preview=preview)
add_all(cwd=repo_dir, preview=preview)
if preview:
print(f'[Preview] Would run in {repo_dir}: git commit -m "Initial commit"')
return
subprocess.run('git commit -m "Initial commit"', cwd=repo_dir, shell=True, check=False)
try:
commit("Initial commit", cwd=repo_dir, preview=preview)
except GitCommitError as exc:
print(f"[WARN] Initial commit failed (continuing): {exc}")
def _git_push_main_or_master(repo_dir: str, preview: bool) -> None:
_run("git branch -M main", cwd=repo_dir, preview=preview)
try:
_run("git push -u origin main", cwd=repo_dir, preview=preview)
branch_move("main", cwd=repo_dir, preview=preview)
push_upstream("origin", "main", cwd=repo_dir, preview=preview)
return
except subprocess.CalledProcessError:
except GitPushUpstreamError:
pass
try:
_run("git branch -M master", cwd=repo_dir, preview=preview)
_run("git push -u origin master", cwd=repo_dir, preview=preview)
except subprocess.CalledProcessError as exc:
branch_move("master", cwd=repo_dir, preview=preview)
push_upstream("origin", "master", cwd=repo_dir, preview=preview)
except GitPushUpstreamError as exc:
print(f"[WARN] Push failed: {exc}")
@@ -157,8 +145,8 @@ def create_repo(
base_dir = os.path.expanduser(str(directories.get("repositories", "~/Repositories")))
repo_dir = os.path.join(base_dir, parts.host, parts.owner, parts.name)
author_name = _git_get("user.name") or "Unknown Author"
author_email = _git_get("user.email") or "unknown@example.invalid"
author_name = get_config_value("user.name") or "Unknown Author"
author_email = get_config_value("user.email") or "unknown@example.invalid"
homepage = _repo_homepage(parts.host, parts.owner, parts.name)
primary_url = _build_default_primary_url(parts)

View File

@@ -1,27 +1,31 @@
# src/pkgmgr/core/git/commands/__init__.py
from __future__ import annotations
from .add import GitAddError, add
from .add_all import GitAddAllError, add_all
from .add_remote import GitAddRemoteError, add_remote
from .add_remote_push_url import GitAddRemotePushUrlError, add_remote_push_url
from .branch_move import GitBranchMoveError, branch_move
from .checkout import GitCheckoutError, checkout
from .clone import GitCloneError, clone
from .commit import GitCommitError, commit
from .create_branch import GitCreateBranchError, create_branch
from .delete_local_branch import GitDeleteLocalBranchError, delete_local_branch
from .delete_remote_branch import GitDeleteRemoteBranchError, delete_remote_branch
from .fetch import GitFetchError, fetch
from .init import GitInitError, init
from .merge_no_ff import GitMergeError, merge_no_ff
from .pull import GitPullError, pull
from .pull_ff_only import GitPullFfOnlyError, pull_ff_only
from .push import GitPushError, push
from .push_upstream import GitPushUpstreamError, push_upstream
from .add_remote import GitAddRemoteError, add_remote
from .add_remote_push_url import GitAddRemotePushUrlError, add_remote_push_url
from .set_remote_url import GitSetRemoteUrlError, set_remote_url
from .tag_annotated import GitTagAnnotatedError, tag_annotated
from .tag_force_annotated import GitTagForceAnnotatedError, tag_force_annotated
from .clone import GitCloneError, clone
__all__ = [
"add",
"add_all",
"fetch",
"checkout",
"pull",
@@ -39,7 +43,10 @@ __all__ = [
"tag_annotated",
"tag_force_annotated",
"clone",
"init",
"branch_move",
"GitAddError",
"GitAddAllError",
"GitFetchError",
"GitCheckoutError",
"GitPullError",
@@ -57,4 +64,6 @@ __all__ = [
"GitTagAnnotatedError",
"GitTagForceAnnotatedError",
"GitCloneError",
"GitInitError",
"GitBranchMoveError",
]

View File

@@ -0,0 +1,22 @@
# src/pkgmgr/core/git/commands/add_all.py
from __future__ import annotations
from ..errors import GitError, GitCommandError
from ..run import run
class GitAddAllError(GitCommandError):
"""Raised when `git add -A` fails."""
def add_all(*, cwd: str = ".", preview: bool = False) -> None:
"""
Stage all changes (tracked + untracked).
Equivalent to:
git add -A
"""
try:
run(["add", "-A"], cwd=cwd, preview=preview)
except GitError as exc:
raise GitAddAllError("Failed to stage all changes with `git add -A`.", cwd=cwd) from exc

View File

@@ -0,0 +1,22 @@
# src/pkgmgr/core/git/commands/branch_move.py
from __future__ import annotations
from ..errors import GitError, GitCommandError
from ..run import run
class GitBranchMoveError(GitCommandError):
"""Raised when renaming/moving a branch fails."""
def branch_move(branch: str, *, cwd: str = ".", preview: bool = False) -> None:
"""
Rename the current branch to `branch`, creating it if needed.
Equivalent to:
git branch -M <branch>
"""
try:
run(["branch", "-M", branch], cwd=cwd, preview=preview)
except GitError as exc:
raise GitBranchMoveError(f"Failed to move/rename current branch to {branch!r}.", cwd=cwd) from exc

View File

@@ -0,0 +1,22 @@
# src/pkgmgr/core/git/commands/init.py
from __future__ import annotations
from ..errors import GitError, GitCommandError
from ..run import run
class GitInitError(GitCommandError):
"""Raised when `git init` fails."""
def init(*, cwd: str = ".", preview: bool = False) -> None:
"""
Initialize a repository.
Equivalent to:
git init
"""
try:
run(["init"], cwd=cwd, preview=preview)
except GitError as exc:
raise GitInitError("Failed to initialize git repository.", cwd=cwd) from exc

View File

@@ -1,3 +1,4 @@
# src/pkgmgr/core/git/commands/push_upstream.py
from __future__ import annotations
from ..errors import GitError, GitCommandError
@@ -8,14 +9,21 @@ class GitPushUpstreamError(GitCommandError):
"""Raised when pushing a branch with upstream tracking fails."""
def push_upstream(remote: str, branch: str, cwd: str = ".") -> None:
def push_upstream(
remote: str,
branch: str,
*,
cwd: str = ".",
preview: bool = False,
) -> None:
"""
Push a branch and set upstream tracking.
Equivalent to: git push -u <remote> <branch>
Equivalent to:
git push -u <remote> <branch>
"""
try:
run(["push", "-u", remote, branch], cwd=cwd)
run(["push", "-u", remote, branch], cwd=cwd, preview=preview)
except GitError as exc:
raise GitPushUpstreamError(
f"Failed to push branch {branch!r} to {remote!r} with upstream tracking.",