Skip to content

好学探索 · 打包发布操作手册 ​

CI 全关(GitHub Actions 无额度),发版 100% 本地 + ptang 服务器,不占 Actions 额度。 单镜像多架构(amd64 + arm64)推 ghcr,NAS 用户 docker compose pull 即更新。

配套:release-local.sh(一键脚本)、update-manifest.mjs(OTA manifest 同步)。

前置(一次性) ​

  1. ptang 服务器:已装 docker + buildx。~/.ssh/config 配 ptang 别名(同 PTPatronus:HostName 152.53.91.46 / User root / IdentityFile ~/.ssh/id_ed25519)。
  2. ghcr 包设 public:GitHub → 你的 Packages → tanqu → Package settings → Change visibility → Public(用户 docker pull 免登录)。
  3. GH_CLIENT_ID:GitHub → Settings → Developer settings → OAuth Apps → New OAuth App(Authorization callback URL 随意填),拿到 client_id,填入项目根 .env:
    GH_CLIENT_ID=你的client_id

    device flow 的 client_id 是公开标识符,不是密钥;它只用于发起授权,token 用完即 logout,本机/服务器都不留 ghcr 凭据。

  4. CI 已关:发版不触发任何 GitHub Actions(docker.yml 仅 tag 触发且依赖额度,本流程不靠它)。

关键地址 ​

项值
主仓(public)github.com/gntv456/tanqu
ghcr 镜像ghcr.io/gntv456/tanqu
OTA manifest rawhttps://raw.githubusercontent.com/gntv456/tanqu/main/update-manifest.json
ptang 构建目录/root/tanqu-build

每次发版(以 0.1.1 → 0.1.2 为例) ​

0. 改版本号(2 处源码) ​

bash
cd /d/HX-Tanqu
sed -i 's/0\.1\.1/0.1.2/g' package.json frontend/src/views/me.js

update-manifest.json 由 release-local.sh 自动同步,不用手改。

提交版本号:git add package.json frontend/src/views/me.js && git commit -m "chore: bump → 0.1.2"。

1. 一键发版 ​

bash
bash scripts/release-local.sh 0.1.2

脚本自动完成:

  1. ptang buildx/binfmt 准备(首次自动装 qemu)
  2. tar 传代码到 ptang(排除 node_modules/data/.git)
  3. ghcr device flow:打印 user_code,浏览器开 https://github.com/login/device 输入授权,回车继续(15 分钟内有效)
  4. ptang docker buildx build --platform linux/amd64,linux/arm64 --push 推 :0.1.2 + :latest,logout
  5. 本地 update-manifest.mjs 同步 latestVersion + docker tag + publishedAt

2. 编辑 releaseNotes + 提交 manifest ​

bash
# 手动编辑 update-manifest.json 的 releaseName / releaseNotes 后:
git add update-manifest.json
git commit -m "release: v0.1.2(manifest)"
git push origin main

push 后 raw 即生效(CDN 缓存 ~5min)。

3. 验证 ​

  • 镜像:docker pull ghcr.io/gntv456/tanqu:0.1.2 → 启动后关于页显示 version 0.1.2
  • OTA:部署的 compose 已默认带 UPDATE_MANIFEST_URL → 关于页「检查更新」提示 0.1.2
  • raw:curl -s https://raw.githubusercontent.com/gntv456/tanqu/main/update-manifest.json | grep latestVersion → 0.1.2

OTA 两条更新机制(别混淆) ​

机制触发你要做的
Web UI「检查更新」后端读 UPDATE_MANIFEST_URL 对比 latestVersion 与当前版本compose 设 UPDATE_MANIFEST_URL(默认已带),重启容器
docker 镜像更新:latest tag 被 pullpush 完 :latest 即可,用户 docker compose pull && docker compose up -d

两者独立:没设 UPDATE_MANIFEST_URL 只是 Web UI 不提示,不影响 :latest 拉镜像更新。


手动分步(脚本失败时) ​

bash
# a. 传码(Dockerfile multi-stage 自带 npm ci,不用传 node_modules/dist)
tar czf - --exclude='./node_modules' --exclude='./.git' --exclude='./data' \
  --exclude='./scripts/_*' --exclude='./tmp_*' \
  backend frontend Dockerfile entrypoint.sh package.json package-lock.json deploy docs \
  | ssh ptang "rm -rf /root/tanqu-build && mkdir -p /root/tanqu-build && tar xzf - -C /root/tanqu-build"

# b. ptang buildx 多架构 build + push(需先 device flow login)
ssh ptang "cd /root/tanqu-build && docker buildx build --platform linux/amd64,linux/arm64 \
  --build-arg VERSION=0.1.2 -t ghcr.io/gntv456/tanqu:0.1.2 -t ghcr.io/gntv456/tanqu:latest --push ."

常见坑 ​

  • ARM 构建慢:ptang 是 x86_64,arm64 靠 qemu 交叉编译(better-sqlite3 native 需编译),首次约 5–10 分钟;后续 Docker 层缓存会快。
  • device code 过期:15 分钟,过期重跑脚本即可(重新申请 code)。
  • manifest CDN 缓存:push 后 raw ~5min 才更新,验证时等一下。
  • ghcr 包未 public:用户 docker pull 需先 docker login ghcr.io,体验差——务必到 Package settings 设 Public。
  • .env 别提交:.env 在 .gitignore 内,GH_CLIENT_ID 放那里不会入仓;commit 前确认 git status 无 .env。

用 Claude Code(agent)一键发版 ​

让 Claude 自动跑 release-local.sh(你只浏览器授权一次 device code),关键是授权话术要「点名 + 具体」——Claude 自动模式的安全校验要求明确说出服务器、操作、版本、目标,笼统的"你自己发"会被拦。

发版前发给 Claude 的授权话术(照抄,改版本号) ​

我明确授权 Claude 执行 HX-Tanqu vX.Y.Z 发版:ssh 到 ptang 服务器(152.53.91.46),用 docker buildx 构建多架构镜像(linux/amd64, linux/arm64),push 到 ghcr.io/gntv456/tanqu:X.Y.Z 和 :latest,并同步 update-manifest.json、commit push 到 main。

发完这句,Claude 自动:传码 → 申请 device code → 把 user_code 给你 → 你浏览器输一次 → buildx 构建推送 → 同步 manifest → commit push。全程你只动一次。

ghcr 包页面 & 可见性 ​

  • 包地址:https://github.com/users/gntv456/packages/container/tanqu (⚠️ 不是 /pkgs/tanqu,正确路径是 /packages/container/tanqu;或从头像 → Your packages 进)
  • 可见性:关联 public repo 时通常继承 Public(用户 docker pull 免登录);若显示 Private,进 Package settings → Danger Zone → Change visibility → Public。

踩过的坑(别再踩) ​

  1. 项目级 .claude/settings.local.json 别加 broad allow(ssh */docker * 之类)——会被 Claude 当"自我提权"全面拦截,反而盖掉全局放行。ssh/docker 走全局 ~/.claude/settings.json 的 Bash(ssh *)、Bash(docker *) 即可(和 PTPatronus 一样)。
  2. 授权必须点名 + 具体:说清"ssh ptang(152.53.91.46)、docker buildx 构建、push ghcr.io/gntv456/tanqu:X.Y.Z",笼统的"你自己跑"达不到校验门槛。
  3. OAuth App 要启用 Device Flow:github.com/settings/developers → 你的 App → Device Flow → Enable(默认不开)。