1. 状态同步加 20 秒节流、超时缩短到 8 秒;Gitea 改用 runs 列表接口一次批量取回全部任务状态,在途任务并发补查作业,消除逐任务串行 API 请求导致的后台/我的构建/详情页慢。 2. 停止时先区分 404:运行已删除则本地标记取消;Gitea 1.27 无取消 API 时,若后台配置了 Gitea 网页账号密码则模拟网页登录取消,否则回退手动链接提示。 3. 后台 Gitea 连接设置新增网页登录账号/密码两个可选项。
100 lines
3.8 KiB
Python
100 lines
3.8 KiB
Python
"""构建后端统一接口与共享逻辑。"""
|
|
from dataclasses import dataclass
|
|
|
|
|
|
class BackendError(Exception):
|
|
"""触发构建失败时抛出,message 为可直接展示给用户的中文提示。"""
|
|
|
|
def __init__(self, message, *, kind='error'):
|
|
super().__init__(message)
|
|
self.message = message
|
|
# rejected=平台明确拒绝(4xx/5xx);network=连不上平台
|
|
self.kind = kind
|
|
|
|
|
|
@dataclass
|
|
class DispatchResult:
|
|
run_id: object = None # 平台返回的运行编号(int 或 None)
|
|
html_url: str = '' # 平台上的运行详情页地址
|
|
|
|
|
|
@dataclass
|
|
class RunInfo:
|
|
finished: bool # 是否已进入终态
|
|
status: str = '' # 终态结论:success/failure/cancelled/skipped;未结束为进行中状态
|
|
html_url: str = ''
|
|
|
|
|
|
# rdgen 目标平台 -> 工作流文件名(两平台同名)
|
|
WORKFLOW_FILES = {
|
|
'windows': 'generator-windows.yml',
|
|
'windows-x86': 'generator-windows-x86.yml',
|
|
'linux': 'generator-linux.yml',
|
|
'android': 'generator-android.yml',
|
|
'macos': 'generator-macos.yml',
|
|
}
|
|
|
|
|
|
class BuildBackend:
|
|
"""各构建平台实现此接口。所有配置均通过 app_settings 实时读取。"""
|
|
|
|
name = ''
|
|
label = ''
|
|
|
|
# ---- 配置健康度(后台页 / 全局告警条使用) ----
|
|
def configured(self) -> bool:
|
|
raise NotImplementedError
|
|
|
|
def warnings(self) -> list:
|
|
"""配置隐患的中文提示列表;通用项(GENURL/ZIP_PASSWORD)各实现自行包含。"""
|
|
raise NotImplementedError
|
|
|
|
# ---- 构建任务 ----
|
|
def workflow_file_for(self, platform, selfhosted=False) -> str:
|
|
raise NotImplementedError
|
|
|
|
def dispatch(self, workflow_file, inputs, *, timeout=20) -> DispatchResult:
|
|
"""触发工作流。inputs 为完整输入字典(GitHub/Gitea 均为 {ref, inputs})。"""
|
|
raise NotImplementedError
|
|
|
|
def get_run(self, run_id, *, timeout=12):
|
|
"""查询单次运行;网络异常或非 200 返回 None(调用方按「仍在进行」处理)。"""
|
|
raise NotImplementedError
|
|
|
|
def get_runs_batch(self, run_ids, *, timeout=12):
|
|
"""批量查询多个运行,返回 {str(run_id): RunInfo}。
|
|
|
|
列表页一次刷新多个在途任务时使用;平台不支持或查询失败返回 None,
|
|
调用方退化为逐个 get_run。返回字典中缺失的 id 由调用方逐个兜底。
|
|
"""
|
|
return None
|
|
|
|
def cancel_run(self, run_id, *, timeout=15):
|
|
"""请求平台取消一次运行;成功无返回,已结束时抛 BackendError(kind='finished')。"""
|
|
raise NotImplementedError
|
|
|
|
def log_url(self, run_id) -> str:
|
|
raise NotImplementedError
|
|
|
|
# ---- 后台连接测试 ----
|
|
def test_connection(self) -> dict:
|
|
"""返回 {'ok': bool, 'message': 中文说明},不抛异常。"""
|
|
raise NotImplementedError
|
|
|
|
# ---- 共享的配置检查 ----
|
|
def _shared_warnings(self, *, include_sh_secret=False):
|
|
"""两平台共用的回调/加密检查。"""
|
|
from .. import app_settings
|
|
warnings = []
|
|
if not app_settings.get_value('GENURL').strip():
|
|
warnings.append('平台外部访问地址(GENURL)未配置,构建机将无法回传构建产物。')
|
|
zip_password = app_settings.get_value('ZIP_PASSWORD')
|
|
if zip_password in ('', 'insecure'):
|
|
warnings.append(
|
|
'配置压缩包密码为空或仍为默认值 insecure,建议设置随机强密码,'
|
|
f'并同步更新{self.label}仓库 Secret。'
|
|
)
|
|
if include_sh_secret and app_settings.get_value('SH_SECRET') in ('', 'secret'):
|
|
warnings.append('自托管 Runner 密钥为空或仍为默认值 secret;如使用自托管 Runner,建议设置独立强密钥,避免被冒用触发。')
|
|
return warnings
|