Files
naeeo 6e5754fb59 停止/删除改为纯本地操作,页面不再查询 Gitea
停止只在本平台标记已取消、删除只删本地记录,均不再调用 GitHub/Gitea 的查询或取消接口,操作秒响应;构建状态完全以工作流结束回调为准,未收到回调的在途任务由纯本地 6 小时超时兜底。

移除上一版的 Gitea 网页登录取消、网页账密配置项、runs 批量状态查询及两后端 get_run/cancel_run 接口,消除页面加载时的远程等待。
2026-09-30 09:20:28 +08:00

307 lines
10 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
GitHub / 构建相关站点配置的统一读取层。
取值优先级:
1. 后台「GitHub 构建配置」页保存的值(SiteSetting 表)
2. 环境变量(docker-compose / 系统环境,历史部署方式,继续支持)
3. 内置默认值
进程内带 15 秒短缓存,避免每次调用都查库;后台保存后立即失效当前进程缓存,
其他 gunicorn worker 最迟 15 秒后生效。
"""
import os
import time
# 每项:key=配置键 / env=对应环境变量名 / default=内置默认值 / label/help/组 供后台页渲染
SETTING_DEFS = [
{
'key': 'GHUSER',
'env': 'GHUSER',
'default': '',
'label': 'GitHub 用户名',
'group': 'basic',
'sensitive': False,
'help': 'Fork 本项目仓库所在的 GitHub 账号用户名(或组织名)。',
},
{
'key': 'REPONAME',
'env': 'REPONAME',
'default': 'rdgen',
'label': '仓库名称',
'group': 'basic',
'sensitive': False,
'help': 'Fork 后的仓库名,默认为 rdgen;若改名请如实填写。',
},
{
'key': 'GHBRANCH',
'env': 'GHBRANCH',
'default': 'master',
'label': '工作流分支',
'group': 'basic',
'sensitive': False,
'help': '触发 GitHub Actions 时使用的分支名,通常保持 master。',
},
{
'key': 'GHBEARER',
'env': 'GHBEARER',
'default': '',
'label': 'GitHub 访问令牌(Fine-grained PAT)',
'group': 'basic',
'sensitive': True,
'help': '需对该仓库授予 Actions 与 Workflows 的读写权限。页面仅显示保存状态,不会回显明文。',
},
{
'key': 'GENURL',
'env': 'GENURL',
'default': '',
'label': '本平台外部访问地址',
'group': 'callback',
'sensitive': False,
'help': '运行 Actions 的构建机可从网络访问到的本平台地址,例如 https://rdgen.example.com,用于回传构建产物。',
},
{
'key': 'PROTOCOL',
'env': 'PROTOCOL',
'default': 'https',
'label': '平台访问协议',
'group': 'callback',
'sensitive': False,
'choices': [('https', 'https'), ('http', 'http')],
'help': '经 Nginx/Caddy 等 HTTPS 反向代理时保持 https;本地纯 HTTP 部署选 http。',
},
{
'key': 'ZIP_PASSWORD',
'env': 'ZIP_PASSWORD',
'default': 'insecure',
'label': '配置压缩包密码',
'group': 'callback',
'sensitive': True,
'help': '本平台用它加密传给 Actions 的配置包,必须与构建仓库 Secret 中的 ZIP_PASSWORD 完全一致(GitHub 与 Gitea 仓库均需配置)。默认值不安全,建议更换。',
},
{
'key': 'SH_SECRET',
'env': 'SH_SECRET',
'default': 'secret',
'label': '自托管 Runner 密钥',
'group': 'advanced',
'sensitive': True,
'help': '仅在使用自托管 GitHub Runner(rdgen-cli 的 sh_secret_field)时需要,默认值不安全。',
},
{
'key': 'WEBHOOK_SECRET',
'env': 'WEBHOOK_SECRET',
'default': '',
'label': '回调校验密钥',
'group': 'advanced',
'sensitive': True,
'help': '可选。配置后构建平台(GitHub / Gitea)Actions 回调必须携带 X-Webhook-Secret 请求头;留空则不校验(兼容旧工作流)。',
},
{
'key': 'GH_PROXY',
'env': 'GH_PROXY',
'default': '',
'label': 'GitHub 访问代理',
'group': 'network',
'sensitive': True,
'help': (
'本服务器直连 GitHub 失败时填写,例如 http://127.0.0.1:7890;'
'支持 socks5://(需 PySocks)。可包含账密,如 http://user:pass@host:port。'
'留空则直连(仍遵循容器的 HTTPS_PROXY/HTTP_PROXY 环境变量)。'
),
},
# ===== 构建平台选择(GitHub / Gitea 二选一) =====
{
'key': 'BUILD_PLATFORM',
'env': 'BUILD_PLATFORM',
'default': 'github',
'label': '构建平台',
'group': 'platform',
'sensitive': False,
'choices': [('github', 'GitHub Actions'), ('gitea', 'Gitea Actions(自建)')],
'help': (
'选择实际执行构建任务的平台。切换后仅影响新提交的任务,'
'历史任务仍在原平台查询状态与日志。Gitea 需自建实例并自备构建机(Linux/Windows/macOS)。'
),
},
# ===== Gitea 连接(BUILD_PLATFORM=gitea 时生效) =====
{
'key': 'GITEA_SERVER_URL',
'env': 'GITEA_SERVER_URL',
'default': '',
'label': 'Gitea 服务器地址',
'group': 'gitea',
'sensitive': False,
'help': '自建 Gitea 的访问地址,例如 https://gitea.example.com(不带末尾斜杠);建议版本不低于 1.27。',
},
{
'key': 'GITEA_OWNER',
'env': 'GITEA_OWNER',
'default': '',
'label': 'Gitea 仓库属主',
'group': 'gitea',
'sensitive': False,
'help': '存放构建仓库的 Gitea 用户名或组织名。',
},
{
'key': 'GITEA_REPO',
'env': 'GITEA_REPO',
'default': 'rdgen',
'label': 'Gitea 仓库名称',
'group': 'gitea',
'sensitive': False,
'help': 'Gitea 上的构建仓库名,默认 rdgen;仓库需在设置中启用 Repository Actions。',
},
{
'key': 'GITEA_BRANCH',
'env': 'GITEA_BRANCH',
'default': 'master',
'label': 'Gitea 工作流分支',
'group': 'gitea',
'sensitive': False,
'help': '触发 Gitea Actions 时使用的分支名,通常保持 master。',
},
{
'key': 'GITEA_TOKEN',
'env': 'GITEA_TOKEN',
'default': '',
'label': 'Gitea 访问令牌',
'group': 'gitea',
'sensitive': True,
'help': '在 Gitea 个人设置中生成的 API 令牌,需对构建仓库授予 Actions 读写权限。页面仅显示保存状态,不会回显明文。',
},
{
'key': 'GITEA_PROXY',
'env': 'GITEA_PROXY',
'default': '',
'label': 'Gitea 访问代理',
'group': 'gitea',
'sensitive': True,
'help': (
'服务器访问 Gitea 需要代理时填写;Gitea 通常部署在同内网,多数情况留空直连即可。'
),
},
# ===== 任务维护(后台「维护设置」页使用,不渲染在 GitHub 配置页) =====
{
'key': 'BUILD_RETENTION_DAYS',
'env': 'BUILD_RETENTION_DAYS',
'default': '30',
'label': '构建任务保留天数',
'group': 'maintenance',
'sensitive': False,
'help': '超过该天数的已结束任务(成功/失败/取消)及其安装包产物会被自动清理;0 表示永不自动清理。',
},
{
'key': 'DB_BACKUP_ENABLED',
'env': 'DB_BACKUP_ENABLED',
'default': '1',
'label': '启用数据库定时备份',
'group': 'maintenance',
'sensitive': False,
'help': '开启后维护进程每天自动备份一次数据库(含账号、配置方案、构建记录)。',
},
{
'key': 'DB_BACKUP_KEEP',
'env': 'DB_BACKUP_KEEP',
'default': '7',
'label': '数据库备份保留份数',
'group': 'maintenance',
'sensitive': False,
'help': '超出份数的最旧备份会被自动删除,建议 7~30。',
},
]
DEFS_BY_KEY = {d['key']: d for d in SETTING_DEFS}
SOURCE_DB = 'db' # 后台配置
SOURCE_ENV = 'env' # 环境变量
SOURCE_DEFAULT = 'default' # 内置默认值
SOURCE_LABELS = {
SOURCE_DB: '后台配置',
SOURCE_ENV: '环境变量',
SOURCE_DEFAULT: '默认值',
}
_CACHE_TTL = 15.0
_cache = {'ts': 0.0, 'rows': {}}
def _load_rows():
"""一次性读取全部后台配置,带短缓存。"""
now = time.time()
if now - _cache['ts'] > _CACHE_TTL:
try:
from .models import SiteSetting
_cache['rows'] = dict(SiteSetting.objects.values_list('key', 'value'))
except Exception:
# 迁移尚未执行等异常情况下退回环境变量,避免阻断请求
_cache['rows'] = {}
_cache['ts'] = now
return _cache['rows']
def invalidate_cache():
_cache['ts'] = 0.0
def get_source(key):
"""返回某项当前生效值的来源:db / env / default。"""
d = DEFS_BY_KEY[key]
rows = _load_rows()
if key in rows:
return SOURCE_DB
if os.environ.get(d['env']) is not None:
return SOURCE_ENV
return SOURCE_DEFAULT
def get_value(key):
"""按 后台配置 → 环境变量 → 默认值 的优先级返回生效值(始终为字符串)。"""
d = DEFS_BY_KEY[key]
rows = _load_rows()
if key in rows:
return rows[key]
return os.environ.get(d['env'], d['default'])
def is_overridden(key):
return get_source(key) == SOURCE_DB
def set_value(key, value):
"""写入后台配置覆盖。"""
from .models import SiteSetting
SiteSetting.objects.update_or_create(key=key, defaults={'value': value})
invalidate_cache()
def delete_value(key):
"""删除后台覆盖,回退到环境变量/默认值。"""
from .models import SiteSetting
SiteSetting.objects.filter(key=key).delete()
invalidate_cache()
def all_settings():
"""供后台页面渲染:每项定义 + 当前生效值 + 来源。"""
result = []
for d in SETTING_DEFS:
result.append({
**d,
'value': get_value(d['key']),
'source': get_source(d['key']),
})
return result
def is_github_configured():
"""当前所选构建平台是否具备发起构建的最低配置(保留函数名兼容既有调用)。"""
from .build_backends import get_backend
return get_backend().configured()
def config_warnings():
"""返回当前所选构建平台的配置隐患列表(中文),供页面提示。"""
from .build_backends import get_backend
return get_backend().warnings()