Files
pangolin/.gitea/workflows/deploy-client.yml
T
wangjia 6756cea413
Deploy Client / build-android (push) Successful in 1m37s
Deploy Client / build-macos (push) Failing after 3s
Deploy Client / build-ios (push) Successful in 3s
Deploy Client / release-deploy (push) Successful in 1m1s
Deploy Client / build-windows (push) Successful in 1m57s
ci: deploy-client concurrency cancel-in-progress true(新版取消僵尸旧 run)
2026-07-07 01:07:00 +08:00

209 lines
8.8 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
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
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/
# Why build-macos/build-ios don't block the working android+windows pipeline
# when Apple secrets aren't configured yet (they aren't, as of this writing):
# 1. release-deploy's `needs:` below is [build-android, build-windows]
# ONLY — macOS/iOS are NOT dependencies, so release-deploy never waits
# on them and never fails because of them.
# 2. `continue-on-error: true` on both jobs keeps the overall workflow-run
# status green even while compile-macos.sh hard-fails (Apple Developer
# ID / notary secrets absent — see its fail-fast checks) — that failure
# is real signal ("go configure the secrets"), but it shouldn't read as
# "the release pipeline is broken" when android+windows shipped fine.
# 3. compile-macos.sh's own default behavior is to hard-fail (not skip)
# when its secrets are missing (macOS distribution must never ship
# unsigned/unnotarized — see its header comment); compile-ios.sh's
# default is to skip gracefully (exit 0) since an unconfigured iOS
# account is a normal "not set up yet" state, not a defect. Either way
# the job produces no dist/pangolin-macos-x64.zip, and
# release-deploy's "Download all artifacts" step (no `name:` filter)
# simply picks up whatever artifacts DO exist — an absent "macos"
# artifact is not an error there.
build-macos:
runs-on: mac
continue-on-error: true
env:
PUB_HOSTED_URL: https://pub.flutter-io.cn
FLUTTER_STORAGE_BASE_URL: https://storage.flutter-io.cn
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Compile (macOS System Extension app)
env:
MACOS_DEVELOPER_ID_CERT_P12_BASE64: ${{ secrets.MACOS_DEVELOPER_ID_CERT_P12_BASE64 }}
MACOS_DEVELOPER_ID_CERT_PASSWORD: ${{ secrets.MACOS_DEVELOPER_ID_CERT_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:
PUB_HOSTED_URL: https://pub.flutter-io.cn
FLUTTER_STORAGE_BASE_URL: https://storage.flutter-io.cn
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Compile & upload to TestFlight (iOS)
env:
IOS_DIST_CERT_P12_BASE64: ${{ secrets.IOS_DIST_CERT_P12_BASE64 }}
IOS_DIST_CERT_PASSWORD: ${{ secrets.IOS_DIST_CERT_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:
needs: [build-android]
runs-on: mac
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