← 文档索引

Pangolin CI/CD 实现计划

#30 · 2026-07-05 · 阅读版 · 执行真相源 docs/superpowers/plans/2026-07-05-cicd.md(带 checkbox)· 设计 cicd-design.html

目标:tag 触发的「编译 → 测试 → 发版(Gitea release)→ 部署」全自动。镜像 jiu 的 scripts/ci/*.sh(逻辑)+ .gitea/workflows/*.yml(编排)。runner:nas(官网+服务端,容器化 node:20/golang:1.25)、mac(Android+macOS)、windows(Windows)。 CI「测试」= workflow_dispatch 手动触发跑一遍 + 观察产物/部署(非经典单元 TDD)。

全局约束

Phase 1 —— 基座 + 官网 + 服务端(无签名,可立即上线)

Task 1 · scripts/ci 基座

Create: scripts/ci/_env.sh · lib-forgejo.sh · notify.sh(抄 jiu 同名改 pangolin 专属值)
产出:_env.sh(镜像源 + ver_from_tag${ref#refs/tags/prefix-v} 参数展开);lib-forgejo.shforgejo_release_ensure / forgejo_upload_asset,curl+API);notify.sh。 验证:bash -n + shellcheck 0 告警 → commit。

Task 2 · checks 工作流(保留)

Modify: .gitea/workflows/ci.yml
现有 ci.yml(nas,shellcheck/openapi/redline/flutter/go test)保留;把 scripts/ci/*.sh 纳入 shellcheck 扫描。push 观察全绿。

Task 3 · 官网发布

Create: scripts/ci/compile-site.sh · deploy-site.sh · .gitea/workflows/deploy-site.yml
前置(基础设施,改机器前问用户):pangolin1 装 nginx/caddy 配 pangolin.yanmeiai.com vhost(web 根 /var/www/pangolin-site);CF DNS 指向 103.119.13.48(cf-api,记 baize);TLS 先 CF 橙云或并入 #25。 验证:dispatch → curl -I https://pangolin.yanmeiai.com/ 200。

Task 4 · 服务端发布(固化 F3/F4,带回滚)

Create: scripts/ci/compile-backend.sh · release-server.sh · deploy-server.sh · .gitea/workflows/deploy-server.yml
#!/usr/bin/env bash
set -euo pipefail
DB=/var/lib/pangolin/pangolin.db; BIN=/usr/local/bin; TAG="$1"
scp server/out/pangolin-{server,agent,migrate} pangolin1:/tmp/
ssh pangolin1 "bash -s" <<REMOTE
set -euo pipefail
systemctl stop pangolin-server
runuser -u pangolin -- sqlite3 "$DB" 'PRAGMA wal_checkpoint(TRUNCATE);'
cp -p "$DB" "$DB.bak-pre-$TAG"
if ! runuser -u pangolin -- env DB_DRIVER=sqlite DB_DSN=$DB /tmp/pangolin-migrate up; then
  echo "!! migrate 失败,回滚"; cp -p "$DB.bak-pre-$TAG" "$DB"; systemctl start pangolin-server; exit 1
fi
cp -p "$BIN/pangolin-server" "$BIN/pangolin-server.bak-$TAG" || true
install -m755 /tmp/pangolin-server "$BIN/pangolin-server"
install -m755 /tmp/pangolin-agent  "$BIN/pangolin-agent"
install -m755 /tmp/pangolin-migrate "$BIN/pangolin-migrate"
systemctl start pangolin-server; systemctl is-active pangolin-server
REMOTE
curl -fsS -m10 --retry 5 --retry-connrefused http://103.119.13.48:8080/healthz >/dev/null && echo healthz OK
deploy-server.yml:tag server-v* + dispatch,nas,compile → test → release → deploy。 验证:dispatch → migrate 版本前进 + /healthz 200 + 行数守恒。

Task 5 · scripts/ci/test.sh

test.sh servergolang:1.25 go test ./...test.sh clientflutter test。接入 deploy-server 的 test 步骤。
Phase 2 —— Android(解锁官网下载链接)

Task 6 · Android gradle 接 release 签名

Modify: client/android/app/build.gradle · Create: keystore.properties(gitignore)
signingConfigs.release,从 env/keystore.properties 读 keystore + 三密码(ANDROID_*);buildTypes.release.signingConfig 指向它。本机验证 apksigner verify --print-certs 显示 CN=Pangolin(非 debug)。

Task 7 · Android CI

Create: scripts/ci/compile-android.sh · release-client.sh · .gitea/workflows/build-android.yml
compile-android.shbuild-libbox.sh android(JDK17/NDK≥28)→ secrets 落 keystore → flutter build apk --release --split-per-abi --dart-define=PANGOLIN_API_URL=…build-android.yml:tag client-v*runs-on: mac,provision → compile → release。验证:真机 adb install -r 可用。

Task 8 · 官网下载链接接 Android

Modify: web/website/src/config/site.ts(downloads.android)· Download.astro
site.ts.downloads.android = Forgejo /releases/latest/download/<asset> 稳定 URL(不支持则构建期烘焙)。重部署官网,点击落到最新 apk。关 todo 30A(Android 部分)。
Phase 3 —— macOS + Windows

Task 9 · macOS 签名+公证 dmg

Create: scripts/ci/compile-macos.sh · .gitea/workflows/build-macos.yml(证书导入+notarytool 可复用 jiu compile-macos.sh)
建临时 keychain → MACOS_DEVELOPER_ID_CERT_P12_BASE64 导入 → 两个描述文件解码装入 → 递增 CURRENT_PROJECT_VERSION → Xcode Developer ID 构建 app+sysext → notarytool submit --key-id $APPSTORE_API_KEY_ID --issuer $APPSTORE_API_ISSUER_ID --waitstapler → dmg。runs-on: mac。验证:另一台 mac spctl -a -vv + stapler validate 通过。

Task 10 · Windows 安装包

Create: scripts/ci/compile-windows.sh · .gitea/workflows/build-windows.yml(参照 jiu install-innosetup.ps1)
flutter build windows --release → Inno Setup 打包(先不代码签名,首装有 SmartScreen 提示可接受)。tag client-v*/winbuild*runs-on: windows。验证:windows 机装上能连。

Task 11 · 下载链接全端闭环

site.ts.downloads 补齐 macos/windows;三端按钮全接 release。客户端发版触发官网重部署刷新。关 todo 30A/30B。

不在本计划

iOS(G)、备份/容灾(#26)、TLS(#25)、Windows 代码签名、上架商店。