Skip to content
Closed
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
1 change: 1 addition & 0 deletions .github/workflows/collect-changelogs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ jobs:
- name: Fetch changelogs
env:
GITHUB_TOKEN: ${{ steps.app-token-source.outputs.token }}
RELEASE_DATE: ${{ inputs.release_date }}
run: |
cat repos.json | python3 scripts/fetch-changelogs.py > changelogs.json
echo "✅ CHANGELOG 抓取完成"
Expand Down
96 changes: 93 additions & 3 deletions scripts/fetch-changelogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
输出: 包含各仓库 CHANGELOG 内容的 JSON (stdout)
"""
import base64
import datetime
import json
import os
import re
Expand Down Expand Up @@ -70,6 +71,51 @@ def fetch_changelog_from_tag(repo, version, changelog_path, token):
return None


def get_latest_tag_info(repo, token):
"""
获取仓库最新 tag 的版本号和日期

Args:
repo: 仓库名
token: GitHub token

Returns:
(version, date_str) 元组,version 不含 v 前缀,date_str 为 YYYY-MM-DD 格式
如果没有 tag 则返回 (None, None)
"""
# 获取最新 tag
endpoint = f"/repos/{ORG}/{repo}/tags?per_page=1"
tags = github_api(endpoint, token)
if not tags:
return None, None

tag_name = tags[0]["name"]
version = tag_name.lstrip("v")

# 获取 tag 对应的 commit 日期
sha = tags[0]["commit"]["sha"]
commit_endpoint = f"/repos/{ORG}/{repo}/git/commits/{sha}"
commit_data = github_api(commit_endpoint, token)
if not commit_data:
return version, None

# 解析日期 (格式: 2026-02-02T01:46:19Z)
date_str = commit_data.get("committer", {}).get("date", "")[:10]
return version, date_str

content = data.get("content", "")
encoding = data.get("encoding", "")
if encoding == "base64":
try:
return base64.b64decode(content).decode("utf-8")
except UnicodeDecodeError:
print(f"⚠️ {repo}: CHANGELOG 非 UTF-8,已跳过", file=sys.stderr)
return None

print(f"⚠️ {repo}: 未知编码格式 {encoding}", file=sys.stderr)
return None
Comment on lines +74 to +116
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

删除 get_latest_tag_info 中残留的重复解码逻辑
该函数在 return 之后还有一段解码逻辑,且引用未定义的 data,会触发 Ruff F821 并可能导致 CI 失败。建议删除这段残留代码,避免误导后续维护。

建议修改
@@
     date_str = commit_data.get("committer", {}).get("date", "")[:10]
     return version, date_str
-
-    content = data.get("content", "")
-    encoding = data.get("encoding", "")
-    if encoding == "base64":
-        try:
-            return base64.b64decode(content).decode("utf-8")
-        except UnicodeDecodeError:
-            print(f"⚠️  {repo}: CHANGELOG 非 UTF-8,已跳过", file=sys.stderr)
-            return None
-
-    print(f"⚠️  {repo}: 未知编码格式 {encoding}", file=sys.stderr)
-    return None
🧰 Tools
🪛 Ruff (0.14.14)

[warning] 83-83: Docstring contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF002)


[warning] 83-83: Docstring contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF002)


[error] 106-106: Undefined name data

(F821)


[error] 107-107: Undefined name data

(F821)


[warning] 112-112: String contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF001)

🤖 Prompt for AI Agents
In `@scripts/fetch-changelogs.py` around lines 74 - 116, The function
get_latest_tag_info contains leftover decoding logic after its final return
(including references to an undefined symbol data and base64 decoding), which is
unreachable and triggers Ruff F821; remove the entire block starting from
"content = data.get(...)" through the final return so that get_latest_tag_info
ends after "return version, date_str", leaving no references to undefined
variables or dead code.



def extract_version_section(changelog_text, version):
"""
从 Keep a Changelog 格式的文本中提取指定版本的 section
Expand Down Expand Up @@ -140,6 +186,8 @@ def main():
print("❌ 错误: 需要设置 GITHUB_TOKEN 环境变量", file=sys.stderr)
sys.exit(1)

release_date = os.environ.get("RELEASE_DATE", "")

# 读取配置
config_path = os.path.join(os.path.dirname(__file__), "release-notes-config.json")
with open(config_path, encoding="utf-8") as f:
Expand All @@ -148,6 +196,45 @@ def main():
# 从 stdin 读取仓库列表 (parse-repos.py 的输出格式)
repos_input = json.loads(sys.stdin.read())

# 收集已输入的 repo 名称
input_repos = {item["repo"] for item in repos_input}

# 自动检测 auto_detect 组件
for component_name, component in config["components"].items():
if not component.get("auto_detect"):
continue
if component_name in input_repos:
continue # 已手动指定,跳过自动检测

source_repo = component.get("source_repo", component_name)
print(f"🔍 自动检测 {component_name}(from {source_repo})...", file=sys.stderr)

version, tag_date = get_latest_tag_info(source_repo, token)
if version is None:
print(f" ⚠️ 未找到 tag,跳过", file=sys.stderr)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

移除无占位符的 f-string
此处 f-string 不含占位符,Ruff F541 会报错。直接使用普通字符串即可。

建议修改
-            print(f"  ⚠️  未找到 tag,跳过", file=sys.stderr)
+            print("  ⚠️  未找到 tag,跳过", file=sys.stderr)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
print(f" ⚠️ 未找到 tag,跳过", file=sys.stderr)
print(" ⚠️ 未找到 tag,跳过", file=sys.stderr)
🧰 Tools
🪛 Ruff (0.14.14)

[error] 214-214: f-string without any placeholders

Remove extraneous f prefix

(F541)


[warning] 214-214: String contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF001)

🤖 Prompt for AI Agents
In `@scripts/fetch-changelogs.py` at line 214, Print call uses an f-string with no
placeholders (the print(f"  ⚠️  未找到 tag,跳过", file=sys.stderr) occurrence) which
triggers Ruff F541; change that print to use a normal string literal (remove the
f-prefix) so the message is printed to stderr without an f-string.

continue

# 检查 tag 日期是否匹配发布日期
if release_date:
if tag_date != release_date:
print(f" ⚠️ 最新 tag v{version}({tag_date})与发布日期 {release_date} 不匹配,跳过", file=sys.stderr)
continue
# 如果没有指定发布日期,使用今天
else:
today = datetime.date.today().isoformat()
# 允许今天或昨天的 tag
yesterday = (datetime.date.today() - datetime.timedelta(days=1)).isoformat()
if tag_date not in (today, yesterday):
print(f" ⚠️ 最新 tag v{version}({tag_date})不在近两天内,跳过", file=sys.stderr)
continue

print(f" ✅ 发现匹配的 tag v{version}({tag_date}),自动添加", file=sys.stderr)
repos_input.append({
"repo": component_name,
"version": version,
"changelog_path": component.get("changelog_path", "CHANGELOG.md"),
})

results = []
for item in repos_input:
repo = item["repo"]
Expand All @@ -164,6 +251,9 @@ def main():
if item.get("changelog_path") and item["changelog_path"] != "CHANGELOG.md":
changelog_path = item["changelog_path"]

# 确定抓取 CHANGELOG 的实际仓库(可能与输入 repo 不同)
source_repo = component.get("source_repo", repo)

entry = {
"repo": repo,
"version": version,
Expand All @@ -176,15 +266,15 @@ def main():
"changelog": None,
}

# firmware 等无仓库组件跳过抓取
# 无 CHANGELOG 路径的组件跳过抓取
if changelog_path is None:
print(f"ℹ️ {repo}: 无 CHANGELOG 路径,跳过抓取", file=sys.stderr)
results.append(entry)
continue

# 获取 CHANGELOG
print(f"📥 正在获取 {repo} v{version} 的 CHANGELOG...", file=sys.stderr)
raw = fetch_changelog_from_tag(repo, version, changelog_path, token)
print(f"📥 正在获取 {repo} v{version} 的 CHANGELOG(from {source_repo})...", file=sys.stderr)
raw = fetch_changelog_from_tag(source_repo, version, changelog_path, token)
if raw is None:
results.append(entry)
continue
Expand Down
6 changes: 4 additions & 2 deletions scripts/release-notes-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
"display_name_zh": "固件",
"display_name_en": "Firmware",
"public_repo": null,
"changelog_path": null,
"source_repo": "wh110-firmware",
"changelog_path": "CHANGELOG.md",
"update_method_zh": "通过 Wuji Hand Upgrader 更新",
"update_method_en": "Update via Wuji Hand Upgrader",
"order": 1
"order": 1,
"auto_detect": true
},
"wujihandpy": {
"display_name_zh": "Wuji Hand SDK",
Expand Down