- 响应式项目首页 (Landing, 含 R2 APK 下载) + 路由 /home 调整 - OTA 升级: tauri-plugin-hotswap (lib.rs/main.rs 拆分, 客户端热替换) - OTA 服务端 (check/bundle/manifest-web) + build-ota/genkey/upload 脚本 - 密钥/凭据统一存配置中心 (signing + ota + cloudflare 分组) - Android CI (android-* 分支) + OTA CI (手动触发), 产物上传 R2 - 修复 tsc/构建阻塞问题
112 lines
4.6 KiB
YAML
112 lines
4.6 KiB
YAML
name: OTA Frontend Build & Sign
|
|
|
|
# 手动触发 (发版前用): 构建前端 → 打生产 dist 的 OTA 升级包 (minisign 签名) → 上传 R2
|
|
# 产物:
|
|
# - ota-package/wardrobe-ota.tar.gz (前端替换包)
|
|
# - ota-package/latest.json (manifest, 客户端 check 用)
|
|
# 存储: Cloudflare R2 store/ota/ (公开桶)
|
|
# 依赖配置注册中心 (bh.vps.honor3.com:8008):
|
|
# - service-wardrobe / ota : MINISIGN_PRIVATE_KEY (整段 .key 内容, 多行)
|
|
# - CommonExternalService / cloudflare : CF_API_TOKEN, CF_R2_PUBLIC_URL
|
|
# 注意: 不修改 src-tauri/tauri.conf.json 的 pubkey, 换密钥请手动改 conf 并 commit。
|
|
# 部署 server (托管 OTA check 端点 + 首页 dist) 见 README "OTA 升级 与 首页" 章节。
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
sequence:
|
|
description: 'OTA sequence (单调递增整数, 留空用 timestamp)'
|
|
required: false
|
|
type: string
|
|
notes:
|
|
description: '发布说明 (写入 latest.json.notes)'
|
|
required: false
|
|
type: string
|
|
default: ''
|
|
|
|
jobs:
|
|
build-ota:
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
env:
|
|
CONFIG_CENTER_URL: '${{ secrets.CONFIG_CENTER_URL }}'
|
|
CONFIG_CENTER_TOKEN: '${{ secrets.CONFIG_CENTER_TOKEN }}'
|
|
REGISTRY_URL_FALLBACK: 'http://bh.vps.honor3.com:8008'
|
|
CFG_PROJECT_SIGNING: 'proj-mtwjnvir-k52zvp'
|
|
CFG_PROJECT_R2: 'proj-mts0s5jo-fb3rz7'
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: https://gitea.com/actions/checkout@v4
|
|
|
|
- name: Setup Node
|
|
uses: https://gitea.com/actions/setup-node@v4
|
|
with:
|
|
node-version: 22
|
|
|
|
- name: Install deps
|
|
run: npm ci --no-audit --no-fund
|
|
|
|
- name: Build frontend
|
|
# 复用 vite build 产物 (同时是 OTA bundle 内容)
|
|
run: npm run build
|
|
|
|
- name: Install minisign
|
|
run: sudo apt-get update && sudo apt-get install -y minisign
|
|
|
|
- name: Fetch config center (minisign key + R2)
|
|
run: |
|
|
set -euo pipefail
|
|
export CONFIG_CENTER_URL="${CONFIG_CENTER_URL:-$REGISTRY_URL_FALLBACK}"
|
|
python3 - <<'PYEOF'
|
|
import json, os, urllib.request
|
|
url = os.environ["CONFIG_CENTER_URL"]
|
|
token = os.environ.get("CONFIG_CENTER_TOKEN", "") or ""
|
|
wanted = {}
|
|
req = urllib.request.Request(f"{url}/api/projects/{os.environ['CFG_PROJECT_SIGNING']}/configs")
|
|
if token:
|
|
req.add_header("Authorization", "Bearer " + token)
|
|
with urllib.request.urlopen(req, timeout=20) as r:
|
|
data = json.load(r).get("data", [])
|
|
for cfg in data:
|
|
if cfg.get("key") in ("MINISIGN_PRIVATE_KEY",):
|
|
wanted[cfg["key"]] = cfg.get("value", "")
|
|
req = urllib.request.Request(f"{url}/api/projects/{os.environ['CFG_PROJECT_R2']}/configs")
|
|
if token:
|
|
req.add_header("Authorization", "Bearer " + token)
|
|
with urllib.request.urlopen(req, timeout=20) as r:
|
|
data = json.load(r).get("data", [])
|
|
for cfg in data:
|
|
if cfg.get("key") in ("CF_API_TOKEN", "CF_R2_PUBLIC_URL"):
|
|
wanted[cfg["key"]] = cfg.get("value", "")
|
|
# GITHUB_ENV 多行值需用 heredoc 语法; 单行值直接 NAME=value
|
|
with open(os.environ["GITHUB_ENV"], "a", encoding="utf-8") as f:
|
|
for k, v in wanted.items():
|
|
if "\n" in v or v.startswith("untrusted comment"):
|
|
f.write(f"{k}<<EOF\n{v}\nEOF\n")
|
|
else:
|
|
f.write(f"{k}={v}\n")
|
|
missing = [k for k in ("MINISIGN_PRIVATE_KEY", "CF_API_TOKEN") if k not in wanted]
|
|
if missing:
|
|
raise SystemExit("配置中心缺少: " + ", ".join(missing))
|
|
PYEOF
|
|
|
|
- name: Build & sign OTA package
|
|
# MINISIGN_PRIVATE_KEY 由上一步写入 GITHUB_ENV, 已是本步的真实环境变量,
|
|
# build-ota.mjs 直接读 process.env.MINISIGN_PRIVATE_KEY, 无需再映射
|
|
env:
|
|
OTA_NOTES: ${{ inputs.notes }}
|
|
run: |
|
|
set -euo pipefail
|
|
ARGS="--out ota-package"
|
|
if [ -n "${{ inputs.sequence }}" ]; then ARGS="${ARGS} --sequence ${{ inputs.sequence }}"; fi
|
|
if [ -n "${OTA_NOTES}" ]; then ARGS="${ARGS} --notes ${OTA_NOTES}"; fi
|
|
node scripts/build-ota.mjs ${ARGS}
|
|
echo "===== latest.json ====="
|
|
cat ota-package/latest.json
|
|
echo "===== bundle sha256 ====="
|
|
sha256sum ota-package/wardrobe-ota.tar.gz
|
|
|
|
- name: Upload OTA package to Cloudflare R2
|
|
run: |
|
|
bash scripts/upload-ota-r2.sh ota-package |