codekingpro/portable-devtools
114k
1"""Fetch information about any current git repo."""2 3import functools4import logging5import subprocess6from typing import List, Optional, TypeVar7 8from typing_extensions import TypedDict9 10logger = logging.getLogger(__name__)11 12T = TypeVar("T")13 14 15def exec_git(command: List[str]) -> Optional[str]:16 try:17 return subprocess.check_output(18 ["git"] + command, encoding="utf-8", stderr=subprocess.DEVNULL19 ).strip()20 except BaseException:21 return None22 23 24class GitInfo(TypedDict, total=False):25 repo_name: Optional[str]26 remote_url: Optional[str]27 commit: Optional[str]28 branch: Optional[str]29 author_name: Optional[str]30 author_email: Optional[str]31 commit_time: Optional[str]32 dirty: Optional[bool]33 tags: Optional[str]34 35 36@functools.lru_cache(maxsize=1)37def get_git_info(remote: str = "origin") -> GitInfo:38 """Get information about the git repository."""39 if not exec_git(["rev-parse", "--is-inside-work-tree"]):40 return GitInfo(41 remote_url=None,42 commit=None,43 branch=None,44 author_name=None,45 author_email=None,46 commit_time=None,47 dirty=None,48 tags=None,49 repo_name=None,50 )51 52 return {53 "remote_url": exec_git(["remote", "get-url", remote]),54 "commit": exec_git(["rev-parse", "HEAD"]),55 "commit_time": exec_git(["log", "-1", "--format=%ct"]),56 "branch": exec_git(["rev-parse", "--abbrev-ref", "HEAD"]),57 "tags": exec_git(58 ["describe", "--tags", "--exact-match", "--always", "--dirty"]59 ),60 "dirty": exec_git(["status", "--porcelain"]) != "",61 "author_name": exec_git(["log", "-1", "--format=%an"]),62 "author_email": exec_git(["log", "-1", "--format=%ae"]),63 "repo_name": (exec_git(["rev-parse", "--show-toplevel"]) or "").split("/")[-1],64 }65 