Initial commit: rdgen with GitHub/Gitea dual build backend

This commit is contained in:
naeeo
2026-09-29 19:56:02 +08:00
commit a3686a49d4
103 changed files with 20007 additions and 0 deletions
+171
View File
@@ -0,0 +1,171 @@
import secrets
from django.conf import settings
from django.db import models
# GitHub Actions 运行状态 -> 中文展示文案
STATUS_LABELS = {
"Starting generator...please wait": "正在启动构建任务",
"queued": "排队中",
"in_progress": "构建中",
"success": "构建成功",
"failure": "构建失败",
"cancelled": "已取消",
"timed_out": "已超时",
"skipped": "已跳过",
"action_required": "等待人工处理",
}
# 状态对应的徽标样式(模板中使用)
STATUS_BADGE = {
"Starting generator...please wait": "badge-info",
"queued": "badge-info",
"in_progress": "badge-info",
"success": "badge-success",
"failure": "badge-danger",
"cancelled": "badge-warning",
"timed_out": "badge-warning",
"skipped": "badge-secondary",
"action_required": "badge-warning",
}
PLATFORM_LABELS = {
"windows": "Windows 64 位",
"windows-x86": "Windows 32 位",
"linux": "Linux",
"android": "Android",
"macos": "macOS",
}
def generate_token_key():
return secrets.token_hex(20)
class GithubRun(models.Model):
uuid = models.CharField("任务 UUID", max_length=100, db_index=True)
status = models.CharField("构建状态", max_length=100, default="queued")
github_run_id = models.BigIntegerField("GitHub 运行编号", null=True, blank=True)
# 构建平台:github / gitea;历史任务默认 github。切换平台后旧任务仍按此值查询状态
backend = models.CharField("构建平台", max_length=20, default="github")
platform = models.CharField("目标平台", max_length=20, blank=True, default="")
filename = models.CharField("文件名", max_length=200, blank=True, default="")
# 提交时的表单快照(纯字符串/数值,图片为 data URL),供失败后「一键重试」重新派发
config_data = models.JSONField("构建配置快照", blank=True, default=dict)
created_by = models.ForeignKey(
settings.AUTH_USER_MODEL,
verbose_name="提交用户",
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="builds",
)
created_at = models.DateTimeField("提交时间", auto_now_add=True)
updated_at = models.DateTimeField("更新时间", auto_now=True)
class Meta:
verbose_name = "构建任务"
verbose_name_plural = "构建任务"
ordering = ["-created_at"]
def __str__(self):
return f"{self.filename or self.uuid}({self.status_label()})"
def status_label(self):
return STATUS_LABELS.get(self.status, self.status)
def status_badge(self):
return STATUS_BADGE.get(self.status, "badge-secondary")
def platform_label(self):
return PLATFORM_LABELS.get(self.platform, self.platform or "未知平台")
def is_finished(self):
return self.status in ("success", "failure", "cancelled", "timed_out", "skipped")
@property
def github_log_url(self):
if self.github_run_id:
# 局部导入避免循环依赖;按任务记录的平台生成对应站点的日志链接
from .build_backends import get_backend
return get_backend(self.backend or 'github').log_url(self.github_run_id)
return ""
def short_uuid(self):
return self.uuid[:8] if len(self.uuid) >= 8 else self.uuid
class SiteSetting(models.Model):
"""后台可改的站点配置(键值存储)。
取值优先级由 app_settings 统一处理:后台配置(本表)→ 环境变量 → 默认值,
因此历史的环境变量部署方式继续有效。
"""
key = models.CharField("配置项", max_length=50, primary_key=True)
value = models.TextField("配置值", blank=True, default='')
updated_at = models.DateTimeField("更新时间", auto_now=True)
class Meta:
verbose_name = "站点配置"
verbose_name_plural = "站点配置"
def __str__(self):
return self.key
class SavedConfig(models.Model):
"""用户保存的客户端构建配置方案(与账号绑定,可在定制页直接载入、可导出/导入)。"""
owner = models.ForeignKey(
settings.AUTH_USER_MODEL,
verbose_name="所属用户",
on_delete=models.CASCADE,
related_name="saved_configs",
)
name = models.CharField("方案名称", max_length=100)
data = models.JSONField("配置内容", default=dict)
created_at = models.DateTimeField("创建时间", auto_now_add=True)
updated_at = models.DateTimeField("更新时间", auto_now=True)
class Meta:
verbose_name = "构建配置方案"
verbose_name_plural = "构建配置方案"
unique_together = [('owner', 'name')]
ordering = ["-updated_at"]
def __str__(self):
return f"{self.name}({self.owner})"
def platform_label(self):
return PLATFORM_LABELS.get(self.data.get('platform', ''), '未指定平台')
@property
def version_label(self):
return self.data.get('version', '') or '未指定版本'
class ApiToken(models.Model):
"""供 JSON API(如 rdgen-cli)使用的个人访问令牌"""
key = models.CharField("令牌", max_length=64, primary_key=True, default=generate_token_key, editable=False)
name = models.CharField("令牌名称", max_length=100, help_text="便于识别用途,例如:CI 构建机")
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
verbose_name="所属用户",
on_delete=models.CASCADE,
related_name="api_tokens",
)
is_active = models.BooleanField("启用", default=True)
created_at = models.DateTimeField("创建时间", auto_now_add=True)
last_used_at = models.DateTimeField("最后使用时间", null=True, blank=True)
class Meta:
verbose_name = "API 令牌"
verbose_name_plural = "API 令牌"
ordering = ["-created_at"]
def __str__(self):
return f"{self.name}({self.user})"