Enhance user configuration management and logging

- Introduced user configuration command to set API key.
- Updated README and documentation for user config and logging paths.
- Refactored logging to support user-specific log files.
- Added tests for user configuration and logging behavior.
This commit is contained in:
2026-06-27 10:21:00 +08:00
parent 0e98ce57d4
commit 4685a0165d
10 changed files with 434 additions and 25 deletions

View File

@@ -1,10 +1,16 @@
from __future__ import annotations
import json
import shutil
from pathlib import Path
from nexus_claude_api.cli import main
from nexus_claude_api.config import Settings, load_local_config
from nexus_claude_api.config import (
Settings,
load_local_config,
load_user_config,
write_user_config,
)
from nexus_claude_api.shell import generate_claude_code_powershell
@@ -41,6 +47,8 @@ def test_claude_code_command_uses_custom_model() -> None:
def test_missing_api_key_fails(monkeypatch) -> None:
tmp_path = _workspace_tmp("missing-key")
user_config = tmp_path / ".config" / "nexus-claude-api" / "config.json"
monkeypatch.setattr("nexus_claude_api.config.USER_CONFIG_FILE", user_config)
monkeypatch.delenv("NEXUS_API_KEY", raising=False)
monkeypatch.delenv("AWS_BEARER_TOKEN_BEDROCK", raising=False)
monkeypatch.chdir(tmp_path)
@@ -54,8 +62,43 @@ def test_missing_api_key_fails(monkeypatch) -> None:
assert exit_code == 2
def test_local_config_api_key(monkeypatch) -> None:
tmp_path = _workspace_tmp("local-config")
def test_user_config_api_key(monkeypatch) -> None:
tmp_path = _workspace_tmp("user-config")
user_config = tmp_path / ".config" / "nexus-claude-api" / "config.json"
monkeypatch.setattr("nexus_claude_api.config.USER_CONFIG_FILE", user_config)
write_user_config({"api_key": "user-test-key"})
settings = Settings.from_values(require_api_key=False)
assert settings.api_key == "user-test-key"
assert load_user_config()["api_key"] == "user-test-key"
shutil.rmtree(tmp_path, ignore_errors=True)
def test_dev_local_config_api_key(monkeypatch) -> None:
tmp_path = _workspace_tmp("dev-local-config")
monkeypatch.chdir(tmp_path)
(tmp_path / "nexus-claude-api.local.json").write_text(
'{"api_key": "local-test-key"}',
encoding="utf-8",
)
try:
settings = Settings.from_values(require_api_key=False, dev=True)
assert settings.api_key == "local-test-key"
assert load_local_config()["api_key"] == "local-test-key"
finally:
monkeypatch.chdir(Path(__file__).parents[1])
shutil.rmtree(tmp_path, ignore_errors=True)
def test_default_mode_ignores_local_config(monkeypatch) -> None:
tmp_path = _workspace_tmp("default-ignores-local")
user_config = tmp_path / ".config" / "nexus-claude-api" / "config.json"
monkeypatch.setattr("nexus_claude_api.config.USER_CONFIG_FILE", user_config)
monkeypatch.delenv("NEXUS_API_KEY", raising=False)
monkeypatch.delenv("AWS_BEARER_TOKEN_BEDROCK", raising=False)
monkeypatch.chdir(tmp_path)
(tmp_path / "nexus-claude-api.local.json").write_text(
'{"api_key": "local-test-key"}',
@@ -65,13 +108,51 @@ def test_local_config_api_key(monkeypatch) -> None:
try:
settings = Settings.from_values(require_api_key=False)
assert settings.api_key == "local-test-key"
assert load_local_config()["api_key"] == "local-test-key"
assert settings.api_key is None
finally:
monkeypatch.chdir(Path(__file__).parents[1])
shutil.rmtree(tmp_path, ignore_errors=True)
def test_api_key_precedence_config_before_environment(monkeypatch) -> None:
tmp_path = _workspace_tmp("config-precedence")
user_config = tmp_path / ".config" / "nexus-claude-api" / "config.json"
monkeypatch.setattr("nexus_claude_api.config.USER_CONFIG_FILE", user_config)
monkeypatch.setenv("NEXUS_API_KEY", "env-key")
write_user_config({"api_key": "config-key"})
settings = Settings.from_values(require_api_key=False)
assert settings.api_key == "config-key"
shutil.rmtree(tmp_path, ignore_errors=True)
def test_api_key_argument_overrides_config(monkeypatch) -> None:
tmp_path = _workspace_tmp("arg-precedence")
user_config = tmp_path / ".config" / "nexus-claude-api" / "config.json"
monkeypatch.setattr("nexus_claude_api.config.USER_CONFIG_FILE", user_config)
write_user_config({"api_key": "config-key"})
settings = Settings.from_values(api_key="arg-key", require_api_key=False)
assert settings.api_key == "arg-key"
shutil.rmtree(tmp_path, ignore_errors=True)
def test_config_set_writes_user_config(monkeypatch) -> None:
tmp_path = _workspace_tmp("config-set")
user_config = tmp_path / ".config" / "nexus-claude-api" / "config.json"
monkeypatch.setattr("nexus_claude_api.config.USER_CONFIG_FILE", user_config)
exit_code = main(["config", "set", "--api-key", "written-key"])
assert exit_code == 0
assert json.loads(user_config.read_text(encoding="utf-8")) == {
"api_key": "written-key"
}
shutil.rmtree(tmp_path, ignore_errors=True)
def _workspace_tmp(name: str) -> Path:
path = Path(__file__).parents[1] / ".test-tmp" / name
shutil.rmtree(path, ignore_errors=True)