feat: switch config to JSONC + split secrets.json
Load business config as JSONC (comments + trailing commas) via an in-repo stripper then stdlib json — no new deps. Default path prefers config.jsonc, falls back to legacy config.json. Auth write-back targets only sibling secrets.json so JSONC comments are never wiped; secrets overlay merges on load. Examples, compose, Docker, docs, favsort and tools all share the same loader. Phase A only — no DB settings migration.
This commit was merged in pull request #4.
This commit is contained in:
1 parent
b4f0f45c4e
commit
8e7ead1669
21 files changed
+652
-182
No files matched your search
+83
-2
@@ -11,7 +11,13 @@ from pathlib import Path
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
|
||||
from reaction_board.config import ConfigError, ConfigStore, load_config # noqa: E402
|
||||
from reaction_board.config import ( # noqa: E402
|
||||
ConfigError,
|
||||
ConfigStore,
|
||||
default_config_path,
|
||||
load_config,
|
||||
resolve_secrets_path,
|
||||
)
|
||||
|
||||
|
||||
def write(path: Path, data) -> None:
|
||||
@@ -294,6 +300,78 @@ def test_schedule_recent_validation():
|
||||
|
||||
|
||||
|
||||
|
||||
def test_jsonc_and_secrets_merge_and_hot_reload():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
config_path = root / "config.jsonc"
|
||||
secrets_path = root / "secrets.json"
|
||||
config_path.write_text(
|
||||
"""
|
||||
// 业务配置
|
||||
{
|
||||
"folders": [
|
||||
{"year": 2026, "media_id": 1, "title": "A"},
|
||||
],
|
||||
"track_fans": [],
|
||||
"up_blacklist_seed": [],
|
||||
"telegram": { "enabled": true },
|
||||
"web": { "host": "127.0.0.1", "port": 8080 },
|
||||
}
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
secrets_path.write_text(json.dumps({
|
||||
"bilibili": {
|
||||
"read": {"mid": 11, "csrf": "rc", "cookie": "rk"},
|
||||
"write": {"mid": 22, "csrf": "wc", "cookie": "wk"},
|
||||
},
|
||||
"telegram": {"bot_token": "tok", "chat_id": 9},
|
||||
"web": {"auth_token": "secret-token"},
|
||||
}), encoding="utf-8")
|
||||
|
||||
cfg = load_config(config_path, env={})
|
||||
assert cfg.secrets_path == secrets_path
|
||||
assert cfg.bilibili.read.cookie == "rk"
|
||||
assert cfg.telegram.enabled is True
|
||||
assert cfg.telegram.bot_token == "tok"
|
||||
assert cfg.telegram.chat_id == 9
|
||||
assert cfg.web.auth_token == "secret-token"
|
||||
assert resolve_secrets_path(config_path) == secrets_path
|
||||
|
||||
# 主配置注释在热更新凭据后仍保留
|
||||
original = config_path.read_text(encoding="utf-8")
|
||||
store = ConfigStore(config_path, env={})
|
||||
secrets = json.loads(secrets_path.read_text(encoding="utf-8"))
|
||||
secrets["bilibili"]["read"]["cookie"] = "rk2"
|
||||
secrets_path.write_text(json.dumps(secrets), encoding="utf-8")
|
||||
bump_mtime(secrets_path)
|
||||
assert store.get().bilibili.read.cookie == "rk2"
|
||||
assert config_path.read_text(encoding="utf-8") == original
|
||||
assert "// 业务配置" in original
|
||||
|
||||
|
||||
def test_legacy_monolithic_json_still_loads():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
path = Path(tmp) / "config.json"
|
||||
write(path, base_config())
|
||||
cfg = load_config(path, env={})
|
||||
assert cfg.bilibili.read.mid == 11
|
||||
assert cfg.secrets_path == Path(tmp) / "secrets.json"
|
||||
|
||||
|
||||
def test_default_config_path_prefers_jsonc():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
json_path = root / "config.json"
|
||||
jsonc_path = root / "config.jsonc"
|
||||
json_path.write_text("{}", encoding="utf-8")
|
||||
assert default_config_path(root) == json_path
|
||||
jsonc_path.write_text("{}", encoding="utf-8")
|
||||
assert default_config_path(root) == jsonc_path
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
test_dual_accounts_and_env_override()
|
||||
test_flat_and_missing_account_rejected()
|
||||
@@ -302,7 +380,10 @@ def main():
|
||||
test_analytics_defaults_and_validation()
|
||||
test_schedule_recent_validation()
|
||||
test_web_track_defaults_and_validation()
|
||||
print("OK: 双账号配置加载、拒绝 flat 格式、ENV 覆盖、热加载与 analytics/web.track 测试全部通过")
|
||||
test_jsonc_and_secrets_merge_and_hot_reload()
|
||||
test_legacy_monolithic_json_still_loads()
|
||||
test_default_config_path_prefers_jsonc()
|
||||
print("OK: 双账号配置加载、JSONC/secrets、拒绝 flat 格式、ENV 覆盖、热加载与 analytics/web.track 测试全部通过")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in new issue
Block a user