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
+351
View File
@@ -0,0 +1,351 @@
{% extends "base.html" %}
{% block title %}构建平台配置 · RustDesk 客户端定制平台{% endblock %}
{% block content %}
<nav class="breadcrumb">
<a href="{% url 'dashboard' %}">后台管理</a>
<span class="breadcrumb-sep">/</span>
<span>构建平台配置</span>
</nav>
<div class="page-head">
<h1 class="page-title">
<svg class="icon"><use href="#i-sliders"/></svg>
构建平台配置
</h1>
<p class="page-subtitle">
选择实际执行构建任务的平台:GitHub Actions(云托管构建机)或自建 Gitea Actions(构建机自备、可全内网运行)。
支持在本页直接配置(优先级最高),也继续兼容 docker-compose 环境变量方式。
</p>
</div>
{# ===== 配置状态总览 ===== #}
<div class="card config-card">
<div class="card-header">
<svg class="icon"><use href="#i-shield"/></svg> 配置状态检查<span class="platform-tag" style="margin-left:8px">当前平台:{{ build_platform_label }}</span>
</div>
<div class="card-body">
{% if build_ready and not warnings %}
<div class="config-ok">
<svg class="icon"><use href="#i-check-circle"/></svg>
{{ build_platform_label }} 构建服务配置完整,可以正常提交客户端构建任务。
</div>
{% else %}
<ul class="config-check-list">
{% if build_ready %}
<li class="is-ok"><svg class="icon"><use href="#i-check-circle"/></svg> {{ build_platform_label }} 连接信息已配置</li>
{% else %}
<li class="is-bad"><svg class="icon"><use href="#i-alert"/></svg> {{ build_platform_label }} 连接信息缺失,暂无法触发构建</li>
{% endif %}
{% for w in warnings %}
<li class="is-warn"><svg class="icon"><use href="#i-alert"/></svg> {{ w }}</li>
{% endfor %}
</ul>
{% endif %}
</div>
</div>
{# ===== 配置表单 ===== #}
<form method="post" action="{% url 'github_settings' %}" class="settings-form">
{% csrf_token %}
{# --- 构建平台选择(自定义平台卡,单选) --- #}
<div class="card">
<div class="card-header"><svg class="icon"><use href="#i-sliders"/></svg> 构建平台</div>
<div class="card-body">
<p class="card-desc">切换后仅影响新提交的构建任务;历史任务仍保存在原平台并可继续查询状态与日志。</p>
<div class="build-platform-grid">
<label class="platform-card {% if build_platform != 'gitea' %}active{% endif %}" data-platform-card="github">
<input type="radio" name="build_platform" value="github" class="visually-hidden"
{% if build_platform != 'gitea' %}checked{% endif %}>
<svg class="icon brand-github"><use href="#b-github"/></svg>
<div class="platform-name">GitHub Actions</div>
<div class="platform-desc">官方云托管 Windows / macOS / Linux 构建机,零运维;国内网络可能需要代理。</div>
</label>
<label class="platform-card {% if build_platform == 'gitea' %}active{% endif %}" data-platform-card="gitea">
<input type="radio" name="build_platform" value="gitea" class="visually-hidden"
{% if build_platform == 'gitea' %}checked{% endif %}>
<svg class="icon"><use href="#b-gitea"/></svg>
<div class="platform-name">Gitea Actions(自建)</div>
<div class="platform-desc">API 与工作流语法兼容 GitHub,可全内网运行、回传快;需自备全部构建机。</div>
</label>
</div>
</div>
</div>
{# --- 各配置分组(platform 组已在上方自定义渲染) --- #}
{% for group_key, group_title, group_desc in groups %}{% if group_key != 'platform' %}
<div class="card backend-panel
{% if group_key == 'gitea' %}panel-gitea{% if build_platform != 'gitea' %} panel-hidden{% endif %}
{% elif group_key == 'basic' or group_key == 'network' %}panel-github{% if build_platform == 'gitea' %} panel-hidden{% endif %}{% endif %}">
<div class="card-header"><svg class="icon"><use href="#i-sliders"/></svg> {{ group_title }}</div>
<div class="card-body">
<p class="card-desc">{{ group_desc }}</p>
{% for row in rows %}{% if row.group == group_key %}
<div class="field setting-row{% if row.key == 'SH_SECRET' %} panel-github{% if build_platform == 'gitea' %} panel-hidden{% endif %}{% endif %}">
<label class="setting-label" for="{{ row.field.id_for_label }}">
{{ row.label }}
<span class="source-badge source-{{ row.source }}">{{ row.source_label }}</span>
</label>
{{ row.field }}
{% if row.sensitive %}
<div class="secret-meta">
<label class="clear-check" for="{{ row.clear_field.id_for_label }}">
{{ row.clear_field }} 清除后台配置,回退到环境变量/默认值
</label>
{% if row.source == 'db' %}
<span class="secret-state is-set">已在后台保存</span>
{% elif row.source == 'env' %}
<span class="secret-state is-env">已通过环境变量配置</span>
{% else %}
<span class="secret-state is-empty">未配置(使用默认值)</span>
{% endif %}
</div>
{% endif %}
{% if row.help %}<div class="field-hint">{{ row.help }}</div>{% endif %}
</div>
{% endif %}{% endfor %}
</div>
</div>
{% endif %}{% endfor %}
{# --- 保存与连接测试(始终可见,测试目标跟随当前所选平台) --- #}
<div class="card settings-submit-card">
<div class="card-body settings-actions">
<div class="btn-row">
<button type="submit" class="btn btn-primary">
<svg class="icon"><use href="#i-save"/></svg> 保存配置
</button>
<button type="button" class="btn btn-secondary" id="testBuildBtn">
<svg class="icon"><use href="#i-zap"/></svg> <span id="testBuildBtnLabel">测试 GitHub 连接</span>
</button>
</div>
<div id="testResult" class="test-result" hidden></div>
</div>
</div>
</form>
{# ===== GitHub 配置引导 ===== #}
<div class="card guide-card guide-panel guide-github {% if build_platform == 'gitea' %}panel-hidden{% endif %}">
<div class="card-header">
<svg class="icon brand-github"><use href="#b-github"/></svg> GitHub 首次配置引导(约 5 分钟)
</div>
<div class="card-body">
<ol class="guide-steps">
<li>
<div class="guide-title">Fork 构建仓库</div>
<p>
打开上游仓库 <a href="https://github.com/bryangerlach/rdgen" target="_blank" rel="noopener">github.com/bryangerlach/rdgen
<svg class="icon icon-inline"><use href="#i-external"/></svg></a>,
点击右上角 <strong>Fork</strong> 复制到你自己的 GitHub 账号下。
</p>
</li>
<li>
<div class="guide-title">启用 GitHub Actions</div>
<p>
进入 Fork 后的仓库页面,打开
<a href="https://github.com/{% if gh_user %}{{ gh_user }}{% else %}你的用户名{% endif %}/{% if gh_repo %}{{ gh_repo }}{% else %}rdgen{% endif %}/actions"
target="_blank" rel="noopener">Actions 页面
<svg class="icon icon-inline"><use href="#i-external"/></svg></a>,
如页面提示则点击绿色的 <strong>Enable Actions</strong> 按钮。
</p>
</li>
<li>
<div class="guide-title">创建 Fine-grained 访问令牌(PAT)</div>
<p>
打开
<a href="https://github.com/settings/personal-access-tokens/new" target="_blank" rel="noopener">
Generate new token <svg class="icon icon-inline"><use href="#i-external"/></svg></a>,
按如下设置后生成,并把令牌(github_pat_ 开头)填入上方「GitHub 访问令牌」:
</p>
<ul class="guide-sublist">
<li><strong>Repository access</strong>:选择 Only select repositories,勾选你 Fork 的仓库</li>
<li><strong>Repository permissions</strong>:Actions 设为 <strong>Read and write</strong>,Workflows 设为 <strong>Read and write</strong></li>
<li>Expiration 建议按需设置,过期后需要回到这里更新令牌</li>
</ul>
</li>
<li>
<div class="guide-title">添加两个仓库 Secret</div>
<p>
打开仓库
<a href="https://github.com/{% if gh_user %}{{ gh_user }}{% else %}你的用户名{% endif %}/{% if gh_repo %}{{ gh_repo }}{% else %}rdgen{% endif %}/settings/secrets/actions"
target="_blank" rel="noopener">Settings → Secrets and variables → Actions
<svg class="icon icon-inline"><use href="#i-external"/></svg></a>,
分别 New repository secret:
</p>
<ul class="guide-sublist">
<li><strong>GENURL</strong>:本平台的公网访问地址,须与上方「本平台外部访问地址」一致,例如 https://rdgen.example.com</li>
<li><strong>ZIP_PASSWORD</strong>:一个随机强密码(可用 <code>python3 -c 'import secrets; print(secrets.token_hex(100))'</code> 生成),
须与上方「配置压缩包密码」<strong>完全一致</strong></li>
</ul>
</li>
<li>
<div class="guide-title">保存并验证</div>
<p>填写上方表单后点击「保存配置」,再点击「测试 GitHub 连接」,看到「连接正常」提示即配置完成,可以去客户端定制页提交构建了。</p>
</li>
</ol>
</div>
</div>
{# ===== Gitea 配置引导 ===== #}
<div class="card guide-card guide-panel guide-gitea {% if build_platform != 'gitea' %}panel-hidden{% endif %}">
<div class="card-header">
<svg class="icon"><use href="#b-gitea"/></svg> Gitea 首次配置引导(需自备 Gitea 与构建机)
</div>
<div class="card-body">
<ol class="guide-steps">
<li>
<div class="guide-title">部署 Gitea 1.27+ 并准备构建仓库</div>
<p>
自建一个 Gitea 实例(建议 1.27 或更高版本,低版本不支持运行详情回传),
把本项目仓库推送到该实例(仓库内含 <code>.gitea/workflows</code> 适配工作流)。
<a href="https://docs.gitea.com/usage/actions/quickstart" target="_blank" rel="noopener">
官方 Quick Start <svg class="icon icon-inline"><use href="#i-external"/></svg></a>
</p>
</li>
<li>
<div class="guide-title">启用仓库 Actions</div>
<p>
进入
{% if gitea_server and gitea_owner %}
<a href="{{ gitea_server }}/{{ gitea_owner }}/{{ gitea_repo|default:'rdgen' }}/settings" target="_blank" rel="noopener">
仓库设置页 <svg class="icon icon-inline"><use href="#i-external"/></svg></a>
{% else %}仓库设置页{% endif %}
,勾选 <strong>Enable Repository Actions</strong>。
</p>
</li>
<li>
<div class="guide-title">注册 act_runner 构建机</div>
<p>在仓库 Settings → Actions → Runners 创建注册令牌,并在构建机上安装注册 act_runner:</p>
<ul class="guide-sublist">
<li><strong>Linux</strong>:可用 Docker 模式(需预装 QEMU 以构建 arm64);</li>
<li><strong>Windows</strong>:只能 host 模式直接跑在 Windows 机器上(MSVC/Flutter/vcpkg 环境);</li>
<li><strong>macOS</strong>:只能 host 模式跑在 Apple 硬件上;</li>
<li>runner 自定义标签需与工作流一致:<code>ubuntu-22.04</code>、<code>ubuntu-22.04-arm</code>、<code>windows-2022</code>、<code>macos-14</code>、<code>macos-15-intel</code>。</li>
</ul>
</li>
<li>
<div class="guide-title">配置仓库 Secrets</div>
<p>
在仓库 Settings → Actions → Secrets 中添加
<strong>GENURL</strong>(本平台地址)与 <strong>ZIP_PASSWORD</strong>(与上方完全一致);
如需 Android/macOS 签名,再添加 ANDROID_SIGNING_KEY、MACOS_P12_BASE64、SIGN_BASE_URL、SIGN_API_KEY。
</p>
</li>
<li>
<div class="guide-title">第三方 actions 的网络说明</div>
<p>
工作流使用的第三方 action 默认从 github.com 拉取;纯内网环境请为 runner 配置出网白名单,
或在 Gitea 的 <code>app.ini</code> 配置 <code>[actions].DEFAULT_ACTIONS_URL</code> 走自建 action 镜像。
完整部署步骤(含 vcpkg 文件缓存配置)见项目 setup.md 的「Gitea 部署附录」。
</p>
</li>
<li>
<div class="guide-title">保存并验证</div>
<p>填写上方 Gitea 配置后点击「保存配置」,再点击「测试 Gitea 连接」,看到「连接正常」提示即可提交构建。</p>
</li>
</ol>
</div>
</div>
{# ===== 环境变量方式说明 ===== #}
<div class="card">
<div class="card-header">
<svg class="icon"><use href="#i-server"/></svg> 环境变量方式(可选,继续支持)
</div>
<div class="card-body">
<p class="card-desc">
也可以在 <code>docker-compose.yml</code> 的 environment 中配置以下变量,容器重启后自动生效;
本页保存的同名配置优先级更高(值与环境变量相同时会自动回退,不产生重复覆盖)。
</p>
<div class="table-wrap">
<table class="table">
<thead><tr><th>环境变量</th><th>对应配置</th><th>说明</th></tr></thead>
<tbody>
<tr><td class="mono">BUILD_PLATFORM</td><td>构建平台</td><td>github(默认)或 gitea</td></tr>
<tr><td class="mono">GHUSER</td><td>GitHub 用户名</td><td>Fork 仓库所在账号</td></tr>
<tr><td class="mono">GHBEARER</td><td>GitHub 访问令牌</td><td>Fine-grained PAT,Actions/Workflows 读写</td></tr>
<tr><td class="mono">GENURL</td><td>平台外部访问地址</td><td>两平台共用,供构建机回传产物,公网/内网可访问</td></tr>
<tr><td class="mono">ZIP_PASSWORD</td><td>配置压缩包密码</td><td>两平台共用,须与仓库 Secret 一致</td></tr>
<tr><td class="mono">REPONAME</td><td>GitHub 仓库名称</td><td>默认 rdgen</td></tr>
<tr><td class="mono">GHBRANCH</td><td>GitHub 工作流分支</td><td>默认 master</td></tr>
<tr><td class="mono">PROTOCOL</td><td>平台访问协议</td><td>https(默认)或 http</td></tr>
<tr><td class="mono">SH_SECRET</td><td>GitHub 自托管 Runner 密钥</td><td>仅 GitHub 自托管构建时使用</td></tr>
<tr><td class="mono">WEBHOOK_SECRET</td><td>回调校验密钥</td><td>两平台共用,留空不校验</td></tr>
<tr><td class="mono">GH_PROXY</td><td>GitHub 访问代理</td><td>如 http://host:port,留空直连</td></tr>
<tr><td class="mono">GITEA_SERVER_URL</td><td>Gitea 服务器地址</td><td>如 https://gitea.example.com</td></tr>
<tr><td class="mono">GITEA_TOKEN</td><td>Gitea 访问令牌</td><td>需仓库 Actions 读写权限</td></tr>
<tr><td class="mono">GITEA_OWNER</td><td>Gitea 仓库属主</td><td>用户名或组织名</td></tr>
<tr><td class="mono">GITEA_REPO</td><td>Gitea 仓库名称</td><td>默认 rdgen</td></tr>
<tr><td class="mono">GITEA_BRANCH</td><td>Gitea 工作流分支</td><td>默认 master</td></tr>
<tr><td class="mono">GITEA_PROXY</td><td>Gitea 访问代理</td><td>内网直连通常留空</td></tr>
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}
{% block head_extra %}
<script>
document.addEventListener('DOMContentLoaded', function () {
var radios = document.querySelectorAll('input[name=build_platform]');
var btn = document.getElementById('testBuildBtn');
var btnLabel = document.getElementById('testBuildBtnLabel');
var box = document.getElementById('testResult');
function currentPlatform() {
var checked = document.querySelector('input[name=build_platform]:checked');
return checked ? checked.value : 'github';
}
function syncPanels() {
var platform = currentPlatform();
document.querySelectorAll('.panel-gitea, .guide-gitea').forEach(function (el) {
el.classList.toggle('panel-hidden', platform !== 'gitea');
});
document.querySelectorAll('.panel-github, .guide-github').forEach(function (el) {
el.classList.toggle('panel-hidden', platform !== 'github');
});
document.querySelectorAll('[data-platform-card]').forEach(function (card) {
card.classList.toggle('active', card.getAttribute('data-platform-card') === platform);
});
btnLabel.textContent = platform === 'gitea' ? '测试 Gitea 连接' : '测试 GitHub 连接';
}
radios.forEach(function (radio) { radio.addEventListener('change', syncPanels); });
syncPanels();
btn.addEventListener('click', function () {
var platform = currentPlatform();
btn.disabled = true;
box.hidden = false;
box.className = 'test-result is-loading';
box.textContent = platform === 'gitea' ? '正在调用 Gitea API 验证配置…' : '正在调用 GitHub API 验证配置…';
var csrfToken = document.querySelector('[name=csrfmiddlewaretoken]').value;
fetch('{% url "test_build" %}', {
method: 'POST',
headers: {
'X-CSRFToken': csrfToken,
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
},
body: 'platform=' + encodeURIComponent(platform),
})
.then(function (r) { return r.json().then(function (j) { return {ok: r.ok && j.ok, message: j.message}; }); })
.then(function (res) {
box.className = 'test-result ' + (res.ok ? 'is-ok' : 'is-bad');
box.textContent = res.message;
})
.catch(function () {
box.className = 'test-result is-bad';
box.textContent = '测试请求失败,请检查网络或服务日志。';
})
.finally(function () {
btn.disabled = false;
});
});
});
</script>
{% endblock %}