From a8f6da859008971ff1891302a3b49abefbe9af6d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 24 Jan 2026 13:11:24 +0000 Subject: [PATCH 1/5] Initial plan From 769c6110909aa6011a9969fc33e21d1157dba103 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 24 Jan 2026 13:13:52 +0000 Subject: [PATCH 2/5] Add initialization of timestamps when adding new repository Co-authored-by: HTony03 <80151962+HTony03@users.noreply.github.com> --- .../commands.py | 6 +- .../repo_activity_new.py | 59 +++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/src/nonebot_plugin_github_release_notifier/commands.py b/src/nonebot_plugin_github_release_notifier/commands.py index 6e0431e..5fc3ba6 100644 --- a/src/nonebot_plugin_github_release_notifier/commands.py +++ b/src/nonebot_plugin_github_release_notifier/commands.py @@ -90,7 +90,7 @@ async def add_repo( bot: Bot, event: GroupMessageEvent, args: Message = CommandArg() ): """Add a new repository mapping.""" - from .repo_activity_new import github + from .repo_activity_new import github, initialize_repo_timestamps command_args = args.extract_plain_text().split() if len(command_args) < 1: await bot.send(event, "Usage: repo add [group_id]") @@ -123,6 +123,10 @@ async def fetch_repo(repo: str) -> Response[FullRepository]: config.github_default_config_setting, None, False) + + # Initialize timestamps to prevent flooding on first check + await initialize_repo_timestamps(repo) + await bot.send(event, f"Added repository mapping: {group_id} -> {repo}") logger.info(f"Added repository mapping: {group_id} -> {repo}") diff --git a/src/nonebot_plugin_github_release_notifier/repo_activity_new.py b/src/nonebot_plugin_github_release_notifier/repo_activity_new.py index 25a9850..015b6cb 100644 --- a/src/nonebot_plugin_github_release_notifier/repo_activity_new.py +++ b/src/nonebot_plugin_github_release_notifier/repo_activity_new.py @@ -232,6 +232,65 @@ async def get_data( return response +async def initialize_repo_timestamps(repo: str) -> None: + """ + Initialize last_processed timestamps for a newly added repository. + + This prevents flooding by marking all existing commits/issues/PRs/releases + as already processed, so only new items created after adding the repo + will trigger notifications. + + :param repo: GitHub repository in "owner/repo" format + :type repo: str + """ + last_processed = load_last_processed() + + # Check if repo already has timestamps - if so, don't overwrite + if repo in last_processed: + logger.info(f"Repository {repo} already has timestamps, skipping initialization") + return + + timestamps = {} + current_time = datetime.now(timezone.utc).isoformat() + + # For each endpoint type, try to fetch the latest item and record its timestamp + for data_type, endpoint in [ + ("commit", "commits"), + ("issue", "issues"), + ("pull_req", "pulls"), + ("release", "releases") + ]: + try: + data = await fetch_github_data(repo, endpoint) + if data and len(data) > 0: + # Get the timestamp of the most recent item + item = data[0] + if isinstance(item, Commit): + timestamp = item.commit.author.date if item.commit.author else None + elif isinstance(item, (Issue, PullRequest, PullRequestSimple)): + timestamp = item.created_at + elif isinstance(item, Release): + timestamp = item.published_at + else: + timestamp = None + + timestamps[data_type] = timestamp.isoformat() if timestamp else current_time + else: + # No items exist, use current time + timestamps[data_type] = current_time + except Exception as e: + logger.warning( + f"Failed to fetch {endpoint} for {repo} during initialization: " + f"{e.__class__.__name__}: {e}. Using current time." + ) + timestamps[data_type] = current_time + + # Save the timestamps + last_processed[repo] = timestamps + save_last_processed(last_processed) + logger.info(f"Initialized timestamps for repository {repo} to prevent flooding") + + async def process_issues_and_prs( repo: str, owner: str, From 7d6d91dd8242831572dd2e5cbadf20a7527ab33e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 24 Jan 2026 13:15:17 +0000 Subject: [PATCH 3/5] Enhance initialization to handle issue/PR comment tracking Co-authored-by: HTony03 <80151962+HTony03@users.noreply.github.com> --- .../repo_activity_new.py | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/nonebot_plugin_github_release_notifier/repo_activity_new.py b/src/nonebot_plugin_github_release_notifier/repo_activity_new.py index 015b6cb..4229efb 100644 --- a/src/nonebot_plugin_github_release_notifier/repo_activity_new.py +++ b/src/nonebot_plugin_github_release_notifier/repo_activity_new.py @@ -252,6 +252,7 @@ async def initialize_repo_timestamps(repo: str) -> None: timestamps = {} current_time = datetime.now(timezone.utc).isoformat() + owner, repository = repo.split('/') # For each endpoint type, try to fetch the latest item and record its timestamp for data_type, endpoint in [ @@ -269,6 +270,46 @@ async def initialize_repo_timestamps(repo: str) -> None: timestamp = item.commit.author.date if item.commit.author else None elif isinstance(item, (Issue, PullRequest, PullRequestSimple)): timestamp = item.created_at + + # For issues endpoint, initialize tracking for both issues and PRs + # to prevent comment flooding + if endpoint == "issues": + for content_type in ["issues", "prs"]: + try: + # Filter to get only issues or only PRs + filtered_items = [ + i for i in data + if (content_type == "prs" and i.pull_request) or + (content_type == "issues" and not i.pull_request) + ] + + if filtered_items: + latest_filtered = filtered_items[0] + # Store the latest issue/PR ID (id=0 means tracking the latest item) + save_commit_data(repo, str(latest_filtered.id), 0, content_type) + + # Also store latest comment ID for this issue/PR if comments exist + try: + comments_resp = await github.rest.issues.async_list_comments( + owner=owner, + repo=repository, + issue_number=latest_filtered.number + ) + comments = comments_resp.parsed_data + if comments: + latest_comment = comments[-1] + save_commit_data(repo, str(latest_comment.id), latest_filtered.id, content_type) + except Exception as e: + logger.debug( + f"Could not fetch comments for {content_type[:-1]} #{latest_filtered.number} " + f"during initialization: {e.__class__.__name__}" + ) + except Exception as e: + logger.warning( + f"Failed to initialize {content_type} tracking for {repo}: " + f"{e.__class__.__name__}: {e}" + ) + elif isinstance(item, Release): timestamp = item.published_at else: @@ -291,6 +332,8 @@ async def initialize_repo_timestamps(repo: str) -> None: logger.info(f"Initialized timestamps for repository {repo} to prevent flooding") + + async def process_issues_and_prs( repo: str, owner: str, From 1e20b33b6f0dfd6bcc99cbc19ea292bf28c4be2c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 24 Jan 2026 13:17:00 +0000 Subject: [PATCH 4/5] Improve documentation and comments based on code review Co-authored-by: HTony03 <80151962+HTony03@users.noreply.github.com> --- .../repo_activity_new.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/nonebot_plugin_github_release_notifier/repo_activity_new.py b/src/nonebot_plugin_github_release_notifier/repo_activity_new.py index 4229efb..541027b 100644 --- a/src/nonebot_plugin_github_release_notifier/repo_activity_new.py +++ b/src/nonebot_plugin_github_release_notifier/repo_activity_new.py @@ -240,6 +240,12 @@ async def initialize_repo_timestamps(repo: str) -> None: as already processed, so only new items created after adding the repo will trigger notifications. + The function performs two types of initialization: + 1. Records timestamps of the latest items in the last_processed table + 2. Records issue/PR IDs and latest comment IDs in the issues/prs tables + - Uses id=0 as a special key to track the most recent issue/PR itself + - Uses id= to track the most recent comment on that issue/PR + :param repo: GitHub repository in "owner/repo" format :type repo: str """ @@ -285,7 +291,8 @@ async def initialize_repo_timestamps(repo: str) -> None: if filtered_items: latest_filtered = filtered_items[0] - # Store the latest issue/PR ID (id=0 means tracking the latest item) + # Store the latest issue/PR ID in the database with special key id=0 + # This tracks when a completely new issue/PR is created save_commit_data(repo, str(latest_filtered.id), 0, content_type) # Also store latest comment ID for this issue/PR if comments exist From 3d60fa2037e2c751974228659e01f58c15ad1c9a Mon Sep 17 00:00:00 2001 From: HTony03 Date: Sun, 25 Jan 2026 15:38:58 +0800 Subject: [PATCH 5/5] feat(main): configable "initialize_repo_timestamps", resolve #27 --- .idea/dataSources.xml | 12 ++++++++ README.md | 29 ++++++++++--------- README_en.md | 27 ++++++++--------- .../commands.py | 6 ++-- .../config.py | 5 ++++ .../db_action.py | 8 ++--- .../repo_activity_new.py | 2 +- 7 files changed, 54 insertions(+), 35 deletions(-) create mode 100644 .idea/dataSources.xml diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml new file mode 100644 index 0000000..64d01ce --- /dev/null +++ b/.idea/dataSources.xml @@ -0,0 +1,12 @@ + + + + + sqlite.xerial + true + org.sqlite.JDBC + jdbc:sqlite:$USER_HOME$/AppData/Local/nonebot2/nonebot_plugin_github_release_notifier/github_release_notifier.db + $ProjectFileDir$ + + + \ No newline at end of file diff --git a/README.md b/README.md index 3dd1900..2e18469 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ **本项目为纯GitHub REST API实现,非webhook,不依赖相关服务** -其他语言 | Other languages: [English](https://github.com/HTony03/nonebot_plugin_github_release_notifier/README_en.md) +其他语言 | Other languages: [English](https://github.com/HTony03/nonebot_plugin_github_release_notifier/blob/main/README_en.md) ## 📖 介绍 @@ -60,19 +60,20 @@ 在 nonebot2 项目的 `.env` 文件中添加下表中的必填配置: -| 配置项 | 必填 | 默认值 | 说明 | -|:-----:|:----:|:----:|:----:| -| GITHUB_TOKEN | 否 | 空字符串 | 用于访问 GitHub API 的 Token | -| GITHUB_RETRIES | 否 | 3 | 刷新最大重试次数 | -| GITHUB_RETRY_DELAY | 否 | 5 | 每次刷新重试之间的延迟(秒) | -| GITHUB_LANGUAGE | 否 | "en_us" | 发送的模板语言 | -| GITHUB_SEND_FALIURE_GROUP | 否 | True | 失败时是否通知群聊 | -| GITHUB_SEND_FALIURE_SUPERUSER | 否 | False | 失败时是否通知超级用户 | -| GITHUB_DEFAULT_CONFIG_SETTING | 否 | True | 添加仓库时默认监控所有事件 | -| GITHUB_SEND_IN_MARKDOWN | 否 | False | 是否以 Markdown 图片方式发送消息 | -| GITHUB_SEND_DETAIL_IN_MARKDOWN | 否 | True | 是否以 Markdown 图片方式发送详细信息(pr/issue/release)| -| GITHUB_UPLOAD_REMOVE_OLDER_VER | 否 | True | 上传 release 文件时是否移除旧版本( in development) | -| GITHUB_THEME | 否 | "dark" | (针对issue/pull request comment)渲染页面风格 ["light","dark"] | +| 配置项 | 必填 | 默认值 | 说明 | +|:-----:|:----:|:-------:|:-----------------------------------------------------:| +| GITHUB_TOKEN | 否 | 空字符串 | 用于访问 GitHub API 的 Token | +| GITHUB_RETRIES | 否 | 3 | 刷新最大重试次数 | +| GITHUB_RETRY_DELAY | 否 | 5 | 每次刷新重试之间的延迟(秒) | +| GITHUB_LANGUAGE | 否 | "en_us" | 发送的模板语言 | +| GITHUB_SEND_FALIURE_GROUP | 否 | True | 失败时是否通知群聊 | +| GITHUB_SEND_FALIURE_SUPERUSER | 否 | False | 失败时是否通知超级用户 | +| GITHUB_DEFAULT_CONFIG_SETTING | 否 | True | 添加仓库时默认监控所有事件 | +| GITHUB_SEND_IN_MARKDOWN | 否 | False | 是否以 Markdown 图片方式发送消息 | +| GITHUB_SEND_DETAIL_IN_MARKDOWN | 否 | True | 是否以 Markdown 图片方式发送详细信息(pr/issue/release) | +| GITHUB_SEND_PREV_DETAILS | 否 | False | 是否发送添加repo前的数据 | +| GITHUB_UPLOAD_REMOVE_OLDER_VER | 否 | True | 上传 release 文件时是否移除旧版本( in development) | +| GITHUB_THEME | 否 | "dark" | (针对issue/pull request comment)渲染页面风格 ["light","dark"] | `v0.1.9` 删除了对于`.env`添加群组repo的适配, 请使用指令使用相关功能 diff --git a/README_en.md b/README_en.md index 0f4023f..2763f1f 100644 --- a/README_en.md +++ b/README_en.md @@ -58,19 +58,20 @@ Before use, ensure that the `SUPERUSERS` configuration item in NoneBot2 is set. Add the following required configuration items to the `.env` file in your NoneBot2 project: -| Config Item | Required | Default | Description | -|:-----------:|:--------:|:-------:|:-----------:| -| GITHUB_TOKEN | No | Empty string | Token for accessing the GitHub API | -| GITHUB_RETRIES | No | 3 | Maximum retry attempts for refreshing | -| GITHUB_RETRY_DELAY | No | 5 | Delay between each refresh retry (seconds) | -| GITHUB_LANGUAGE | No | "en_us" | Language for sending templates | -| GITHUB_SEND_FALIURE_GROUP | No | True | Notify group on failure | -| GITHUB_SEND_FALIURE_SUPERUSER | No | False | Notify superuser on failure | -| GITHUB_DEFAULT_CONFIG_SETTING | No | True | Monitor all events by default when adding a repo | -| GITHUB_SEND_IN_MARKDOWN | No | False | Send messages as Markdown images | -| GITHUB_SEND_DETAIL_IN_MARKDOWN | No | True | Send details (pr/issue/release) as Markdown images | -| GITHUB_UPLOAD_REMOVE_OLDER_VER | No | True | Remove old versions when uploading release files (in development) | -| GITHUB_THEME | No | "dark" | (For issue/pull request comments) Page rendering style ["light","dark"] | +| Config Item | Required | Default | Description | +|:-----------:|:--------:|:-------:|:-----------------------------------------------------------------------:| +| GITHUB_TOKEN | No | Empty string | Token for accessing the GitHub API | +| GITHUB_RETRIES | No | 3 | Maximum retry attempts for refreshing | +| GITHUB_RETRY_DELAY | No | 5 | Delay between each refresh retry (seconds) | +| GITHUB_LANGUAGE | No | "en_us" | Language for sending templates | +| GITHUB_SEND_FALIURE_GROUP | No | True | Notify group on failure | +| GITHUB_SEND_FALIURE_SUPERUSER | No | False | Notify superuser on failure | +| GITHUB_DEFAULT_CONFIG_SETTING | No | True | Monitor all events by default when adding a repo | +| GITHUB_SEND_IN_MARKDOWN | No | False | Send messages as Markdown images | +| GITHUB_SEND_DETAIL_IN_MARKDOWN | No | True | Send details (pr/issue/release) as Markdown images | +| GITHUB_SEND_PREV_DETAILS | No | False | Whether send previous details when adding a new repository | +| GITHUB_UPLOAD_REMOVE_OLDER_VER | No | True | Remove old versions when uploading release files (in development) | +| GITHUB_THEME | No | "dark" | (For issue/pull request comments) Page rendering style ["light","dark"] | `v0.1.9` removed support for adding group repo via `.env`. Please use commands for related features. diff --git a/src/nonebot_plugin_github_release_notifier/commands.py b/src/nonebot_plugin_github_release_notifier/commands.py index 5fc3ba6..0ef5079 100644 --- a/src/nonebot_plugin_github_release_notifier/commands.py +++ b/src/nonebot_plugin_github_release_notifier/commands.py @@ -123,9 +123,9 @@ async def fetch_repo(repo: str) -> Response[FullRepository]: config.github_default_config_setting, None, False) - - # Initialize timestamps to prevent flooding on first check - await initialize_repo_timestamps(repo) + if not config.github_send_prev_details: + # Initialize timestamps to prevent flooding on first check + await initialize_repo_timestamps(repo) await bot.send(event, f"Added repository mapping: {group_id} -> {repo}") logger.info(f"Added repository mapping: {group_id} -> {repo}") diff --git a/src/nonebot_plugin_github_release_notifier/config.py b/src/nonebot_plugin_github_release_notifier/config.py index 680400e..e28904d 100644 --- a/src/nonebot_plugin_github_release_notifier/config.py +++ b/src/nonebot_plugin_github_release_notifier/config.py @@ -90,6 +90,11 @@ class Config(BaseModel): # pylint: disable=missing-class-docstring - release """ + github_send_prev_details: bool = False + """ + Whether send previous details when adding a new repository. + """ + github_comment_check_amount: int = 20 """ The amount of issues/prs to check for comment each time when refresh. diff --git a/src/nonebot_plugin_github_release_notifier/db_action.py b/src/nonebot_plugin_github_release_notifier/db_action.py index 494cc6e..cb54c9a 100644 --- a/src/nonebot_plugin_github_release_notifier/db_action.py +++ b/src/nonebot_plugin_github_release_notifier/db_action.py @@ -59,10 +59,10 @@ def _create_tables(cursor: sqlite3.Cursor) -> None: CREATE TABLE IF NOT EXISTS group_config ( group_id TEXT, repo TEXT, - commits BOOLEAN, - issues BOOLEAN, - prs BOOLEAN, - releases BOOLEAN, + commits BOOLEAN DEFAULT FALSE, + issues BOOLEAN DEFAULT FALSE, + prs BOOLEAN DEFAULT FALSE, + releases BOOLEAN DEFAULT FALSE, release_folder TEXT, send_release BOOLEAN DEFAULT FALSE, send_issue_comment BOOLEAN DEFAULT FALSE, diff --git a/src/nonebot_plugin_github_release_notifier/repo_activity_new.py b/src/nonebot_plugin_github_release_notifier/repo_activity_new.py index 541027b..db1dc8e 100644 --- a/src/nonebot_plugin_github_release_notifier/repo_activity_new.py +++ b/src/nonebot_plugin_github_release_notifier/repo_activity_new.py @@ -336,7 +336,7 @@ async def initialize_repo_timestamps(repo: str) -> None: # Save the timestamps last_processed[repo] = timestamps save_last_processed(last_processed) - logger.info(f"Initialized timestamps for repository {repo} to prevent flooding") + logger.info(f"Initialized timestamps for repository {repo}")