Coverage for langsmith/env/_git.py: 22%
27 statements
« prev ^ index » next coverage.py v7.10.1, created at 2025-12-11 16:15 -0800
« prev ^ index » next coverage.py v7.10.1, created at 2025-12-11 16:15 -0800
1"""Fetch information about any current git repo."""
3import functools
4import logging
5import subprocess
6from typing import List, Optional, TypeVar
8from typing_extensions import TypedDict
10logger = logging.getLogger(__name__)
12T = TypeVar("T")
15def exec_git(command: List[str]) -> Optional[str]:
16 try:
17 return subprocess.check_output(
18 ["git"] + command, encoding="utf-8", stderr=subprocess.DEVNULL
19 ).strip()
20 except BaseException:
21 return None
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]
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 )
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 }