PTPatronus 打包发布操作手册
闭源发布。源码留私有仓,只分发镜像/二进制/APK。本手册 = 本地打包 + ptang 服务器 docker + ghcr 发布 + OTA manifest,step-by-step 可直接抄。
配套阅读:发布与在线更新.md(机制)、各端发布步骤.md(各端细节)。本文是实操命令。
前置(一次性)
- 本机:node/npm + go + flutter(+ Visual Studio Desktop C++ 工作负载,打 windows 用)
~/.ssh/config配ptang别名:Host ptang HostName <生产服务器IP——勿写入任何仓库文件> User root Port 22 IdentityFile ~/.ssh/id_ed25519 IdentitiesOnly yes ServerAliveInterval 30 TCPKeepAlive yes- ptang 服务器:docker + git(已装)
- ghcr 包设 public:GitHub → Packages → pt-patronus → Package settings → Public(用户
docker pull免登录) .claude/settings.local.json放行主仓 push:{"permissions":{"allow":["Bash(git push origin main)"]}}(harness 默认拦 default-branch push)- CI 已全关——发版 100% 本地 + ptang,打 tag 不触发任何 Actions
关键地址速查
| 项 | 值 |
|---|---|
| 主仓(私有) | github.com/gntv456/pt-patronus |
| 插件市场仓(公开,兼托管 OTA manifest) | github.com/gntv456/ptpatronus-plugin-market |
| ghcr 镜像 | ghcr.io/gntv456/pt-patronus |
| OTA manifest raw URL | https://raw.githubusercontent.com/gntv456/ptpatronus-plugin-market/main/update-manifest.json |
| ghcr device flow client_id | 178c6fc778ccc68e1d6a |
| 产物网盘 | https://wwazg.lanzoub.com/b03anmtyxg(提取码 hxpt) |
| ptang 服务器 docker build 目录 | /root/ptpatronus-build/ |
| 本机 plugin-market staging | d:\ptpatronus-plugin-market |
每次发版(以 0.85.02 → 0.86.00 为例)
0. 改版本号(6 处源码)
bash
cd /d/PTPatronus
for f in backend/internal/version/version.go frontend/package.json \
mobile/lib/core/version.dart mobile/ohos/AppScope/app.json5 \
"mobile/ohos/signing/ptpatronus-release-profile-unsigned.json"; do
sed -i 's/0\.85\.02/0.86.00/g' "$f"
done
sed -i 's/0\.85\.02+13/0.86.00+14/' mobile/pubspec.yaml # build 号 +1
dist/system-*.js(embed 产物)、package-lock.json、update-manifest.json由下面 release-local.sh 自动同步,不用手改。
提交版本号:git add 上述 6 文件 → git commit -m "chore: bump 版本号 → 0.86.00"。
1. 本地打包(agent / android / windows)
bash
bash scripts/release-local.sh 0.86.00- 前端 build + embed → backend/internal/web/dist
- docker 步骤自动 skip(本机无 daemon,走第 2 步 ptang)
- agent(linux amd64/arm64)+ android apk(arm64/armv7a)+ windows zip →
dist/release-0.86.00/ - 末尾
scripts/update-manifest.mjs自动填update-manifest.json的 latestVersion + docker.image + 各产物 sha256
2. ptang 服务器 docker 打包
bash
# a. 传代码(tar 管道,排除大目录;Dockerfile multi-stage 自带 npm+go build,不用传 dist)
tar czf - \
--exclude='./node_modules' --exclude='./.git' --exclude='./frontend/node_modules' \
--exclude='./frontend/dist' --exclude='./mobile' --exclude='./backend/internal/web/dist' \
--exclude='./dist' --exclude='./data' --exclude='*.db' \
backend frontend Dockerfile entrypoint.sh docker-compose.example.yml scripts \
| ssh ptang "mkdir -p /root/ptpatronus-build && tar xzf - -C /root/ptpatronus-build"
# b. docker build(amd64;multi-stage:node:20 npm build → golang embed → alpine 运行)
ssh ptang "cd /root/ptpatronus-build && docker build --build-arg VERSION=0.86.00 \
-t ghcr.io/gntv456/pt-patronus:0.86.00 -t ghcr.io/gntv456/pt-patronus:latest ."⚠ 服务器是 x86_64,镜像单 amd64。用户有 ARM 部署需 buildx + qemu 出多架构(
--platform linux/amd64,linux/arm64)。
3. push ghcr(device flow,每次发版授权一次)
bash
# a. 申请 device code
ssh ptang 'curl -sS -X POST https://github.com/login/device/code \
-H "Accept: application/json" \
-d "client_id=178c6fc778ccc68e1d6a&scope=write:packages"'
# 返回 {"device_code":"<DC>","user_code":"XXXX-XXXX","expires_in":899,...}b. 浏览器开 https://github.com/login/device → 输 user_code → Authorize(15 分钟内;过期重跑 a)
bash
# c. 换 token + login + push 两个 tag + logout(token 不留服务器)
ssh ptang 'set -e
DC=<把 a 返回的 device_code 填这>
TOKEN=$(curl -sS -X POST https://github.com/login/oauth/access_token \
-H "Accept: application/json" \
-d "client_id=178c6fc778ccc68e1d6a&device_code='"$DC"'&grant_type=urn:ietf:params:oauth:grant-type:device_code" \
| grep -o "\"access_token\":\"[^\"]*\"" | head -1 | sed "s/.*\":\"//;s/\"//")
echo "$TOKEN" | docker login ghcr.io -u gntv456 --password-stdin
docker push ghcr.io/gntv456/pt-patronus:0.86.00
docker push ghcr.io/gntv456/pt-patronus:latest
docker logout ghcr.io'token 用完即 logout,服务器/本机都不留 ghcr 凭据(所以查不到历史 login,每次发版重新授权)。harness auto-mode 会拦 device code 请求,需用户本 session 明确说"push"/"同意"。
4. OTA manifest 推到公开仓
主仓私有(raw 外部 404),manifest 借公开的 plugin-market 仓托管。
bash
# 手填 update-manifest.json 的 targets.*.url(蓝奏云)+ releaseNotes 后:
cp /d/PTPatronus/update-manifest.json /d/ptpatronus-plugin-market/update-manifest.json
cd /d/ptpatronus-plugin-market
git config user.name "pt-patronus" # staging 没继承全局,首次要设
git config user.email "dev@pt-patronus.local"
git add update-manifest.json
git commit -m "OTA manifest 0.86.00"
git push origin mainpush 后 raw 即生效(CDN 缓存 ~5min):
bash
ssh ptang 'curl -sS https://raw.githubusercontent.com/gntv456/ptpatronus-plugin-market/main/update-manifest.json | grep latestVersion'
# 应见 "latestVersion": "0.86.00"5. 网盘 + 主仓提交
- 上传
dist/release-0.86.00/*到蓝奏云分享页(提取码 hxpt) update-manifest.json的targets.*.url填蓝奏云分享页 + releaseNotes 带提取码- 主仓提交 + push:
bash
cd /d/PTPatronus
git add update-manifest.json backend/internal/web/dist
git commit -m "build: 发版 0.86.00(dist + manifest)"
git push origin main6. 验证
- manifest:
ssh ptang 'curl -sS .../update-manifest.json | grep latestVersion'→ 0.86.00 - 镜像:
docker pull ghcr.io/gntv456/pt-patronus:0.86.00(或 :latest)→ 启动后关于页 version 0.86.00 - Web UI 检查更新:部署的 docker-compose 设
UPDATE_MANIFEST_URL: https://raw.githubusercontent.com/gntv456/ptpatronus-plugin-market/main/update-manifest.json→ 关于页「检查更新」提示 0.86.00
两条「更新」机制(别混淆)
| 机制 | 触发 | 你要做的 |
|---|---|---|
| Web UI「检查更新」 | 后端读 UPDATE_MANIFEST_URL manifest 的 latestVersion | 部署 compose 设 UPDATE_MANIFEST_URL(指向上面 raw),重启容器 |
| docker 镜像自动更新 | :latest tag pull(watchtower / 手动 docker compose pull && up -d) | push 完 :latest 即可,用户那边拉到就更新 |
两者独立:没设 UPDATE_MANIFEST_URL 只是 Web UI 不提示,不影响 :latest 拉镜像更新。
常见坑
- staging commit 报 email:d:\ptpatronus-plugin-market 没继承全局 git config,首次
git config user.name/email - 本机 docker daemon 500:Docker Desktop engine 卡,本机发不了 docker,走 ptang(本手册默认)
- device code 过期:15 分钟,过期重跑申请;harness 拦 device code 请求时,用户明确说"push"
- manifest CDN 缓存:push 后 raw ~5min 才更新,验证时等一下
- ARM 部署:服务器 x86 build 出单 amd64,ARM 用户需 buildx 多架构(见第 2 步注)