# 墨观 InkWatch V4.0 · 设计系统双向护栏 CI 入口 # # 前提:本 workflow 只有在 Gitea 实例「启用 Actions」时才会真正运行; # 未启用时该文件仅作声明,不会触发任何检查。 # 本地复现(无需 Actions、无需 Gitea):cd && bash tests/run-guards.sh # 不在本文件里引 CDN、不写任何凭据;Flutter 用官方 flutter-action 安装。 # # Flutter / Dart 段说明: # client/scripts/test.sh 默认找 $HOME/development/flutter/bin/flutter, # 下面把 flutter 装到同一位置并把绝对路径经 FLUTTER_BIN 显式传给 test.sh, # 以保证默认跑全量 Dart(含 token_parity_test.dart 的 CSS ↔ Dart 双向护栏)。 # SDK 取自 storage.flutter-io.cn 的 stable 归档(非 git clone),版本钉死。 # 若 runner 无法安装 Flutter:设 SKIP_FLUTTER_TESTS=1 降级 —— Dart 段会在 # 汇总表里显式标 SKIPPED (explicit),绝不静默通过。 # # 管理台 axe 段(第 6 套件,默认不跑): # run-guards.sh 只在 RUN_AXE=1 时执行 node tests/admin-axe-audit.mjs # (3 视口 × 2 皮肤 × 6 页 + E-Ink 6 格 = 42 格,单跑约 45s)。 # **runner 必须自带 Chromium 系浏览器(google-chrome / microsoft-edge / # chromium)并能联网安装 axe-core,否则保持默认不跑**;若强行启用而浏览器缺失, # 该套件以退出码 2 失败(汇总表 FAIL,不会伪造成 PASS)。 # 两种启用方式(任选其一,均不硬编码任何凭据): # ① 手动触发:Actions 里 Run workflow → run_axe 勾选 true; # ② 仓库变量:Gitea 仓库 Settings → Actions → Variables 设 IW_RUN_AXE=1, # 之后 push / pull_request 也会带上该套件。 # 若所在 Gitea 版本不支持 vars 上下文,删掉下面 job 级 env 里 # IW_RUN_AXE 那一行即可(其余逻辑不变,退回「默认不跑」)。 name: Design System Guard on: push: pull_request: workflow_dispatch: inputs: run_axe: # 用字符串而非 type: boolean —— 兼容不支持 inputs.type 的旧版 Gitea description: '启用管理台 axe 42 格矩阵(填 true 启用;需 runner 自带 Chromium/Edge)' default: 'false' jobs: guard: runs-on: ubuntu-latest # 2026-11-09:历史上 6 次运行全红,根因两处,均已在此固化: # ① subosito/flutter-action@v2 的 setup.sh 依赖 jq,而 runner 的 # node:20-bookworm 容器没有 jq → 首行即 "jq not found" 退出。 # 故本文件不再使用该 action,改为直取官方镜像的 tar.xz(无需 jq)。 # ② 该 runner 到 github.com 与 nodejs.org 的直连极慢/超时 # (实测 setup-node 重试 3 轮烧掉 8 分钟才靠 fallback 成功; # flutter-action 默认 `git clone github.com/flutter/flutter` 必挂)。 # 故 Flutter 全程改走国内镜像。 # setup-node 也已删除:其 `mirror` 参数只影响 dist 下载,解析版本清单 # 时仍打 github.com/actions/node-versions,实测照样 ETIMEDOUT。 # 本 job 只用 fs/path/crypto 三个内置模块,容器自带的 node 20 足够 # (runner 的 ubuntu-latest 映射到 node:20-bookworm,见运行日志)。 timeout-minutes: 30 env: # 仓库变量(可选);未设置时为空串,等价于「默认不跑 axe」 IW_RUN_AXE: ${{ vars.IW_RUN_AXE }} # Flutter/Dart 官方中国镜像(下载 SDK 与 pub 包均走它,避开 github/pub.dev) FLUTTER_STORAGE_BASE_URL: https://storage.flutter-io.cn PUB_HOSTED_URL: https://pub.flutter-io.cn steps: - name: Checkout uses: actions/checkout@v4 - name: Report toolchain run: | # 不使用 setup-node:容器自带 Node,版本随镜像走,此处只记录以便追溯。 command -v node >/dev/null 2>&1 || { echo "容器内无 node,无法跑护栏脚本" >&2; exit 1; } echo "node $(node --version) / npm $(npm --version 2>/dev/null || echo n/a)" # 不用 subosito/flutter-action:它硬依赖 jq,且默认 git clone github。 # 直接取官方镜像归档,1.58GB,走 storage.flutter-io.cn。 # node:20-bookworm 自带 curl/tar/xz/git,故本步骤无需 apt。 - name: Setup Flutter (mirror archive, no jq) run: | set -euo pipefail FLUTTER_VERSION="3.47.9" # Dart 3.13.7,满足 pubspec 的 sdk: ^3.13.3 ARCHIVE="flutter_linux_${FLUTTER_VERSION}-stable.tar.xz" URL="${FLUTTER_STORAGE_BASE_URL}/flutter_infra_release/releases/stable/linux/${ARCHIVE}" mkdir -p "$HOME/development" echo "下载 $URL" curl -fsSL --retry 3 --retry-delay 5 --connect-timeout 20 -o /tmp/flutter.tar.xz "$URL" tar xf /tmp/flutter.tar.xz -C "$HOME/development" rm -f /tmp/flutter.tar.xz echo "$HOME/development/flutter/bin" >> "$GITHUB_PATH" echo "FLUTTER_BIN=$HOME/development/flutter/bin/flutter" >> "$GITHUB_ENV" "$HOME/development/flutter/bin/flutter" --version - name: Run design system guards run: | if [ -n "${FLUTTER_ROOT:-}" ] && [ -x "$FLUTTER_ROOT/bin/flutter" ]; then export FLUTTER_BIN="$FLUTTER_ROOT/bin/flutter" elif command -v flutter >/dev/null 2>&1; then export FLUTTER_BIN="$(command -v flutter)" fi # 管理台 axe 段:默认 0;手动触发时取 run_axe 输入;否则看仓库变量 IW_RUN_AXE RUN_AXE="${IW_RUN_AXE:-0}" if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then if [ "${{ inputs.run_axe }}" = "true" ]; then RUN_AXE=1; else RUN_AXE=0; fi fi export RUN_AXE echo "RUN_AXE=$RUN_AXE(0=跳过管理台 axe 42 格矩阵,1=执行)" bash tests/run-guards.sh