Skip to content

Commit 77eaf99

Browse files
committed
refactor(config): Set User config based on Git config instead of the opposite
1 parent 44ecee8 commit 77eaf99

File tree

7 files changed

+76
-109
lines changed

7 files changed

+76
-109
lines changed

src/dda/cli/base.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,14 +137,17 @@ def __exit__(
137137
from dda.cli import START_TIME, START_TIMESTAMP
138138
from dda.utils.platform import join_command_args
139139

140+
username = app.config.user.name if app.config.user.name != "auto" else app.tools.git.author_name
141+
email = app.config.user.email if app.config.user.email != "auto" else app.tools.git.author_email
142+
140143
metadata = {
141144
"cli.command": join_command_args(sys.argv[1:]),
142145
"cli.exit_code": str(exit_code),
143-
"author.name": app.config.user.name,
144-
"author.emails": app.config.user.emails,
146+
"author.name": username,
147+
"author.email": email,
145148
# TODO: Remove this once the new keys are fully rolled out
146-
"git.author.name": app.config.user.name,
147-
"git.author.email": app.config.user.emails[0],
149+
"git.author.name": username,
150+
"git.author.email": email,
148151
}
149152
if os.environ.get("PRE_COMMIT") == "1":
150153
metadata["exec.source"] = "pre-commit"

src/dda/config/model/tools.py

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,43 @@ class BazelConfig(Struct, frozen=True, forbid_unknown_fields=True):
2121
managed: bool | Literal["auto"] = "auto"
2222

2323

24+
def _get_name_from_git() -> str:
25+
from os import environ
26+
27+
from dda.tools.git import Git
28+
from dda.utils.process import static_capture
29+
30+
if name := environ.get(Git.AUTHOR_NAME_ENV_VAR):
31+
return name
32+
33+
return static_capture(["git", "config", "--global", "--get", "user.name"]).strip()
34+
35+
36+
def _get_email_from_git() -> str:
37+
from os import environ
38+
39+
from dda.tools.git import Git
40+
from dda.utils.process import static_capture
41+
42+
if email := environ.get(Git.AUTHOR_EMAIL_ENV_VAR):
43+
return email
44+
45+
return static_capture(["git", "config", "--global", "--get", "user.email"]).strip()
46+
47+
2448
class GitConfig(Struct, frozen=True):
2549
"""
2650
/// tab | :octicons-file-code-16: config.toml
2751
```toml
2852
[tools.git]
29-
author_details = "inherit"
53+
name = "U.N. Owen"
54+
email = "void@some.where"
3055
```
31-
`author_details` can be either:
32-
- `inherit`: The author name and email will be inherited from the main 'user' config (see [UserConfig](./user.md))
33-
> The first email will be used if multiple emails are found.
34-
- `system`: The author name and email will be inherited from the system git config
3556
///
3657
"""
3758

38-
author_details: Literal["inherit", "system"] = "system"
59+
author_name: str = field(default_factory=_get_name_from_git)
60+
author_email: str = field(default_factory=_get_email_from_git)
3961

4062

4163
class ToolsConfig(Struct, frozen=True):

src/dda/config/model/user.py

Lines changed: 7 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,7 @@
33
# SPDX-License-Identifier: MIT
44
from __future__ import annotations
55

6-
from msgspec import Struct, field
7-
8-
9-
def _get_name_from_git() -> str:
10-
from os import environ
11-
12-
from dda.tools.git import Git
13-
from dda.utils.process import static_capture
14-
15-
if name := environ.get(Git.AUTHOR_NAME_ENV_VAR):
16-
return name
17-
18-
return static_capture(["git", "config", "--global", "--get", "user.name"]).strip()
19-
20-
21-
def _get_emails_from_git() -> list[str]:
22-
from os import environ
23-
24-
from dda.tools.git import Git
25-
from dda.utils.process import static_capture
26-
27-
if email := environ.get(Git.AUTHOR_EMAIL_ENV_VAR):
28-
return [email]
29-
30-
return [static_capture(["git", "config", "--global", "--get", "user.email"]).strip()]
6+
from msgspec import Struct
317

328

339
class UserConfig(Struct, frozen=True):
@@ -36,12 +12,13 @@ class UserConfig(Struct, frozen=True):
3612
```toml
3713
[user]
3814
name = "U.N. Owen"
39-
emails = ["void@some.where", "other@some.where"]
15+
email = "void@some.where"
4016
```
41-
> The first email will be used for setting git author email if multiple emails are found.
17+
These values will be used for dda-related functionality, such as telemetry.
18+
Both `email` and `name` can be set to `auto`, in which case they will be equal to the values in [tools.git]
4219
///
4320
"""
4421

45-
# Default username and email are fetched from git config
46-
name: str = field(default_factory=_get_name_from_git)
47-
emails: list[str] = field(default_factory=_get_emails_from_git)
22+
# Default username and email are equal to the values in [tools.git]
23+
name: str = "auto"
24+
email: str = "auto"

src/dda/tools/git.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,10 @@ class Git(Tool):
2626
AUTHOR_EMAIL_ENV_VAR = "GIT_AUTHOR_EMAIL"
2727

2828
def env_vars(self) -> dict[str, str]:
29-
if self.app.config.tools.git.author_details == "inherit":
30-
return {
31-
self.AUTHOR_NAME_ENV_VAR: self.app.config.user.name.strip(),
32-
self.AUTHOR_EMAIL_ENV_VAR: self.app.config.user.emails[0].strip(),
33-
}
34-
return {}
29+
return {
30+
self.AUTHOR_NAME_ENV_VAR: self.app.config.tools.git.author_name.strip(),
31+
self.AUTHOR_EMAIL_ENV_VAR: self.app.config.tools.git.author_email.strip(),
32+
}
3533

3634
@cached_property
3735
def path(self) -> str:

tests/cli/config/test_show.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ def test_default_scrubbed(dda, config_file, helpers, default_cache_dir, default_
1111

1212
# The default name and email are queried from the global git config on config initialization
1313
# We override them to make sure we have a known value
14-
config_file.data["user"]["name"] = "Foo Bar"
15-
config_file.data["user"]["emails"] = ["foo@bar.baz"]
14+
config_file.data["tools"]["git"]["author_name"] = "Foo Bar"
15+
config_file.data["tools"]["git"]["author_email"] = "foo@bar.baz"
1616
config_file.save()
1717

1818
result = dda("config", "show")
@@ -35,7 +35,8 @@ def test_default_scrubbed(dda, config_file, helpers, default_cache_dir, default_
3535
managed = "auto"
3636
3737
[tools.git]
38-
author_details = "system"
38+
author_name = "Foo Bar"
39+
author_email = "foo@bar.baz"
3940
4041
[storage]
4142
data = "{default_data_directory}"
@@ -46,8 +47,8 @@ def test_default_scrubbed(dda, config_file, helpers, default_cache_dir, default_
4647
token = "*****"
4748
4849
[user]
49-
name = "Foo Bar"
50-
emails = ["foo@bar.baz"]
50+
name = "auto"
51+
email = "auto"
5152
5253
[terminal]
5354
verbosity = 0
@@ -73,10 +74,10 @@ def test_default_scrubbed(dda, config_file, helpers, default_cache_dir, default_
7374
def test_reveal(dda, config_file, helpers, default_cache_dir, default_data_dir):
7475
config_file.data["github"]["auth"] = {"user": "foo", "token": "bar"}
7576

76-
# The default name and email are queried from the global git config on config initialization
77+
# The default git author name and email are queried from the global git config on config initialization
7778
# We override them to make sure we have a known value
78-
config_file.data["user"]["name"] = "Foo Bar"
79-
config_file.data["user"]["emails"] = ["foo@bar.baz"]
79+
config_file.data["tools"]["git"]["author_name"] = "Foo Bar"
80+
config_file.data["tools"]["git"]["author_email"] = "foo@bar.baz"
8081
config_file.save()
8182

8283
result = dda("config", "show", "-a")
@@ -99,7 +100,8 @@ def test_reveal(dda, config_file, helpers, default_cache_dir, default_data_dir):
99100
managed = "auto"
100101
101102
[tools.git]
102-
author_details = "system"
103+
author_name = "Foo Bar"
104+
author_email = "foo@bar.baz"
103105
104106
[storage]
105107
data = "{default_data_directory}"
@@ -110,8 +112,8 @@ def test_reveal(dda, config_file, helpers, default_cache_dir, default_data_dir):
110112
token = "bar"
111113
112114
[user]
113-
name = "Foo Bar"
114-
emails = ["foo@bar.baz"]
115+
name = "auto"
116+
email = "auto"
115117
116118
[terminal]
117119
verbosity = 0

tests/tools/conftest.py

Lines changed: 13 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import os
21
import shutil
32
from collections.abc import Callable, Generator
43

@@ -28,7 +27,7 @@ def clear_cached_config(app: Application) -> None:
2827

2928
# Initialize a dummy repo in a temporary directory for the tests to use
3029
@pytest.fixture
31-
def temp_repo(app: Application, temp_dir: Path, set_system_git_author: None) -> Generator[Path, None, None]: # noqa: ARG001
30+
def temp_repo(app: Application, temp_dir: Path, set_git_author: None) -> Generator[Path, None, None]: # noqa: ARG001
3231
git: Git = app.tools.git
3332
repo_path = temp_dir / "dummy-repo"
3433
repo_path.mkdir() # Don't do exist_ok, the directory should not exist
@@ -42,52 +41,22 @@ def temp_repo(app: Application, temp_dir: Path, set_system_git_author: None) ->
4241

4342

4443
@pytest.fixture
45-
def set_system_git_author(app: Application) -> Generator[None, None, None]:
46-
# Make sure the config is set to "system" mode, so that the author details are not inherited from the user config
47-
old_config = app.config_file.data["tools"]["git"]["author_details"]
48-
app.config_file.data["tools"]["git"]["author_details"] = "system"
49-
app.config_file.save()
50-
clear_cached_config(app)
44+
def set_git_author(app: Application) -> Generator[None, None, None]:
45+
"""
46+
Set the git author name and email to "Test Runner" and "test.runner@example.com" respectively.
47+
This is done by setting the values in the config file.
48+
Any commits made by `dda` will use these values, but any calls to `git config` will still return the global git config values.
49+
"""
50+
old_name = app.config_file.data["tools"]["git"]["author_name"]
51+
old_email = app.config_file.data["tools"]["git"]["author_email"]
52+
app.config_file.data["tools"]["git"]["author_name"] = "Test Runner"
53+
app.config_file.data["tools"]["git"]["author_email"] = "test.runner@example.com"
5154

52-
old_env_author = os.environ.pop(Git.AUTHOR_NAME_ENV_VAR, default=None)
53-
old_env_email = os.environ.pop(Git.AUTHOR_EMAIL_ENV_VAR, default=None)
54-
old_author_name = app.tools.git.capture(["config", "--get", "user.name"], check=False)
55-
old_author_email = app.tools.git.capture(["config", "--get", "user.email"], check=False)
56-
app.tools.git.run(["config", "--global", "user.name", "Test Runner"])
57-
app.tools.git.run(["config", "--global", "user.email", "test.runner@example.com"])
58-
yield
59-
60-
app.tools.git.run(["config", "--global", "--unset", "user.name"])
61-
app.tools.git.run(["config", "--global", "--unset", "user.email"])
62-
if old_author_name:
63-
app.tools.git.run(["config", "--global", "user.name", old_author_name.strip()])
64-
if old_author_email:
65-
app.tools.git.run(["config", "--global", "user.email", old_author_email.strip()])
66-
if old_env_author:
67-
os.environ[Git.AUTHOR_NAME_ENV_VAR] = old_env_author.strip()
68-
if old_env_email:
69-
os.environ[Git.AUTHOR_EMAIL_ENV_VAR] = old_env_email.strip()
70-
71-
app.config_file.data["tools"]["git"]["author_details"] = old_config
72-
app.config_file.save()
73-
clear_cached_config(app)
74-
75-
76-
@pytest.fixture
77-
def set_inherit_git_author(app: Application) -> Generator[None, None, None]:
78-
old_config = app.config_file.data["tools"]["git"]["author_details"]
79-
app.config_file.data["tools"]["git"]["author_details"] = "inherit"
80-
81-
old_name = app.config_file.data["user"]["name"]
82-
old_emails = app.config_file.data["user"]["emails"]
83-
app.config_file.data["user"]["name"] = "Test Runner"
84-
app.config_file.data["user"]["emails"] = ["test.runner@example.com"]
8555
app.config_file.save()
8656
clear_cached_config(app)
8757
yield
88-
app.config_file.data["tools"]["git"]["author_details"] = old_config
89-
app.config_file.data["user"]["name"] = old_name
90-
app.config_file.data["user"]["emails"] = old_emails
58+
app.config_file.data["tools"]["git"]["author_name"] = old_name
59+
app.config_file.data["tools"]["git"]["author_email"] = old_email
9160
app.config_file.save()
9261
clear_cached_config(app)
9362

tests/tools/test_git.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,18 +49,12 @@ def test_basic(
4949
assert f"Initial commit: {random_key}" in app.tools.git.capture(["log", "-1", "--oneline"])
5050

5151

52-
def test_author_details_from_system(app: Application, set_system_git_author: None) -> None: # noqa: ARG001
52+
def test_author_details(app: Application, set_git_author: None) -> None: # noqa: ARG001
5353
clear_cached_config(app)
5454
assert app.tools.git.author_name == "Test Runner"
5555
assert app.tools.git.author_email == "test.runner@example.com"
5656

5757

58-
def test_author_details_inherit(app: Application, set_inherit_git_author: None) -> None: # noqa: ARG001
59-
clear_cached_config(app)
60-
assert app.tools.git.author_name == app.config.user.name
61-
assert app.tools.git.author_email == app.config.user.emails[0]
62-
63-
6458
def test_get_remote_details(app: Application, temp_repo_with_remote: Path) -> None:
6559
with temp_repo_with_remote.as_cwd():
6660
assert app.tools.git.get_remote_details() == ("foo", "bar", "https://github.com/foo/bar")
@@ -77,7 +71,9 @@ def test_get_head_commit(
7771

7872

7973
def test_get_commit_details(
80-
app: Application, temp_repo: Path, create_commit_dummy_file: Callable[[Path | str, str, str], None]
74+
app: Application,
75+
temp_repo: Path,
76+
create_commit_dummy_file: Callable[[Path | str, str, str], None],
8177
) -> None:
8278
with temp_repo.as_cwd():
8379
create_commit_dummy_file("dummy", "dummy content", "Initial commit")

0 commit comments

Comments
 (0)