Compare commits

...

4 Commits

Author SHA1 Message Date
wangjia eb18f1ef06 Merge pull request 'fix(server+ci): CI 收尾 — go-integration 真 bug + e2e 免疫代理' (#3) from worktree-macos-killswitch into main
ci-pangolin / Lint — shellcheck (push) Successful in 9s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (push) Successful in 23s
ci-pangolin / OpenAPI Sync Check (push) Successful in 34s
ci-pangolin / Flutter — analyze + test (push) Successful in 29s
ci-pangolin / Codegen Drift — token 生成物未漂移 (push) Successful in 5s
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (push) Successful in 5s
ci-pangolin / Go — build + test (push) Successful in 8s
ci-pangolin / E2E Smoke — L4 进程级端到端 (push) Successful in 9s
ci-pangolin / Go — integration (mysql/redis testcontainers) (push) Successful in 4m30s
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (push) Successful in 19s
ci-pangolin / Cleartext Scan — Android 禁明文 (push) Failing after 10m42s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (push) Failing after 10m55s
2026-07-08 02:51:06 +00:00
wangjia 37258e1cb2 fix(client/test): 删未用变量修 flutter analyze(CI Flutter job 全绿)
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (pull_request) Successful in 24s
ci-pangolin / Flutter — analyze + test (pull_request) Successful in 33s
ci-pangolin / Cleartext Scan — Android 禁明文 (pull_request) Successful in 28s
ci-pangolin / Codegen Drift — token 生成物未漂移 (pull_request) Successful in 10s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (pull_request) Successful in 24s
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (pull_request) Successful in 12s
ci-pangolin / Go — build + test (pull_request) Successful in 7s
ci-pangolin / E2E Smoke — L4 进程级端到端 (pull_request) Successful in 8s
ci-pangolin / Go — integration (mysql/redis testcontainers) (pull_request) Successful in 4m33s
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (pull_request) Successful in 18s
ci-pangolin / OpenAPI Sync Check (pull_request) Failing after 10m21s
ci-pangolin / Lint — shellcheck (pull_request) Failing after 10m33s
stats_device_filter_test.dart 的 const t = StringsZh() 声明后未使用 →
unused_local_variable warning → flutter analyze --no-fatal-infos exit 1 →
CI Flutter job 一直红(既存,与 i18n 修复无关)。删该变量 + 随之无用的
strings_zh import。

容器复验:analyze exit 0(0 warning)· test +97 过 · 覆盖率 38.5%≥28%。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 10:11:32 +08:00
wangjia 38be40a107 fix(client/ci): sing-box/wintun 境内镜像到 NAS(修 Windows 构建 GFW 失败)
ci-pangolin / Cleartext Scan — Android 禁明文 (pull_request) Successful in 25s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (pull_request) Successful in 22s
ci-pangolin / Lint — shellcheck (pull_request) Successful in 8s
ci-pangolin / OpenAPI Sync Check (pull_request) Successful in 30s
ci-pangolin / Flutter — analyze + test (pull_request) Failing after 18s
ci-pangolin / Codegen Drift — token 生成物未漂移 (pull_request) Successful in 4s
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (pull_request) Successful in 4s
ci-pangolin / Go — build + test (pull_request) Successful in 14s
ci-pangolin / E2E Smoke — L4 进程级端到端 (pull_request) Successful in 16s
ci-pangolin / Go — integration (mysql/redis testcontainers) (pull_request) Successful in 4m52s
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (pull_request) Successful in 23s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (pull_request) Failing after 13m12s
根因:Windows CI 从 GitHub release 下 sing-box 压缩包被 GFW 限速超时(github.com
网页可达但 release 资产 CDN 被掐),build-windows 卡在 fetch-desktop-bin 早期。

修:
- 二进制镜像到 NAS Gitea generic 包(v1.13.12/sing-box-*-windows-amd64.zip +
  wintun-0.14.1.zip),上传前后均 sha256 校验。
- fetch-desktop-bin.sh 加 DESKTOP_BIN_MIRROR(+可选 _TOKEN):设了先试镜像、
  命中即用、未设/失败回退 GitHub/wintun.net;镜像文件照走现有 sha pin 校验(防
  投毒/损坏)。修一处 macOS bash3.2 空数组 set -u unbound 坑。
- deploy-client.yml build-windows env 指向 NAS 镜像基址 + 复用现有 FORGEJO_TOKEN
  secret(匿名 GET 也行,token 仅备将来私有)。无新 secret、无硬编码、无入库二进制。

回归(mac bash3.2):无 mirror 走 GitHub ✓ / mirror 走 NAS 命中 ✓ / bogus mirror
回退 ✓。Windows 端到端待下个 client-v* tag 触发 CI 观察。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 09:53:38 +08:00
wangjia 8e569b83a7 Merge pull request 'feat(ds-flow): 前端设计系统治理重构(Flutter 五端 + Web 两端)' (#2) from worktree-macos-killswitch into main
ci-pangolin / Cleartext Scan — Android 禁明文 (push) Successful in 27s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (push) Successful in 24s
ci-pangolin / Lint — shellcheck (push) Successful in 7s
ci-pangolin / OpenAPI Sync Check (push) Successful in 33s
ci-pangolin / Flutter — analyze + test (push) Failing after 16s
ci-pangolin / Codegen Drift — token 生成物未漂移 (push) Successful in 4s
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (push) Successful in 4s
ci-pangolin / Go — build + test (push) Successful in 8s
ci-pangolin / E2E Smoke — L4 进程级端到端 (push) Failing after 7s
Deploy Site / deploy-site (push) Successful in 2m39s
ci-pangolin / Go — integration (mysql/redis testcontainers) (push) Failing after 4m24s
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (push) Successful in 20s
Deploy Client / build-android (push) Successful in 2m30s
Deploy Client / build-windows (push) Failing after 13m38s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (push) Failing after 14m24s
Deploy Client / build-macos (push) Successful in 3m56s
Deploy Client / build-ios (push) Successful in 3m28s
Deploy Client / release-deploy (push) Successful in 1m38s
2026-07-08 00:46:57 +00:00
3 changed files with 51 additions and 10 deletions
+8
View File
@@ -62,6 +62,14 @@ jobs:
GOPROXY: https://goproxy.cn,direct GOPROXY: https://goproxy.cn,direct
PUB_HOSTED_URL: https://pub.flutter-io.cn PUB_HOSTED_URL: https://pub.flutter-io.cn
FLUTTER_STORAGE_BASE_URL: https://storage.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: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
+43 -8
View File
@@ -20,6 +20,15 @@
# 提取对应 arch 的 wintun.dll 到产物目录。 # 提取对应 arch 的 wintun.dll 到产物目录。
# #
# 幂等: 产物已存在且 SHA256 校验通过则跳过下载(传 --force 强制重下) # 幂等: 产物已存在且 SHA256 校验通过则跳过下载(传 --force 强制重下)
#
# 境内镜像(可选,解决 CI 从 GitHub release 被 GFW 限速的问题):
# DESKTOP_BIN_MIRROR 镜像基址;设了则 archive 与 wintun.zip 先试
# ${DESKTOP_BIN_MIRROR}/<文件名>,命中即用,失败/未设
# 则回退官方 GitHub / wintun.net。镜像下载的文件照样走
# 下面的 SHA256 校验(防投毒/损坏)。
# 例:http://192.168.3.200:3000/api/packages/wangjia/generic/desktop-bin/v1.13.12
# DESKTOP_BIN_MIRROR_TOKEN 可选;镜像需鉴权时作 `Authorization: token <值>`。
# 不设则匿名 GETNAS Gitea generic 包默认可匿名读)。
set -euo pipefail set -euo pipefail
@@ -116,6 +125,36 @@ _sha256() {
fi fi
} }
# ── 下载助手:镜像优先,回退官方源 ─────────────────────────────────────────────
# 用法: _download_with_mirror <文件名> <官方回退URL> <输出路径>
# 若设了 DESKTOP_BIN_MIRROR:先试 ${DESKTOP_BIN_MIRROR}/<文件名>(带可选 token
# header),命中即返回;未设 / 镜像失败则回退官方 <回退URL>。
# SHA256 校验由调用方在下载后统一执行——镜像来的文件同样要过校验。
_download_with_mirror() {
local filename="$1" fallback_url="$2" out="$3"
if [[ -n "${DESKTOP_BIN_MIRROR:-}" ]]; then
local mirror_url="${DESKTOP_BIN_MIRROR%/}/${filename}"
local -a auth=()
if [[ -n "${DESKTOP_BIN_MIRROR_TOKEN:-}" ]]; then
auth=(-H "Authorization: token ${DESKTOP_BIN_MIRROR_TOKEN}")
fi
printf '==> [mirror] 尝试 %s…\n' "${mirror_url}"
# ${auth[@]+...} 兜住空数组 + set -umacOS bash 3.2 下 "${auth[@]}" 在数组
# 为空时会报 "unbound variable",此写法数组空则整体展开为空。
if curl -fSL --retry 5 --retry-delay 3 --retry-all-errors --connect-timeout 15 \
${auth[@]+"${auth[@]}"} -o "${out}" "${mirror_url}"; then
printf ' ✓ [mirror] 命中\n'
return 0
fi
printf ' ! [mirror] 未命中,回退官方源\n' >&2
fi
printf '==> 下载 %s…\n' "${fallback_url}"
curl -fSL --retry 8 --retry-delay 5 --retry-connrefused --retry-all-errors --connect-timeout 20 \
-o "${out}" "${fallback_url}"
}
# ── 幂等检查(已有产物则跳过;--force 强制重下)──────────────────────────────── # ── 幂等检查(已有产物则跳过;--force 强制重下)────────────────────────────────
if [[ "${FORCE}" == false && -f "${OUT_BIN}" ]]; then if [[ "${FORCE}" == false && -f "${OUT_BIN}" ]]; then
printf '✓ %s 已存在,跳过下载\n' "${OUT_BIN}" printf '✓ %s 已存在,跳过下载\n' "${OUT_BIN}"
@@ -138,11 +177,8 @@ if [[ -z "${EXPECTED_HASH}" ]]; then
exit 1 exit 1
fi fi
# ── 下载二进制压缩包 ────────────────────────────────────────────────────────── # ── 下载二进制压缩包(镜像优先,回退 GitHub Release──────────────────────────
printf '==> 下载 %s…\n' "${ARCHIVE_FILE}" _download_with_mirror "${ARCHIVE_FILE}" "${ARCHIVE_URL}" "${ARCHIVE_CACHE}"
curl -fSL --retry 8 --retry-delay 5 --retry-connrefused --retry-all-errors --connect-timeout 20 \
-o "${ARCHIVE_CACHE}" \
"${ARCHIVE_URL}"
# ── SHA256 校验(对压缩包,比对内置 pin)────────────────────────────────────── # ── SHA256 校验(对压缩包,比对内置 pin)──────────────────────────────────────
printf '==> 校验 SHA256…\n' printf '==> 校验 SHA256…\n'
@@ -197,9 +233,8 @@ if [[ "${TARGET_OS}" == "windows" ]]; then
if [[ "${FORCE}" == false && -f "${WINTUN_OUT}" ]]; then if [[ "${FORCE}" == false && -f "${WINTUN_OUT}" ]]; then
printf '✓ wintun.dll 已存在,跳过(传 --force 重新下载)\n' printf '✓ wintun.dll 已存在,跳过(传 --force 重新下载)\n'
else else
curl -fSL --retry 8 --retry-delay 5 --retry-connrefused --retry-all-errors --connect-timeout 20 \ # 镜像优先,回退 wintun.net
-o "${WINTUN_ZIP_CACHE}" \ _download_with_mirror "${WINTUN_ZIP_NAME}" "${WINTUN_URL}" "${WINTUN_ZIP_CACHE}"
"${WINTUN_URL}"
printf '==> 校验 wintun.zip SHA256…\n' printf '==> 校验 wintun.zip SHA256…\n'
WINTUN_ACTUAL="$(_sha256 "${WINTUN_ZIP_CACHE}")" WINTUN_ACTUAL="$(_sha256 "${WINTUN_ZIP_CACHE}")"
@@ -6,7 +6,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:http/testing.dart'; import 'package:http/testing.dart';
import 'package:pangolin_vpn/l10n/strings_zh.dart';
import 'package:pangolin_vpn/pangolin_theme.dart'; import 'package:pangolin_vpn/pangolin_theme.dart';
import 'package:pangolin_vpn/screens/stats_page.dart'; import 'package:pangolin_vpn/screens/stats_page.dart';
import 'package:pangolin_vpn/services/api_client.dart'; import 'package:pangolin_vpn/services/api_client.dart';
@@ -38,7 +37,6 @@ class _LoggedIn implements TokenStore {
void main() { void main() {
setUpAll(disableGoogleFontsFetching); setUpAll(disableGoogleFontsFetching);
const t = StringsZh();
testWidgets('选设备 → /v1/usage 带 device=<uuid>', (tester) async { testWidgets('选设备 → /v1/usage 带 device=<uuid>', (tester) async {
await tester.binding.setSurfaceSize(const Size(900, 1200)); await tester.binding.setSurfaceSize(const Size(900, 1200));