Skip to content

Commit 03731a9

Browse files
committed
feat: 商店存放 json5 格式的数据
避免合并冲突
1 parent 77759c4 commit 03731a9

File tree

18 files changed

+127
-93
lines changed

18 files changed

+127
-93
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/lang/zh-CN/
1010
### Added
1111

1212
- 通过名称加主页避免机器人重复
13+
- 商店存放 json5 格式的数据
1314

1415
### Fixed
1516

src/plugins/github/plugins/publish/utils.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010
from src.plugins.github.models import IssueHandler
1111
from src.plugins.github.models.github import GithubHandler
1212
from src.plugins.github.utils import commit_message as _commit_message
13-
from src.plugins.github.utils import dump_json, load_json, run_shell_command
13+
from src.plugins.github.utils import run_shell_command
1414
from src.providers.models import RegistryUpdatePayload, to_store
15+
from src.providers.utils import dump_json5, load_json5_from_file
1516
from src.providers.validation import PublishType, ValidationDict
1617

1718
from .constants import (
@@ -149,9 +150,9 @@ def update_file(result: ValidationDict) -> None:
149150

150151
logger.info(f"正在更新文件: {path}")
151152

152-
data = load_json(path)
153+
data = load_json5_from_file(path)
153154
data.append(new_data)
154-
dump_json(path, data, 2)
155+
dump_json5(path, data)
155156

156157
logger.info("文件更新完成")
157158

src/plugins/github/plugins/remove/utils.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,8 @@
99
get_type_by_labels,
1010
)
1111
from src.plugins.github.models import GithubHandler, IssueHandler
12-
from src.plugins.github.utils import (
13-
commit_message,
14-
dump_json,
15-
run_shell_command,
16-
)
12+
from src.plugins.github.utils import commit_message, run_shell_command
13+
from src.providers.utils import dump_json5
1714
from src.providers.validation.models import PublishType
1815

1916
from .constants import COMMIT_MESSAGE_PREFIX, REMOVE_LABEL
@@ -40,7 +37,7 @@ def update_file(type: PublishType, key: str):
4037
data = load_publish_data(type)
4138
# 删除对应的数据项
4239
data.pop(key)
43-
dump_json(path, list(data.values()))
40+
dump_json5(path, list(data.values()))
4441
logger.info(f"已更新 {path.name} 文件")
4542

4643

src/plugins/github/plugins/remove/validation.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44

55
from src.plugins.github import plugin_config
66
from src.plugins.github.models import AuthorInfo
7-
from src.plugins.github.utils import extract_issue_info_from_issue, load_json
7+
from src.plugins.github.utils import extract_issue_info_from_issue
88
from src.providers.constants import BOT_KEY_TEMPLATE, PYPI_KEY_TEMPLATE
9+
from src.providers.utils import load_json5_from_file
910
from src.providers.validation.models import PublishType
1011

1112
from .constants import (
@@ -25,23 +26,27 @@ def load_publish_data(publish_type: PublishType):
2526
project_link=adapter["project_link"],
2627
module_name=adapter["module_name"],
2728
): adapter
28-
for adapter in load_json(plugin_config.input_config.adapter_path)
29+
for adapter in load_json5_from_file(
30+
plugin_config.input_config.adapter_path
31+
)
2932
}
3033
case PublishType.BOT:
3134
return {
3235
BOT_KEY_TEMPLATE.format(
3336
name=bot["name"],
3437
homepage=bot["homepage"],
3538
): bot
36-
for bot in load_json(plugin_config.input_config.bot_path)
39+
for bot in load_json5_from_file(plugin_config.input_config.bot_path)
3740
}
3841
case PublishType.PLUGIN:
3942
return {
4043
PYPI_KEY_TEMPLATE.format(
4144
project_link=plugin["project_link"],
4245
module_name=plugin["module_name"],
4346
): plugin
44-
for plugin in load_json(plugin_config.input_config.plugin_path)
47+
for plugin in load_json5_from_file(
48+
plugin_config.input_config.plugin_path
49+
)
4550
}
4651
case PublishType.DRIVER:
4752
raise ValueError("不支持的删除类型")

src/plugins/github/utils.py

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
1-
import json
21
import subprocess
3-
from pathlib import Path
42
from re import Pattern
5-
from typing import Any
63

74
from nonebot import logger
8-
from pydantic_core import to_jsonable_python
95

106

117
def run_shell_command(command: list[str]):
@@ -30,20 +26,6 @@ def commit_message(prefix: str, message: str, issue_number: int):
3026
return f"{prefix} {message} (#{issue_number})"
3127

3228

33-
def load_json(path: Path) -> list[dict[str, str]]:
34-
"""加载 JSON 文件"""
35-
with path.open("r", encoding="utf-8") as f:
36-
return json.load(f)
37-
38-
39-
def dump_json(path: Path, data: Any, indent: int = 4):
40-
"""保存 JSON 文件"""
41-
with path.open("w", encoding="utf-8") as f:
42-
# 结尾加上换行符,不然会被 pre-commit fix
43-
json.dump(to_jsonable_python(data), f, ensure_ascii=False, indent=indent)
44-
f.write("\n")
45-
46-
4729
def extract_issue_info_from_issue(
4830
patterns: dict[str, Pattern[str]], body: str
4931
) -> dict[str, str | None]:

src/providers/store_test/store.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
StorePlugin,
2727
StoreTestResult,
2828
)
29+
from src.providers.utils import dump_json, load_json5_from_web, load_json_from_web
2930
from src.providers.validation.utils import get_author_name
3031

3132
from .constants import (
@@ -36,7 +37,7 @@
3637
PLUGINS_PATH,
3738
RESULTS_PATH,
3839
)
39-
from .utils import dump_json, get_latest_version, load_json
40+
from .utils import get_latest_version
4041
from .validation import validate_plugin
4142

4243
print = click.echo
@@ -52,63 +53,65 @@ def __init__(self) -> None:
5253
project_link=adapter["project_link"],
5354
module_name=adapter["module_name"],
5455
): StoreAdapter(**adapter)
55-
for adapter in load_json(STORE_ADAPTERS_URL)
56+
for adapter in load_json5_from_web(STORE_ADAPTERS_URL)
5657
}
5758
self._store_bots: dict[str, StoreBot] = {
5859
BOT_KEY_TEMPLATE.format(
5960
name=bot["name"],
6061
homepage=bot["homepage"],
6162
): StoreBot(**bot)
62-
for bot in load_json(STORE_BOTS_URL)
63+
for bot in load_json5_from_web(STORE_BOTS_URL)
6364
}
6465
self._store_drivers: dict[str, StoreDriver] = {
6566
PYPI_KEY_TEMPLATE.format(
6667
project_link=driver["project_link"],
6768
module_name=driver["module_name"],
6869
): StoreDriver(**driver)
69-
for driver in load_json(STORE_DRIVERS_URL)
70+
for driver in load_json5_from_web(STORE_DRIVERS_URL)
7071
}
7172
self._store_plugins: dict[str, StorePlugin] = {
7273
PYPI_KEY_TEMPLATE.format(
7374
project_link=plugin["project_link"],
7475
module_name=plugin["module_name"],
7576
): StorePlugin(**plugin)
76-
for plugin in load_json(STORE_PLUGINS_URL)
77+
for plugin in load_json5_from_web(STORE_PLUGINS_URL)
7778
}
7879
# 上次测试的结果
7980
self._previous_results: dict[str, StoreTestResult] = {
8081
key: StoreTestResult(**value)
81-
for key, value in load_json(REGISTRY_RESULTS_URL).items()
82+
for key, value in load_json_from_web(REGISTRY_RESULTS_URL).items()
8283
}
8384
self._previous_adapters: dict[str, RegistryAdapter] = {
8485
PYPI_KEY_TEMPLATE.format(
8586
project_link=adapter["project_link"],
8687
module_name=adapter["module_name"],
8788
): RegistryAdapter(**adapter)
88-
for adapter in load_json(REGISTRY_ADAPTERS_URL)
89+
for adapter in load_json_from_web(REGISTRY_ADAPTERS_URL)
8990
}
9091
self._previous_bots: dict[str, RegistryBot] = {
9192
BOT_KEY_TEMPLATE.format(
9293
name=bot["name"],
9394
homepage=bot["homepage"],
9495
): RegistryBot(**bot)
95-
for bot in load_json(url=REGISTRY_BOTS_URL)
96+
for bot in load_json_from_web(url=REGISTRY_BOTS_URL)
9697
}
9798
self._previous_drivers: dict[str, RegistryDriver] = {
9899
PYPI_KEY_TEMPLATE.format(
99100
project_link=driver["project_link"],
100101
module_name=driver["module_name"],
101102
): RegistryDriver(**driver)
102-
for driver in load_json(REGISTRY_DRIVERS_URL)
103+
for driver in load_json_from_web(REGISTRY_DRIVERS_URL)
103104
}
104105
self._previous_plugins: dict[str, RegistryPlugin] = {
105106
PYPI_KEY_TEMPLATE.format(
106107
project_link=plugin["project_link"], module_name=plugin["module_name"]
107108
): RegistryPlugin(**plugin)
108-
for plugin in load_json(REGISTRY_PLUGINS_URL)
109+
for plugin in load_json_from_web(REGISTRY_PLUGINS_URL)
109110
}
110111
# 插件配置文件
111-
self._plugin_configs: dict[str, str] = load_json(REGISTRY_PLUGIN_CONFIG_URL)
112+
self._plugin_configs: dict[str, str] = load_json_from_web(
113+
REGISTRY_PLUGIN_CONFIG_URL
114+
)
112115

113116
def should_skip(self, key: str, force: bool = False) -> bool:
114117
"""是否跳过测试"""

src/providers/store_test/utils.py

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,9 @@
1-
import json
21
from functools import cache
3-
from pathlib import Path
42
from typing import Any
53

64
import httpx
7-
from pydantic_core import to_jsonable_python
85

9-
10-
def load_json(url: str) -> Any:
11-
"""从网络加载 JSON 文件"""
12-
r = httpx.get(url)
13-
if r.status_code != 200:
14-
raise ValueError(f"下载文件失败:{r.text}")
15-
return r.json()
16-
17-
18-
def dump_json(path: Path, data: Any, minify: bool = True) -> None:
19-
"""保存 JSON 文件
20-
21-
为减少文件大小,还需手动设置 separators
22-
"""
23-
data = to_jsonable_python(data)
24-
with open(path, "w", encoding="utf-8") as f:
25-
if minify:
26-
json.dump(data, f, ensure_ascii=False, separators=(",", ":"))
27-
else:
28-
json.dump(data, f, ensure_ascii=False, indent=2)
6+
from src.providers.utils import load_json_from_web
297

308

319
@cache
@@ -55,5 +33,5 @@ def get_upload_time(project_link: str) -> str:
5533

5634
def get_user_id(name: str) -> int:
5735
"""获取用户信息"""
58-
data = load_json(f"https://api.github.com/users/{name}")
36+
data = load_json_from_web(f"https://api.github.com/users/{name}")
5937
return data["id"]

src/providers/utils.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import json
2+
from pathlib import Path
3+
from typing import Any
4+
5+
import httpx
6+
import json5
7+
from pydantic_core import to_jsonable_python
8+
9+
10+
def load_json_from_file(file_path: Path):
11+
"""从文件加载 JSON 文件"""
12+
with open(file_path, encoding="utf-8") as file:
13+
return json.load(file)
14+
15+
16+
def load_json_from_web(url: str):
17+
"""从网络加载 JSON 文件"""
18+
r = httpx.get(url)
19+
if r.status_code != 200:
20+
raise ValueError(f"下载文件失败:{r.text}")
21+
return r.json()
22+
23+
24+
def dump_json(path: Path, data: Any, minify: bool = True) -> None:
25+
"""保存 JSON 文件
26+
27+
为减少文件大小,还需手动设置 separators
28+
"""
29+
data = to_jsonable_python(data)
30+
with open(path, "w", encoding="utf-8") as f:
31+
if minify:
32+
json.dump(data, f, ensure_ascii=False, separators=(",", ":"))
33+
else:
34+
json.dump(data, f, ensure_ascii=False, indent=2)
35+
36+
37+
def load_json5_from_file(file_path: Path):
38+
"""从文件加载 JSON5 文件"""
39+
with open(file_path, encoding="utf-8") as file:
40+
return json5.load(file)
41+
42+
43+
def load_json5_from_web(url: str):
44+
"""从网络加载 JSON5 文件"""
45+
r = httpx.get(url)
46+
if r.status_code != 200:
47+
raise ValueError(f"下载文件失败:{r.text}")
48+
return json5.loads(r.text)
49+
50+
51+
def dump_json5(path: Path, data: Any) -> None:
52+
"""保存 JSON5 文件
53+
54+
手动添加末尾的逗号和换行符
55+
"""
56+
data = to_jsonable_python(data)
57+
58+
content = json.dumps(data, ensure_ascii=False, indent=2)
59+
# 手动添加末尾的逗号和换行符
60+
# 避免合并时出现冲突
61+
content = content.replace("}\n]", "},\n]\n")
62+
63+
with open(path, "w", encoding="utf-8") as f:
64+
f.write(content)

tests/conftest.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import json
21
from pathlib import Path
32
from typing import TYPE_CHECKING
43

54
import httpx
5+
import json5
66
import nonebot
77
import pytest
88
from nonebot.adapters.github import Adapter
@@ -49,7 +49,7 @@ async def app(app: App, tmp_path: Path, mocker: MockerFixture):
4949

5050
adapter_path = tmp_path / "adapters.json"
5151
with adapter_path.open("w") as f:
52-
json.dump(
52+
json5.dump(
5353
[
5454
{
5555
"module_name": "module_name1",
@@ -66,7 +66,7 @@ async def app(app: App, tmp_path: Path, mocker: MockerFixture):
6666
)
6767
bot_path = tmp_path / "bots.json"
6868
with bot_path.open("w") as f:
69-
json.dump(
69+
json5.dump(
7070
[
7171
{
7272
"name": "name",
@@ -81,7 +81,7 @@ async def app(app: App, tmp_path: Path, mocker: MockerFixture):
8181
)
8282
plugin_path = tmp_path / "plugins.json"
8383
with plugin_path.open("w") as f:
84-
json.dump(
84+
json5.dump(
8585
[
8686
{
8787
"module_name": "module_name1",

tests/github/publish/utils/test_publish_resolve_conflict_pull_requests.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
import json
22
from pathlib import Path
3-
from typing import Any
43

54
import pytest
65
from inline_snapshot import snapshot
76
from nonebug import App
87
from pytest_mock import MockerFixture
98
from respx import MockRouter
109

11-
from tests.github.utils import MockBody, MockIssue, MockUser, get_github_bot
12-
13-
14-
def check_json_data(file: Path, data: Any) -> None:
15-
with open(file, encoding="utf-8") as f:
16-
assert json.load(f) == data
10+
from tests.github.utils import (
11+
MockBody,
12+
MockIssue,
13+
MockUser,
14+
check_json_data,
15+
get_github_bot,
16+
)
1717

1818

1919
@pytest.fixture

0 commit comments

Comments
 (0)