Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/lang/zh-CN/

## [Unreleased]

### Added

- 在 Noneflow 工作流评论处增设 Noneflow 运行历史

## [4.3.1] - 2025-05-10

### Fixed
Expand Down
37 changes: 25 additions & 12 deletions src/plugins/github/handlers/github.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from githubkit.rest import PullRequestSimple
from githubkit.typing import Missing
from githubkit.utils import UNSET
from githubkit.versions.latest.models import IssueComment
from nonebot import logger
from nonebot.adapters.github import Bot
from pydantic import ConfigDict
Expand Down Expand Up @@ -69,22 +70,34 @@ async def update_comment(self, comment_id: int, comment: str):
**self.repo_info.model_dump(), comment_id=comment_id, body=comment
)

async def comment_issue(self, comment: str, issue_number: int):
"""发布评论,若之前已评论过,则会进行复用"""
logger.info("开始发布评论")

# 重复利用评论
# 如果发现之前评论过,直接修改之前的评论
comments = await self.list_comments(issue_number=issue_number)
reusable_comment = next(
async def get_self_comment(self, issue_number: int):
"""获取自己的评论"""
comments: list[IssueComment] = await self.list_comments(
issue_number=issue_number
)
return next(
filter(lambda x: NONEFLOW_MARKER in (x.body if x.body else ""), comments),
None,
)

if reusable_comment:
logger.info(f"发现已有评论 {reusable_comment.id},正在修改")
if reusable_comment.body != comment:
await self.update_comment(reusable_comment.id, comment)
async def resuable_comment_issue(
self, comment: str, issue_number: int
) -> IssueComment | None:
"""复用评论,若之前已评论过,则会进行复用"""
logger.info("查询已有评论")
self_comment = await self.get_self_comment(issue_number=issue_number)
await self.comment_issue(comment, issue_number, self_comment)

async def comment_issue(
self, comment: str, issue_number: int, self_comment: IssueComment | None = None
):
"""发布评论"""
logger.info("开始发布评论")

if self_comment:
logger.info(f"发现已有评论 {self_comment.id},正在修改")
if self_comment.body != comment:
await self.update_comment(self_comment.id, comment)
logger.info("评论修改完成")
else:
logger.info("评论内容无变化,跳过修改")
Expand Down
23 changes: 21 additions & 2 deletions src/plugins/github/handlers/issue.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,31 @@ async def list_comments(self, issue_number: int | None = None):

return await super().list_comments(issue_number)

async def comment_issue(self, comment: str, issue_number: int | None = None):
async def get_self_comment(self, issue_number: int | None = None):
"""获取自己的评论"""
if issue_number is None:
issue_number = self.issue_number

return await super().get_self_comment(issue_number)

async def comment_issue(
self, comment: str, issue_number: int | None = None, self_comment=None
):
"""发布评论"""
if issue_number is None:
issue_number = self.issue_number

await super().comment_issue(comment, issue_number, self_comment)

async def resuable_comment_issue(
self, comment: str, issue_number: int | None = None
):
"""发布评论,若之前已评论过,则会进行复用"""
if issue_number is None:
issue_number = self.issue_number

await super().comment_issue(comment, issue_number)
self_comment = await self.get_self_comment(issue_number)
await self.comment_issue(comment, issue_number, self_comment)

def commit_and_push(
self,
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/github/plugins/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ async def handle_remove_check(
comment = await render_comment(result, True)

# 对议题评论
await handler.comment_issue(comment)
await handler.resuable_comment_issue(comment)

branch_name = f"{BRANCH_NAME_PREFIX}{handler.issue_number}"

Expand Down
16 changes: 13 additions & 3 deletions src/plugins/github/plugins/publish/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Literal
from typing import TYPE_CHECKING, Literal

from nonebot import logger, on_type
from nonebot.adapters.github import (
Expand Down Expand Up @@ -39,6 +39,7 @@
ensure_issue_content,
ensure_issue_plugin_test_button,
ensure_issue_plugin_test_button_in_progress,
get_history_workflow_from_comment,
process_pull_request,
trigger_registry_update,
)
Expand All @@ -48,6 +49,9 @@
validate_plugin_info_from_issue,
)

if TYPE_CHECKING:
from datetime import datetime


async def check_rule(
event: IssuesOpened | IssuesReopened | IssuesEdited | IssueCommentCreated,
Expand Down Expand Up @@ -153,11 +157,17 @@ async def handle_pull_request_and_update_issue(
installation_id: int = Depends(get_installation_id),
) -> None:
async with bot.as_installation(installation_id):
self_comment = await handler.get_self_comment(handler.issue_number)

history: list[tuple[bool, str, datetime]] = []
if self_comment and self_comment.body:
history = await get_history_workflow_from_comment(self_comment.body)

# 渲染评论信息
comment = await render_comment(validation, True)
comment = await render_comment(validation, True, history)

# 对议题评论
await handler.comment_issue(comment)
await handler.comment_issue(comment, self_comment=self_comment)

# 设置拉取请求与议题的标题
# 限制标题长度,过长的标题不好看
Expand Down
7 changes: 7 additions & 0 deletions src/plugins/github/plugins/publish/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@
ADAPTER_MODULE_NAME_PATTERN = re.compile(ISSUE_PATTERN.format("适配器 import 包名"))
ADAPTER_HOMEPAGE_PATTERN = re.compile(ISSUE_PATTERN.format("适配器项目仓库/主页链接"))


WORKFLOW_HISTORY_PATTERN = re.compile(
r'<li>(⚠️|✅)\s*<a href="(https://github\.com/nonebot/nonebot2/actions/runs/\d+)">([^<]+?CST)</a>。</li>'
)

WORKFLOW_HISTORY_TEMPLATE = """<li>{status} <a href="{url}">{time}</a>。</li>"""

# 评论卡片模板
COMMENT_CARD_TEMPLATE = """[![{name}](https://img.shields.io/badge/{head}-{content}-{color}?style=for-the-badge)]({url})"""

Expand Down
28 changes: 27 additions & 1 deletion src/plugins/github/plugins/publish/render.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ def format_time(time: str) -> str:
return dt.strftime("%Y-%m-%d %H:%M:%S %Z")


def format_datetime(dt: datetime) -> str:
"""格式化 datetime 对象为字符串"""
dt = dt.astimezone(tz=TIME_ZONE)
return dt.strftime("%Y-%m-%d %H:%M:%S %Z")


env = jinja2.Environment(
loader=jinja2.FileSystemLoader(Path(__file__).parent / "templates"),
enable_async=True,
Expand All @@ -63,14 +69,21 @@ def format_time(time: str) -> str:
env.filters["loc_to_name"] = loc_to_name
env.filters["key_to_name"] = key_to_name
env.filters["format_time"] = format_time
env.filters["format_datetime"] = format_datetime


async def render_comment(result: ValidationDict, reuse: bool = False) -> str:
async def render_comment(
result: ValidationDict,
reuse: bool = False,
history: list[tuple[bool, str, datetime]] | None = None,
) -> str:
"""将验证结果转换为评论内容"""
title = f"{result.type}: {result.name}"

valid_data = result.valid_data.copy()

history = history or []

if result.type == PublishType.PLUGIN:
# https://github.com/he0119/action-test/actions/runs/4469672520
# 仅在测试通过或跳过测试时显示
Expand Down Expand Up @@ -119,6 +132,18 @@ async def render_comment(result: ValidationDict, reuse: bool = False) -> str:
url=action_url,
)
)
history.append(
Comment thread
he0119 marked this conversation as resolved.
(
result.valid,
action_url,
datetime.now(tz=TIME_ZONE),
)
)

# 测试历史应该时间倒序排列
history.sort(key=lambda x: x[2], reverse=True)
# 限制最多显示 10 条历史
history = history[:10]

template = env.get_template("comment.md.jinja")
return await template.render_async(
Expand All @@ -127,6 +152,7 @@ async def render_comment(result: ValidationDict, reuse: bool = False) -> str:
title=title,
valid=result.valid,
data=data,
history=history,
errors=result.errors,
skip_test=result.skip_test,
)
Expand Down
11 changes: 11 additions & 0 deletions src/plugins/github/plugins/publish/templates/comment.md.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,17 @@
</details>
{% endif %}

{%- if history %}
<details>
<summary>历史测试</summary>
<pre><code>
{%- for status, action_url, time in history%}
<li>{{"✅" if status else "⚠️"}} <a href={{action_url}}>{{time|format_datetime}}</li>
{%- endfor %}
</code></pre>
</details>
{% endif %}

---

💡 如需修改信息,请直接修改 issue,机器人会自动更新检查结果。
Expand Down
17 changes: 17 additions & 0 deletions src/plugins/github/plugins/publish/utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import re
from datetime import datetime

from githubkit.exception import RequestFailed
from nonebot import logger
Expand All @@ -13,6 +14,7 @@
from src.plugins.github.handlers import GithubHandler, IssueHandler
from src.plugins.github.typing import PullRequestList
from src.plugins.github.utils import commit_message as _commit_message
from src.providers.constants import TIME_ZONE
from src.providers.models import RegistryUpdatePayload, to_store
from src.providers.utils import dump_json5, load_json_from_file
from src.providers.validation import PublishType, ValidationDict
Expand All @@ -25,6 +27,7 @@
PLUGIN_TEST_BUTTON_STRING,
PLUGIN_TEST_PATTERN,
PLUGIN_TEST_STRING,
WORKFLOW_HISTORY_PATTERN,
)
from .validation import (
validate_adapter_info_from_issue,
Expand Down Expand Up @@ -277,3 +280,17 @@ async def trigger_registry_update(handler: IssueHandler, publish_type: PublishTy
repo=plugin_config.input_config.registry_repository,
)
logger.info("已触发商店列表更新")


async def get_history_workflow_from_comment(
comment: str,
) -> list[tuple[bool, str, datetime]]:
"""获取历史工作流"""
return [
(
status == "✅",
action_url,
datetime.strptime(time, "%Y-%m-%d %H:%M:%S CST").replace(tzinfo=TIME_ZONE),
)
for status, action_url, time in WORKFLOW_HISTORY_PATTERN.findall(comment)
]
4 changes: 2 additions & 2 deletions src/plugins/github/plugins/remove/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ async def handle_remove_check(
result = await validate_author_info(handler.issue, publish_type)
except PydanticCustomError as err:
logger.error(f"信息验证失败: {err}")
await handler.comment_issue(await render_error(err))
await handler.resuable_comment_issue(await render_error(err))
await remove_check_matcher.finish()

title = f"{result.publish_type}: Remove {result.name or 'Unknown'}"[
Expand All @@ -113,7 +113,7 @@ async def handle_remove_check(
result,
f"{plugin_config.input_config.store_repository}#{pull_number}",
)
await handler.comment_issue(comment)
await handler.resuable_comment_issue(comment)


async def review_submitted_rule(
Expand Down
2 changes: 1 addition & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ def datetime_modules_loc() -> list[str]:
return find_datetime_loc(PROJECT_SOURCE_PATH)


@pytest.fixture
@pytest.fixture(autouse=True)
def mock_datetime(mocker: MockerFixture, datetime_modules_loc: list[str]):
"""
将所有模块中的 datetime.now() 方法返回值固定
Expand Down
5 changes: 4 additions & 1 deletion tests/plugins/github/config/process/test_config_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ async def test_process_config_check(
tmp_path: Path,
mock_installation,
mock_results: dict[str, Path],
mock_datetime,
) -> None:
"""测试发布检查不通过"""
from src.providers.docker_test import Metadata
Expand Down Expand Up @@ -146,6 +145,10 @@ async def test_process_config_check(
<summary>详情</summary>
<pre><code><li>✅ 项目 <a href="https://nonebot.dev">主页</a> 返回状态码 200。</li><li>✅ 项目 <a href="https://pypi.org/project/nonebot-plugin-treehelp/">nonebot-plugin-treehelp</a> 已发布至 PyPI。</li><li>✅ 标签: test-#ffffff。</li><li>✅ 插件类型: application。</li><li>✅ 插件支持的适配器: nonebot.adapters.onebot.v11。</li><li>✅ 插件 <a href="https://github.com/owner/repo/actions/runs/123456">加载测试</a> 通过。</li><li>✅ 版本号: 1.0.0。</li><li>✅ 发布时间:2024-07-13 12:41:40 CST。</li></code></pre>
</details>
<details>
<summary>历史测试</summary>
<pre><code><li>✅ <a href=https://github.com/owner/repo/actions/runs/123456>2023-08-23 09:22:14 CST</li></code></pre>
</details>

---

Expand Down
6 changes: 1 addition & 5 deletions tests/plugins/github/config/utils/test_config_update_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,7 @@


async def test_update_file(
app: App,
mocker: MockerFixture,
tmp_path: Path,
mock_results: dict[str, Path],
mock_datetime,
app: App, mocker: MockerFixture, tmp_path: Path, mock_results: dict[str, Path]
) -> None:
from src.plugins.github.plugins.config.utils import update_file
from src.providers.validation.models import (
Expand Down
Loading
Loading