From d8a9e7fc11231b3f482b71aea6f7924d9f8082d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=B8=AD=E9=B8=AD=E3=80=8C=E3=82=AB=E3=83=A2=E3=80=8D?= <89643991+DuckDuckStudio@users.noreply.github.com> Date: Wed, 18 Feb 2026 05:42:32 +0800 Subject: [PATCH 1/4] =?UTF-8?q?refactor(func/github/pr):=20=E6=94=B9?= =?UTF-8?q?=E7=94=A8=E7=BB=9F=E4=B8=80=E7=9A=84=E4=BF=AE=E6=94=B9=E6=8B=89?= =?UTF-8?q?=E5=8F=96=E8=AF=B7=E6=B1=82=E6=8F=90=E4=BA=A4=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/function/github/pr.py | 88 +++++++++++++++++++++++++++++++++++++++ src/tools/modify.py | 78 +++++++--------------------------- src/tools/remove.py | 48 ++++----------------- 3 files changed, 111 insertions(+), 103 deletions(-) diff --git a/src/function/github/pr.py b/src/function/github/pr.py index 33d0c22..6f5c24c 100644 --- a/src/function/github/pr.py +++ b/src/function/github/pr.py @@ -1,4 +1,92 @@ import subprocess +from colorama import Fore +from requests import HTTPError +from catfood.functions.print import 消息头 +from function.github.token import read_token +from function.maintain.config import 读取配置 +from function.constant.general import PR_TOOL_NOTE +from catfood.functions.github.api import 请求GitHubAPI +from catfood.exceptions.operation import OperationFailed +from catfood.functions.format.github import ResolvesIssue + +def submitChanges( + branch: str, + packageIdentifier: str, + packageVersion: str, + doWhat: str, + resolves: str | None = None, + information: str | None = None, + token: str | None = None +) -> bool: + """ + 向上游仓库(microsoft/winget-pkgs)提交修改拉取请求。 + + :param branch: 修改位于的分支名 + :type branch: str + :param packageIdentifier: 修改的包的标识符 + :type packageIdentifier: str + :param packageVersion: 修改的包的版本 + :type packageVersion: str + :param doWhat: 做什么修改,该内容作为拉取请求标题开头 + :type doWhat: str + :param resolves: 解决了什么议题 + :type resolves: str | None + :param information: 要在拉取请求正文中添加的内容 + :type information: str | None + :param token: 创建拉取请求时使用的 GitHub Token + :type token: str | None + :return: 是否成功创建拉取请求 + :rtype: bool + """ + + pkgs仓库 = 读取配置("repos.winget-pkgs") + if not isinstance(pkgs仓库, tuple): + print(f"{消息头.错误} 未能获取配置文件中的 repos.winget-pkgs") + return False + owner: str = pkgs仓库[0] + + if not token: + token = read_token() + if not token: + print(f"{消息头.错误} 未能读取到 Token") + + jsonData: dict[str, str | bool] = { + "title": f"{doWhat}: {packageIdentifier} version {packageVersion}", + "head": f"{owner}:{branch}", + "base": "master", + "body": PR_TOOL_NOTE + } + + if resolves: + if resolvesStr := ResolvesIssue(resolves): + jsonData["body"] = f"{jsonData['body']}\n\n{resolvesStr}" + else: + print(f"{消息头.警告} 未能格式化解决议题字符串,拉取请求正文中不会链接议题") + + if information: + jsonData["body"] = f"{jsonData['body']}\n\n{information}" + + if 读取配置("github.pr.maintainer_can_modify") == False: + jsonData["maintainer_can_modify"] = False + + try: + try: + response = 请求GitHubAPI( + api="https://api.github.com/repos/microsoft/winget-pkgs/pulls", + json=jsonData, + token=token, + method="POST", + raiseException=True + ) + if not response: + raise ValueError(f"catfood 的 请求GitHubAPI 函数没有返回有效的预期值,实际返回 {repr(response)}") + print(f"{消息头.成功} 拉取请求创建成功: {response.get("html_url", f"{Fore.YELLOW}未能获取到拉取请求链接{Fore.RESET}")}") + return True + except HTTPError as e: + raise OperationFailed(f"GitHub API 响应 {e.response.status_code} 错误: {e.response.text}") from e + except Exception as e: + print(f"{消息头.错误} 创建拉取请求失败: {Fore.RED}{e}{Fore.RESET}") + return False def 检查重复拉取请求(包标识符: str, 包版本: str) -> bool: """ diff --git a/src/tools/modify.py b/src/tools/modify.py index db2e057..3a4ac82 100644 --- a/src/tools/modify.py +++ b/src/tools/modify.py @@ -3,23 +3,22 @@ import csv import time import random -import requests import subprocess from colorama import Fore +from typing import Literal from datetime import datetime -from catfood.constant import YES from catfood.functions.print import 消息头 from function.git.format import branchName +from function.github.pr import submitChanges from function.maintain.config import 读取配置 from catfood.functions.files import open_file from function.files.manifest import 获取清单目录 from function.files.manifest import FormatManifest -from function.constant.general import PR_TOOL_NOTE from function.github.token import read_token, 这是谁的Token -def main(args: list[str]): +def main(args: list[str]) -> Literal[1, 0]: global 包标识符, 包版本, 日志文件路径 - global 解决, 清单目录, 首个_PR, 格式化审查者, 程序所在目录 + global 解决, 清单目录, 格式化审查者, 程序所在目录 global owner # 目录路径 @@ -85,7 +84,6 @@ def main(args: list[str]): return 1 格式化审查者 = ' , '.join([f"@{审查者}" for 审查者 in 审查者列表]) - 首个_PR = "是" # ========= 日志 配置 开始 ========= os.chdir(程序所在目录) @@ -189,52 +187,8 @@ def 写入日志(消息: str, 等级: str="INFO"): for 行 in 消息.split("\n"): 日志文件.write(f"{写入时间} {等级} {行}\n") -# 创建拉取请求 -def 创建拉取请求(分支名: str, 版本文件夹: str, 审查: str="") -> str | int: - # 审查: - # "" -> 不请求审查 - # 带 @ 的字符串 -> 在 PR body 中 @ 审查者 - # 不带 @ 的字符串 -> 在 PR body 中引用首个拉取请求 - global 解决 - while True: # 不 break 直接 return - github_token = read_token() - if not github_token: - print(f"{消息头.错误} 拉取请求创建失败: Token 读取失败") - return 1 - api = "https://api.github.com/repos/microsoft/winget-pkgs/pulls" - 请求头 = { - "Authorization": f"token {github_token}", - "Accept": "application/vnd.github.v3+json" - } - 数据: dict[str, str | bool] - 数据 = { - "title": f"Modify: {包标识符} version {版本文件夹} (Auto)", - "head": f"{owner}:{分支名}", - "base": "master", - "body": f"{PR_TOOL_NOTE}\n\n{审查}\n{解决}\n\n---\n" - } - if 读取配置("github.pr.maintainer_can_modify") == False: - 数据["maintainer_can_modify"] = False - - response = requests.post(api, headers=请求头, json=数据) - if response.status_code == 201: - print(f" {Fore.GREEN}拉取请求创建成功: {response.json()["html_url"]}") - 写入日志(f" Pull request created successfully: {response.json()["html_url"]}") - return response.json()["html_url"] - else: - print(f" {Fore.RED}拉取请求创建失败: {response.status_code} - {response.text}") - 写入日志(f" Failed to create pull request: {response.status_code} - {response.text}", "ERROR") - try: - if input(f"{消息头.问题} 我应该重试吗[Y/N]: ").lower() not in (*YES, "应该", "重试", "retry"): - return 1 - print("正在重试...") - 写入日志(" Retrying to create a pull request...") - except KeyboardInterrupt: - return 1 - # Git 操作部分 -def 修改版本(版本文件夹: str): - global 首个_PR +def 修改版本(版本文件夹: str) -> Literal[1, 0]: print(f"\n正在处理版本文件夹: {版本文件夹}") 写入日志(f"Processing version folder: {版本文件夹}") 版本文件夹路径 = os.path.join(清单目录, 版本文件夹) @@ -326,16 +280,14 @@ def 修改版本(版本文件夹: str): 写入日志(f" Successfully pushed to remote (origin): {新分支}") # 创建拉取请求 - if 格式化审查者: - if 首个_PR == "是": - 首个_PR = 创建拉取请求(新分支, 版本文件夹, f"{格式化审查者} PTAL") - if 首个_PR == 1: - return 1 # 创建拉取请求时出错 - else: - if 创建拉取请求(新分支, 版本文件夹, f"Review has been requested in {首个_PR}") == 1: - return 1 # 创建拉取请求时出错 + if submitChanges( + branch=新分支, + packageIdentifier=包标识符, + packageVersion=包版本, + doWhat="Modify", + resolves=解决, + information=(f"\n\n{格式化审查者} PTAL" if 格式化审查者 else "") + ): + return 0 else: - if 创建拉取请求(新分支, 版本文件夹) == 1: - return 1 # 创建拉取请求时出错 - - return 0 # 成功处理版本文件夹 + return 1 diff --git a/src/tools/remove.py b/src/tools/remove.py index 9b7e54e..9c109e3 100644 --- a/src/tools/remove.py +++ b/src/tools/remove.py @@ -4,7 +4,6 @@ import time import shutil import tempfile -import requests import subprocess import webbrowser import tools.cat as cat @@ -13,50 +12,13 @@ from catfood.constant import YES, NO from catfood.functions.print import 消息头 from function.git.format import branchName +from function.github.pr import submitChanges from function.maintain.config import 读取配置 from translate import Translator # type: ignore -from function.constant.general import PR_TOOL_NOTE from catfood.exceptions.operation import OperationFailed from function.github.token import read_token, 这是谁的Token from function.files.manifest import 获取清单目录, 获取现有包版本 -# 创建拉取请求 -def 创建拉取请求(包标识符: str, 分支名: str, 版本文件夹: str, 理由: str): - global owner, 手动验证结果 - while True: # 不 break 直接 return - github_token = read_token() - if not github_token: - print(f"{消息头.错误} 拉取请求创建失败: Token 读取失败") - return 1 - - api = "https://api.github.com/repos/microsoft/winget-pkgs/pulls" - 请求头 = { - "Authorization": f"token {github_token}", - "Accept": "application/vnd.github.v3+json" - } - 数据: dict[str, str | bool] = { - "title": f"Remove version: {包标识符} version {版本文件夹} (Auto)", - "head": f"{owner}:{分支名}", - "base": "master", - "body": f"{PR_TOOL_NOTE}\n\n{理由}{f'\n{手动验证结果}' if 手动验证结果 else ''}\n\n---\n" - } - - if 读取配置("github.pr.maintainer_can_modify") == False: - 数据["maintainer_can_modify"] = False - - response = requests.post(api, headers=请求头, json=数据) - if response.status_code == 201: - print(f" {Fore.GREEN}拉取请求创建成功: {response.json()["html_url"]}") - return response.json()["html_url"] - else: - print(f" {Fore.RED}拉取请求创建失败: {response.status_code} - {response.text}") - try: - if input(f"{消息头.问题} 我应该重试吗[Y/N]: ").lower() not in (*YES, "应该", "重试", "retry"): - return 1 - print("正在重试...") - except KeyboardInterrupt: - return 1 - def main(args: list[str]) -> int: global 手动验证结果, owner @@ -210,7 +172,13 @@ def main(args: list[str]) -> int: while (not 理由): 理由 = input("移除此包版本的理由: ") - if 创建拉取请求(包标识符, 新分支名, 包版本, 理由) == 1: + if not submitChanges( + branch=新分支名, + packageIdentifier=包标识符, + packageVersion=包版本, + doWhat="Remove version", + information=f"{理由}{f'\n{手动验证结果}' if 手动验证结果 else ''}" + ): return 1 # 拉取请求创建失败 print(f"{Fore.GREEN} 成功移除 {包标识符} 版本 {包版本}") From 362697b653ef6ede2d54a10f0e984a27ce428aec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=B8=AD=E9=B8=AD=E3=80=8C=E3=82=AB=E3=83=A2=E3=80=8D?= <89643991+DuckDuckStudio@users.noreply.github.com> Date: Thu, 19 Feb 2026 16:39:19 +0800 Subject: [PATCH 2/4] =?UTF-8?q?depreacted!(func/gh/pr):=20=E5=BC=83?= =?UTF-8?q?=E7=94=A8=20submitChanges=20=E7=9A=84=20resolves=20=E5=8F=82?= =?UTF-8?q?=E6=95=B0=EF=BC=8C=E8=AF=B7=E8=B0=83=E7=94=A8=E5=A4=84=E8=87=AA?= =?UTF-8?q?=E8=A1=8C=E5=A4=84=E7=90=86=E5=B9=B6=E6=94=B9=E7=94=A8=20inform?= =?UTF-8?q?ation=20=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/function/github/pr.py | 10 ---------- src/tools/modify.py | 3 +-- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/src/function/github/pr.py b/src/function/github/pr.py index 6f5c24c..2c61132 100644 --- a/src/function/github/pr.py +++ b/src/function/github/pr.py @@ -7,14 +7,12 @@ from function.constant.general import PR_TOOL_NOTE from catfood.functions.github.api import 请求GitHubAPI from catfood.exceptions.operation import OperationFailed -from catfood.functions.format.github import ResolvesIssue def submitChanges( branch: str, packageIdentifier: str, packageVersion: str, doWhat: str, - resolves: str | None = None, information: str | None = None, token: str | None = None ) -> bool: @@ -29,8 +27,6 @@ def submitChanges( :type packageVersion: str :param doWhat: 做什么修改,该内容作为拉取请求标题开头 :type doWhat: str - :param resolves: 解决了什么议题 - :type resolves: str | None :param information: 要在拉取请求正文中添加的内容 :type information: str | None :param token: 创建拉取请求时使用的 GitHub Token @@ -57,12 +53,6 @@ def submitChanges( "body": PR_TOOL_NOTE } - if resolves: - if resolvesStr := ResolvesIssue(resolves): - jsonData["body"] = f"{jsonData['body']}\n\n{resolvesStr}" - else: - print(f"{消息头.警告} 未能格式化解决议题字符串,拉取请求正文中不会链接议题") - if information: jsonData["body"] = f"{jsonData['body']}\n\n{information}" diff --git a/src/tools/modify.py b/src/tools/modify.py index 3a4ac82..329128a 100644 --- a/src/tools/modify.py +++ b/src/tools/modify.py @@ -285,8 +285,7 @@ def 修改版本(版本文件夹: str) -> Literal[1, 0]: packageIdentifier=包标识符, packageVersion=包版本, doWhat="Modify", - resolves=解决, - information=(f"\n\n{格式化审查者} PTAL" if 格式化审查者 else "") + information=(f"\n\n{格式化审查者} PTAL" if 格式化审查者 else "") + (f"\n\n{解决}" if 解决 else "") ): return 0 else: From 07b87270fc673a58a338195508b59b5f96509040 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=B8=AD=E9=B8=AD=E3=80=8C=E3=82=AB=E3=83=A2=E3=80=8D?= <89643991+DuckDuckStudio@users.noreply.github.com> Date: Wed, 4 Mar 2026 00:46:50 +0800 Subject: [PATCH 3/4] =?UTF-8?q?feat(func/github/pr):=20=E4=BF=9D=E8=AF=81?= =?UTF-8?q?=E6=8B=89=E5=8F=96=E8=AF=B7=E6=B1=82=E6=AD=A3=E6=96=87=E6=9C=80?= =?UTF-8?q?=E5=90=8E=E6=98=AF=E5=88=86=E5=89=B2=E7=BA=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 和拉取请求模板一致,分隔线后面是策略机器人编辑的东西 --- src/function/github/pr.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/function/github/pr.py b/src/function/github/pr.py index 2c61132..8be4f24 100644 --- a/src/function/github/pr.py +++ b/src/function/github/pr.py @@ -56,6 +56,10 @@ def submitChanges( if information: jsonData["body"] = f"{jsonData['body']}\n\n{information}" + # 保证 PR body 最后是分割线 + if isinstance(jsonData["body"], str) and (not jsonData["body"].rstrip('\n').endswith("---")): + jsonData["body"] = f"{jsonData["body"].rstrip('\n')}\n\n---\n\n" + if 读取配置("github.pr.maintainer_can_modify") == False: jsonData["maintainer_can_modify"] = False From 57652306758d9bad80aa9b7fc855d8ff16d3d215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=B8=AD=E9=B8=AD=E3=80=8C=E3=82=AB=E3=83=A2=E3=80=8D?= <89643991+DuckDuckStudio@users.noreply.github.com> Date: Tue, 10 Mar 2026 02:52:38 +0800 Subject: [PATCH 4/4] =?UTF-8?q?refactor(func/github/pr):=20=E9=87=8D?= =?UTF-8?q?=E5=91=BD=E5=90=8D=20submitChanges=20=E5=87=BD=E6=95=B0?= =?UTF-8?q?=E4=B8=BA=20submitPR?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 因为原函数名和规划中的 sundry submmit 冲突。 一个是 git 上的“提交”(commit);而 function.github.pr 里的这个是创建 PR --- src/function/github/pr.py | 2 +- src/tools/modify.py | 4 ++-- src/tools/remove.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/function/github/pr.py b/src/function/github/pr.py index 8be4f24..8e7ba65 100644 --- a/src/function/github/pr.py +++ b/src/function/github/pr.py @@ -8,7 +8,7 @@ from catfood.functions.github.api import 请求GitHubAPI from catfood.exceptions.operation import OperationFailed -def submitChanges( +def submitPR( branch: str, packageIdentifier: str, packageVersion: str, diff --git a/src/tools/modify.py b/src/tools/modify.py index 329128a..6779157 100644 --- a/src/tools/modify.py +++ b/src/tools/modify.py @@ -9,7 +9,7 @@ from datetime import datetime from catfood.functions.print import 消息头 from function.git.format import branchName -from function.github.pr import submitChanges +from function.github.pr import submitPR from function.maintain.config import 读取配置 from catfood.functions.files import open_file from function.files.manifest import 获取清单目录 @@ -280,7 +280,7 @@ def 修改版本(版本文件夹: str) -> Literal[1, 0]: 写入日志(f" Successfully pushed to remote (origin): {新分支}") # 创建拉取请求 - if submitChanges( + if submitPR( branch=新分支, packageIdentifier=包标识符, packageVersion=包版本, diff --git a/src/tools/remove.py b/src/tools/remove.py index 9c109e3..129a64c 100644 --- a/src/tools/remove.py +++ b/src/tools/remove.py @@ -12,7 +12,7 @@ from catfood.constant import YES, NO from catfood.functions.print import 消息头 from function.git.format import branchName -from function.github.pr import submitChanges +from function.github.pr import submitPR from function.maintain.config import 读取配置 from translate import Translator # type: ignore from catfood.exceptions.operation import OperationFailed @@ -172,7 +172,7 @@ def main(args: list[str]) -> int: while (not 理由): 理由 = input("移除此包版本的理由: ") - if not submitChanges( + if not submitPR( branch=新分支名, packageIdentifier=包标识符, packageVersion=包版本,