Skip to content

Commit ab1f8be

Browse files
authored
Merge pull request #288 from simvue-io/feature/git-metadata
Added git metadata to runs
2 parents 5c5dfa5 + 2d0ce87 commit ab1f8be

File tree

4 files changed

+137
-17
lines changed

4 files changed

+137
-17
lines changed

poetry.lock

Lines changed: 60 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ matplotlib = {version = "^3.8.2", optional = true}
4646
typing_extensions = { version = "^4.11.0", python = "<3.10" }
4747
toml = "^0.10.2"
4848
click = "^8.1.7"
49+
gitpython = "^3.1.43"
4950
humanfriendly = "^10.0"
5051
tabulate = "^0.9.0"
5152
torch = [

simvue/metadata.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
"""
2+
Metadata
3+
========
4+
5+
Contains functions for extracting additional metadata about the current project
6+
7+
"""
8+
9+
import typing
10+
import git
11+
import json
12+
13+
14+
def git_info(repository: str) -> dict[str, typing.Any]:
15+
"""Retrieves metadata for the target git repository
16+
17+
This is a passive function which returns an empty dictionary if any
18+
metadata is missing. Exceptions are raised only if the repository
19+
does not have the expected form assumed by this retrieval method.
20+
21+
Parameters
22+
----------
23+
repository : str
24+
root directory of the git repository
25+
26+
Returns
27+
-------
28+
dict[str, typing.Any]
29+
metadata for the target repository
30+
"""
31+
try:
32+
git_repo = git.Repo(repository, search_parent_directories=True)
33+
except git.InvalidGitRepositoryError:
34+
return {}
35+
current_commit: git.Commit = git_repo.head.commit
36+
author_list: set[str] = set(
37+
email
38+
for commit in git_repo.iter_commits("--all")
39+
if "noreply" not in (email := (commit.author.email or ""))
40+
and "[bot]" not in (commit.author.name or "")
41+
)
42+
43+
ref: str = current_commit.hexsha
44+
45+
# In the case where the repository is dirty blame should point to the
46+
# current developer, not the person responsible for the latest commit
47+
if dirty := git_repo.is_dirty():
48+
blame = git_repo.config_reader().get_value("user", "email")
49+
else:
50+
blame = current_commit.committer.email
51+
52+
for tag in git_repo.tags:
53+
if tag.commit == current_commit:
54+
ref = tag.name
55+
break
56+
57+
return {
58+
"git.authors": json.dumps(list(author_list)),
59+
"git.ref": ref,
60+
"git.msg": current_commit.message.strip(),
61+
"git.time_stamp": current_commit.committed_datetime.strftime(
62+
"%Y-%m-%d %H:%M:%S %z UTC"
63+
),
64+
"git.blame": blame,
65+
"git.url": git_repo.remote().url,
66+
"git.dirty": dirty,
67+
}
68+
69+
70+
if __name__ in "__main__":
71+
import os.path
72+
import json
73+
74+
print(json.dumps(git_info(os.path.dirname(__file__)), indent=2))

simvue/run.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
from .models import RunInput
4040
from .serialization import Serializer
4141
from .system import get_system
42+
from .metadata import git_info
4243
from .utilities import (
4344
calculate_sha256,
4445
compare_alerts,
@@ -514,7 +515,7 @@ def init(
514515
return False
515516

516517
data: dict[str, typing.Any] = {
517-
"metadata": metadata or {},
518+
"metadata": (metadata or {}) | git_info(os.getcwd()),
518519
"tags": tags or [],
519520
"status": self._status,
520521
"ttl": retention_secs,

0 commit comments

Comments
 (0)