fdc13ea06c
Deploy Client / build-windows (push) Successful in 1m41s
Deploy Client / build-android (push) Successful in 4m40s
Deploy Client / build-macos (push) Successful in 7m30s
Deploy Client / build-ios (push) Failing after 11m51s
Deploy Client / release-deploy (push) Has been skipped
client-v1.1.1 首跑:4 平台 build 全绿,但 release-deploy 卡在「Release → Forgejo」curl exit 28(超时,3m3s=release_ensure 60s×3 重试耗尽)。根因: release-deploy `runs-on: mac`(mac-pangolin-2)访问 git.51yanmei.com 走 frps 隧道 → 抖断。deploy-server/deploy-site 同类 Forgejo release 步跑在 ubuntu-latest(nas act_runner,与 gitea 同机/同网)稳定通过(server 仅 13s)。 - runs-on: mac → ubuntu-latest:release-deploy 全为网络/SSH 步骤(下载产物/ 传 Forgejo/SSH pangolin1/通知),无 mac 专属需求,挪到 nas runner 走本地。 - needs: [build-android] → [build-android, build-windows, build-macos, build-ios]: 等全部平台 build 完再发布,修旧竞态(只等 android → macos/ios 产物没传就发布 漏平台)。macos/ios 保留 continue-on-error,失败不阻断已成功平台。 - 更新过时注释(原称 Apple secret 未配 / needs 仅 android+windows)。 yaml 校验通过。build 四平台本身已在 run 639 全绿,本次只修发布环节。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A79VtQA1BwTuQN1ThpvYpo
230 lines
11 KiB
YAML
230 lines
11 KiB
YAML
name: Deploy Client
|
||
|
||
# Mirrors ~/code/jiu/.gitea/workflows/deploy-client.yml's tag→build→release→
|
||
# deploy shape. Android + Windows are required (release-deploy `needs` them);
|
||
# macOS + iOS (Phase 3, see docs/superpowers/plans/2026-07-05-cicd.md) are
|
||
# intentionally DECOUPLED — see the "why build-macos/build-ios don't block"
|
||
# note above the build-macos job below for the mechanism and rationale.
|
||
#
|
||
# TODO(controller) — RUNNER AVAILABILITY: per docs/ci-runner.md, pangolin
|
||
# currently has exactly ONE registered Gitea Actions runner
|
||
# ("mac-pangolin-2", label `nas:host`). Neither `runs-on: mac` nor
|
||
# `runs-on: windows` below has any runner registered to pick it up yet — this
|
||
# workflow will queue forever until that's fixed. Options: (a) register
|
||
# mac-pangolin-2 with an additional `mac` label (it's already a mac host —
|
||
# cheapest fix for build-android/release-deploy) and separately stand up +
|
||
# register an actual Windows host runner labeled `windows` for build-windows
|
||
# (no such machine exists per docs/ci-runner.md), or (b) repoint both at
|
||
# `nas` and accept that Android/Windows builds then compete with the
|
||
# docker-in-domain nas jobs on the same single mac host. This mirrors the
|
||
# `runs-on: mac` / `runs-on: windows` split already planned in
|
||
# docs/superpowers/plans/2026-07-05-cicd.md Task 7/10 — written that way here
|
||
# for fidelity to that plan, NOT because the runners are confirmed to exist.
|
||
on:
|
||
push:
|
||
tags:
|
||
- 'client-v[0-9]*.[0-9]*.[0-9]*'
|
||
workflow_dispatch:
|
||
|
||
concurrency:
|
||
group: deploy-client
|
||
# true:新 client-v* 取消仍在跑的旧发版(如 windows 机离线导致 build-windows 无限排队
|
||
# 卡住的旧 run),让最新版顺利发布,避免并发组被僵尸 run 占死。
|
||
cancel-in-progress: true
|
||
|
||
jobs:
|
||
build-android:
|
||
runs-on: mac
|
||
env:
|
||
GOPROXY: https://goproxy.cn,direct
|
||
PUB_HOSTED_URL: https://pub.flutter-io.cn
|
||
FLUTTER_STORAGE_BASE_URL: https://storage.flutter-io.cn
|
||
# sing-box 源码经 NAS gitea 公网镜像取(mac runner 连不上 github)。
|
||
# 用稳定公网域名 git.51yanmei.com(ali frps ← 家里 NAS frpc,nginx 443 反代
|
||
# gitea)—— 外网/内网都通,不依赖本地 relay/tailscale。见 scripts/build-libbox.sh。
|
||
SINGBOX_GIT: https://git.51yanmei.com/wangjia/sing-box.git
|
||
steps:
|
||
- name: Checkout
|
||
uses: actions/checkout@v4
|
||
|
||
- name: Compile (Android APK)
|
||
env:
|
||
RELEASE_KEYSTORE: ${{ secrets.RELEASE_KEYSTORE }}
|
||
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
|
||
REF_NAME: ${{ gitea.ref_name }}
|
||
run: bash scripts/ci/compile-android.sh "$REF_NAME"
|
||
|
||
- name: Upload android artifact
|
||
uses: actions/upload-artifact@v3
|
||
with:
|
||
name: android
|
||
path: dist/
|
||
|
||
build-windows:
|
||
runs-on: windows
|
||
env:
|
||
GOPROXY: https://goproxy.cn,direct
|
||
PUB_HOSTED_URL: https://pub.flutter-io.cn
|
||
FLUTTER_STORAGE_BASE_URL: https://storage.flutter-io.cn
|
||
# 境内镜像:GitHub release 资产在国内被 GFW 限速 → windows runner(LAN 内)下
|
||
# sing-box.exe / wintun.zip 超时。改从 NAS Gitea generic 包镜像拉,
|
||
# fetch-desktop-bin.sh 命中镜像后照样验 SHA256,失败则回退官方源。
|
||
# ⚠️ 基址含 sing-box 版本目录(v1.13.12)——升级 app/kernel/VERSION 的
|
||
# SINGBOX_VERSION 时,须把新版 zip 重新 PUT 到对应版本目录并同步改这里。
|
||
DESKTOP_BIN_MIRROR: http://192.168.3.200:3000/api/packages/wangjia/generic/desktop-bin/v1.13.12
|
||
# 包默认可匿名读,token 非必需;带上以防将来把包设为私有(未设/为空则匿名 GET)。
|
||
DESKTOP_BIN_MIRROR_TOKEN: ${{ secrets.FORGEJO_TOKEN }}
|
||
steps:
|
||
- name: Checkout
|
||
uses: actions/checkout@v4
|
||
|
||
- name: Compile (Windows installer)
|
||
shell: bash
|
||
env:
|
||
REF_NAME: ${{ gitea.ref_name }}
|
||
run: bash scripts/ci/compile-windows.sh "$REF_NAME"
|
||
|
||
- name: Upload windows artifact
|
||
uses: actions/upload-artifact@v3
|
||
with:
|
||
name: windows
|
||
path: dist/
|
||
|
||
# build-macos/build-ios 用 `continue-on-error: true` → 即便 Apple 侧构建抖了
|
||
# (frps 拉 sing-box 源码 / 公证超时等),也不阻塞 android+windows 发布:
|
||
# 1. release-deploy 现在 `needs:` 全部四个平台(见下),所以它会**等**全部
|
||
# build 完成再发布 —— 避免旧 `needs: [build-android]` 只等 android、
|
||
# macos/ios 还没传产物就发布导致漏平台的竞态。
|
||
# 2. continue-on-error 让 macos/ios 失败仍算「completed」满足 needs,不使整个
|
||
# workflow 变红、不阻断已成功平台的发布;release-deploy 的「Download all
|
||
# artifacts」(无 name 过滤)只捡实际存在的产物,缺某平台不报错。
|
||
# 3. Apple 签名 secret 现已在 gitea 用户级配齐(DEVELOPER_ID_P12/IOS_DIST_P12/
|
||
# APPSTORE_API_* 等),macos/ios 正常应成功;continue-on-error 只是抖动兜底。
|
||
build-macos:
|
||
runs-on: mac
|
||
continue-on-error: true
|
||
env:
|
||
GOPROXY: https://goproxy.cn,direct
|
||
PUB_HOSTED_URL: https://pub.flutter-io.cn
|
||
FLUTTER_STORAGE_BASE_URL: https://storage.flutter-io.cn
|
||
# macOS 同样内嵌 libbox → 同走 NAS gitea 公网镜像取 sing-box 源码(见 build-android)。
|
||
SINGBOX_GIT: https://git.51yanmei.com/wangjia/sing-box.git
|
||
steps:
|
||
- name: Checkout
|
||
uses: actions/checkout@v4
|
||
|
||
- name: Compile (macOS System Extension app)
|
||
env:
|
||
# 左=脚本期望的 env 名(勿改),右=实际密钥名。Apple 证书/公证密钥是
|
||
# 账号级、跨项目唯一 → 放【全局(用户级)密钥】用通用短名,pangolin/jiu 各自
|
||
# 在此映射到自己脚本的 env。Developer ID Application 证书=站外分发,一张签所有 app。
|
||
MACOS_DEVELOPER_ID_CERT_P12_BASE64: ${{ secrets.DEVELOPER_ID_P12 }}
|
||
MACOS_DEVELOPER_ID_CERT_PASSWORD: ${{ secrets.P12_PASSWORD }}
|
||
MACOS_APP_PROVISION_PROFILE_BASE64: ${{ secrets.MACOS_APP_PROVISION_PROFILE_BASE64 }}
|
||
MACOS_SYSEXT_PROVISION_PROFILE_BASE64: ${{ secrets.MACOS_SYSEXT_PROVISION_PROFILE_BASE64 }}
|
||
APPSTORE_API_KEY_ID: ${{ secrets.APPSTORE_API_KEY_ID }}
|
||
APPSTORE_API_ISSUER_ID: ${{ secrets.APPSTORE_API_ISSUER_ID }}
|
||
APPSTORE_API_KEY_P8_BASE64: ${{ secrets.APPSTORE_API_KEY_P8_BASE64 }}
|
||
REF_NAME: ${{ gitea.ref_name }}
|
||
run: bash scripts/ci/compile-macos.sh "$REF_NAME"
|
||
|
||
- name: Upload macos artifact
|
||
uses: actions/upload-artifact@v3
|
||
with:
|
||
name: macos
|
||
path: dist/
|
||
|
||
build-ios:
|
||
runs-on: mac
|
||
continue-on-error: true
|
||
env:
|
||
GOPROXY: https://goproxy.cn,direct
|
||
PUB_HOSTED_URL: https://pub.flutter-io.cn
|
||
FLUTTER_STORAGE_BASE_URL: https://storage.flutter-io.cn
|
||
# iOS 同样内嵌 libbox → 同走 NAS gitea 公网镜像取 sing-box 源码(见 build-android)。
|
||
SINGBOX_GIT: https://git.51yanmei.com/wangjia/sing-box.git
|
||
steps:
|
||
- name: Checkout
|
||
uses: actions/checkout@v4
|
||
|
||
- name: Compile & upload to TestFlight (iOS)
|
||
env:
|
||
# 证书=账号级 →【全局】通用短名(Apple Distribution 证书,签 iOS App Store/TestFlight);
|
||
# 描述文件=与 bundle id 绑定 →【项目级】pangolin 仓库密钥。
|
||
IOS_DIST_CERT_P12_BASE64: ${{ secrets.IOS_DIST_P12 }}
|
||
IOS_DIST_CERT_PASSWORD: ${{ secrets.IOS_DIST_PASSWORD }}
|
||
IOS_APP_PROVISIONING_PROFILE_BASE64: ${{ secrets.IOS_APP_PROVISIONING_PROFILE_BASE64 }}
|
||
IOS_PACKETTUNNEL_PROVISIONING_PROFILE_BASE64: ${{ secrets.IOS_PACKETTUNNEL_PROVISIONING_PROFILE_BASE64 }}
|
||
APPSTORE_API_KEY_ID: ${{ secrets.APPSTORE_API_KEY_ID }}
|
||
APPSTORE_API_ISSUER_ID: ${{ secrets.APPSTORE_API_ISSUER_ID }}
|
||
APPSTORE_API_KEY_P8_BASE64: ${{ secrets.APPSTORE_API_KEY_P8_BASE64 }}
|
||
REF_NAME: ${{ gitea.ref_name }}
|
||
run: bash scripts/ci/compile-ios.sh "$REF_NAME"
|
||
# No artifact upload — compile-ios.sh uploads straight to TestFlight via
|
||
# altool (matches jiu); nothing is produced under dist/ for this job.
|
||
|
||
# release-deploy 只 needs build-android(唯一稳定可用的平台 floor)。windows/macos/ios
|
||
# best-effort:各自 runner+secret 就绪则上传 artifact,release-deploy flatten 收
|
||
# dist-raw/ 里"当时存在"的产物。windows 机离线 / Apple secret 未配 都不阻塞发版
|
||
# (对应平台下载保留 pangolin1 上一版,待可用时下个 client-v* 追上)。
|
||
release-deploy:
|
||
# 等全部平台 build 完再发布,否则 download-artifact 会漏掉尚未上传的平台
|
||
# (原来只 needs build-android → android 一完就发,macos/ios 常还没传产物)。
|
||
needs: [build-android, build-windows, build-macos, build-ios]
|
||
# ubuntu-latest = 家里 nas act_runner,与 gitea 同机/同网:Release → Forgejo 的
|
||
# API 调用走本地不过 frps 隧道(mac runner 走 git.51yanmei.com→frps→抖,curl 超时
|
||
# exit 28,3m3s=release_ensure 60s×3 重试耗尽)。deploy-server/deploy-site 同为
|
||
# ubuntu-latest,其 Forgejo release 步稳定通过(server 仅 13s)。此 job 全为网络/
|
||
# SSH 步骤(下载产物/传 Forgejo/SSH pangolin1/通知),无 mac 专属需求。
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
- name: Checkout
|
||
uses: actions/checkout@v4
|
||
|
||
# 一次性下所有 artifact(不带 name),避免同 job 内两次复用 download-artifact
|
||
# action → act 对其只读缓存 git 仓库做二次操作时 EACCES(pack idx 444)。
|
||
- name: Download all artifacts
|
||
uses: actions/download-artifact@v3
|
||
with:
|
||
path: dist-raw/
|
||
|
||
- name: Flatten artifacts into dist/
|
||
shell: bash
|
||
run: |
|
||
mkdir -p dist
|
||
find dist-raw -type f -exec cp {} dist/ \;
|
||
echo "dist/ 内容:"; ls -la dist/
|
||
|
||
- name: Release → Forgejo
|
||
env:
|
||
FORGEJO_TOKEN: ${{ secrets.FORGEJO_TOKEN }}
|
||
FORGEJO_URL: ${{ secrets.FORGEJO_URL }}
|
||
# Needed here (not just in the "Deploy" step below) because
|
||
# release-client.sh now also SSH-pushes the auto-update manifest
|
||
# (version.yaml) straight to pangolin1's /etc/pangolin/ — see the
|
||
# header comment in scripts/ci/release-client.sh.
|
||
DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
|
||
REF_NAME: ${{ gitea.ref_name }}
|
||
run: bash scripts/ci/release-client.sh "$REF_NAME"
|
||
|
||
- name: Deploy → pangolin1 (downloads/)
|
||
env:
|
||
DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
|
||
REF_NAME: ${{ gitea.ref_name }}
|
||
run: bash scripts/ci/deploy-client.sh "$REF_NAME"
|
||
|
||
- name: Notify
|
||
if: always()
|
||
env:
|
||
TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
|
||
TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
|
||
REF_NAME: ${{ gitea.ref_name }}
|
||
JOB_STATUS: ${{ job.status }}
|
||
run: |
|
||
. scripts/ci/notify.sh
|
||
if [ "$JOB_STATUS" = "success" ]; then
|
||
notify_ok "client $REF_NAME released + deployed"
|
||
else
|
||
notify_fail "client $REF_NAME pipeline failed"
|
||
fi
|