ci: 建立 GitHub Actions 流水线(六个 job,全部命令已本地实测)

## 为什么现在做

这次排查「QQ 收不到回复」花了大半程才定位到根因,途中我犯了两类错:
先断言「提示词没写 output_send 规则」(实际 buildSystemPrompt:48-52 写了),
又断言「适配器丢了内容」(实际两版等价、直连上游正常)。
两次都是**在无自动化判据的情况下凭局部证据外推**。

仓库已有 60 个 Go 包、`go build ./...` 仅 2.2 秒,成本极低却无人强制跑。
AtomGit 停用流水线后更无兜底,故迁到 GitHub 补齐。

## 设计原则:CI 里每条命令都是本地已实测通过的

不写「可能有用先试试」的步骤 —— 未验证的 CI 步骤会把假红灯变成常态,
最后所有人都学会忽略它。本文六个 job 的每条命令都本地跑过:

  go build ./...                      ✓
  go vet ./...                        ✓
  go test ./... -count=1              ✓(干净克隆亦通过)
  make check-client-versions          ✓
  go test -race core + waiter         ✓
  waiter/initconfig/mock-server 交叉  ✓(5 平台)
  npm test(cmd/gui)                 ✓
  make check-csrc                     ✓(告警/ABI/ASan+UBSan/跨架构)

## 六个 job

| job   | 覆盖                                                     |
|-------|----------------------------------------------------------|
| go    | build + vet + test + **跨平台客户端版本一致性**           |
| race  | 并发核心的竞态检测                                        |
| cross | linux/darwin/windows × amd64/arm64(仅可纯交叉的 3 个 cmd)|
| gui   | Electron 仓的 Node 测试                                   |
| csrc  | C 基础设施门禁                                            |
| docs  | 站点配置可解析                                            |

## 关键事实(都由实测确立,不是推断)

1. **只有 waiter/initconfig/mock-server 能纯交叉编译**。homed、memgc、
   homed-kb-migrate 依赖 cgo(gojieba / onnx),必须原生构建 ⇒ 不进 cross matrix。
2. **CGO 必须为 1**:gojieba 需要 cgo,`CGO_ENABLED=0` 下 internal/memory
   直接编译失败(实测)。
3. **`go test ./...` 不会碰到 cmd/gui**。该目录是纯 Electron(0 个 .go、
   无 go.mod),`./...` 只匹配含 Go 文件的包;只有显式 `go test ./cmd/gui`
   才报 "no Go files"。这不是缺陷,是 Go 的包匹配语义 —— 之前把它当
   [setup failed] 是误读。
4. **cmd/gui 的 npm test 零依赖**:三个 .mjs 只 import node: 内置模块
   (fs/url/path/vm)⇒ 不需要 npm ci、不需要 electron,秒级完成。
5. **测试自足,CI 上不会因缺本地服务而红**:webui 测试用 httptest 与
   `127.0.0.1:0`,真实 LLM 测试带 t.Skip 守卫。
6. **action 版本已核实存在**:checkout/setup-go/setup-node/setup-python 均用
   v7(经 GitHub API 逐个确认 tag 存在,避免「版本不存在 ⇒ 立刻红」)。

## 明确不进 CI(依赖真机/密钥/内网,否则只会变 flaky 噪音)

deploy-*.sh、waiter 真机(192.168.2.x)、`npm run test-live`(需真 Electron
+ Xvfb + 真后端)、scripts/kernel-stress/*、需 DEEPSEEK_API_KEY 的真实 LLM 测试。
This commit is contained in:
JianFeeeee
2026-09-29 10:23:21 +08:00
parent d676adbd0e
commit 6d7de92bbd

199
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,199 @@
# HomeAgent 主仓 CI。
#
# 设计原则:**CI 里跑的每一条命令,都是本地已实测通过的命令**。
# 不写「应该有用来试试」的步骤 —— 未验证的 CI 步骤会把假红灯变成常态,
# 最后所有人学会忽略它。
#
# 覆盖范围与本地 `make test` 对齐(build / vet / test / client-versions /
# gui / csrc),并按依赖拆成独立 job,便于失败定位。
#
# 明确**不在** CI 里跑的东西(依赖真机/密钥/内网,跑了只会变 flaky 噪音):
# - deploy-*.sh / homed 生产部署
# - waiter 真机验证(192.168.2.x)
# - cmd/gui 的 `npm run test-live`(需真 Electron + Xvfb + 真后端)
# - scripts/kernel-stress/*(需 llmsproxy 与压测端点)
# - 需要 DEEPSEEK_API_KEY / MEDIALIVE_* 的真实 LLM 测试(已自带 t.Skip)
name: CI
on:
push:
branches: [main, 'release/**']
pull_request:
workflow_dispatch:
# 只读权限:CI 不需要写仓库。
permissions:
contents: read
# 同一分支连续推送时取消旧跑,省额度也避免过期结果误导。
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
env:
# gojieba / onnx 相关包需要 cgo ⇒ 不能用 CGO_ENABLED=0。
CGO_ENABLED: 1
# 减少 go test 输出噪音。
GOFLAGS: -buildvcs=false
jobs:
# ── Go 后端:构建 + 静态检查 + 全量测试 + 跨平台客户端版本一致性 ──
go:
name: Go build / vet / test
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version-file: go.mod
cache: true
# cgo 需要 gcc/g++(gojieba 会编译自带 C++ 源码)。
- name: 确认 cgo 工具链
run: |
gcc --version | head -1
g++ --version | head -1
- name: go build ./...
run: go build ./...
- name: go vet ./...
run: go vet ./...
# ./... 不点名 cmd/gui(该目录是纯 Electron,无 .go 文件):
# 显式 `go test ./cmd/gui` 会报 "no Go files",那是误报,不是缺陷。
- name: go test ./...
run: go test ./... -count=1 -timeout 20m
# 跨平台客户端版本一致性:内核 internal/meta 是唯一事实源,
# GUI(package.json) / 鸿蒙(AppScope/app.json5) / waiter 都必须跟它一致。
- name: 客户端版本一致性
run: make check-client-versions
# ── 竞态检测(并发改动的主要防线)──
race:
name: Race detector
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version-file: go.mod
cache: true
- name: go test -race(并发核心)
run: |
go test -race \
./internal/agent/core/ ./cmd/waiter/ \
-count=1 -timeout 15m
# ── 交叉编译:可在无 cgo 下构建的客户端/工具 ──
#
# 只有这三个 cmd 支持纯交叉编译。另外三个依赖 cgo(gojieba / onnx):
# homed / memgc / homed-kb-migrate → internal/memory(gojieba)
# homed → internal/agent/api(onnx)
# 它们必须在原生平台构建(见 Makefile 的 build target)。
cross:
name: Cross-compile
runs-on: ubuntu-latest
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
include:
- goos: linux
goarch: amd64
ext: ""
- goos: linux
goarch: arm64
ext: ""
- goos: darwin
goarch: amd64
ext: ""
- goos: darwin
goarch: arm64
ext: ""
- goos: windows
goarch: amd64
ext: ".exe"
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version-file: go.mod
cache: true
- name: 构建 ${{ matrix.goos }}/${{ matrix.goarch }}
env:
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
CGO_ENABLED: 0
run: |
set -euo pipefail
mkdir -p dist
for c in waiter initconfig mock-server; do
out="dist/${c}_${{ matrix.goos }}_${{ matrix.goarch }}${{ matrix.ext }}"
go build -trimpath -o "$out" "./cmd/${c}"
echo " ✓ ${c} ${{ matrix.goos }}/${{ matrix.goarch }}"
done
# ── Electron GUI(纯 Node 测试,零依赖)──
#
# `npm test` 只跑三个 .mjs,全部只 import node: 内置模块(fs/url/path/vm),
# 所以**不需要 npm ci、不需要 electron**,秒级完成。
# `npm run test-live` 需真 Electron + 真后端 ⇒ 不进 CI。
gui:
name: GUI (node)
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: '22'
- name: npm test
working-directory: cmd/gui
run: npm test
# ── C 基础设施门禁(ABI / 告警 / ASan+UBSan / 跨架构)──
csrc:
name: C infrastructure gates
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v7
# clang 供双编译器告警对照;gcc-aarch64 供跨架构编译门禁。
# 门禁在缺工具时是显式 SKIP 而不是假通过,这里装齐以免静默降级。
- name: 安装 C 工具链
run: |
sudo apt-get update -qq
sudo apt-get install -y -qq cmake clang gcc-aarch64-linux-gnu
- name: make check-csrc
run: make check-csrc
# ── 文档站构建(mkdocs,纯 Python,无外部依赖)──
docs:
name: Docs build
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
with:
python-version: '3.12'
- name: 校验站点配置可解析
# 这里只做「配置与文档源没坏」的轻量校验,不做完整 mkdocs build
# (站点发布有独立流水线,见 deploy-sdk-site.sh)。
run: |
set -euo pipefail
if [ -f mkdocs.yml ]; then
python -c \
"import yaml; yaml.safe_load(open('mkdocs.yml'))" \
&& echo "mkdocs.yml OK"
else
echo "无 mkdocs.yml,跳过"
fi
test -d docs || echo "无 docs/,跳过"