mirror of
https://gitcode.com/JianFeeeee/homeagent-sdk.git
synced 2026-09-30 06:13:14 +00:00
首次跑出来的 8 个失败全是本 workflow 自己的问题,不是代码缺陷。
三条都属同一类:**命令本地验证过,但环境前提不同**。
## 1. hmapdev 交叉编译:在错误的目录跑(5 个平台全红)
no Go files in /home/runner/work/homeagentsdk/homeagentsdk
`go build .` 缺 `working-directory: tools/hmapdev`,于是在仓库根执行 ——
根目录没有 Go 文件(包在 sdk/ 子目录)。加 working-directory 后本地实测
linux/arm64、darwin/arm64、windows/amd64 均产出 27–30MB 二进制。
## 2. Examples:装了 Go 1.21,而 examples 要求 1.25
go: go.mod requires go >= 1.25.0 (running go 1.21.0; GOTOOLCHAIN=local)
`go-version-file: go.mod` 读的是**根** go.mod —— 它写 `go 1.21.0`,
而 20 个 `example/*/go.mod` 都要求 `go 1.25.0`(只有根与 tools/hmapdev 是 1.21)。
于是 CI 装 1.21,examples 构建必失败。
★ 为什么本地测不出来:本机 Go 1.27 且 GOTOOLCHAIN 默认可自动取更高工具链,
更高版本能满足 1.25 的下限,所以一路通过。而 GitHub runner 上
**GOTOOLCHAIN=local**,Go 拒绝自动下载工具链,低版本直接报错。
本地「能过」在这里完全不构成证据。
改法:SDK CI 全部钉 `go-version: '1.25'`(同时满足 1.21 的下限与
examples 的 1.25 要求)。
## 3. 技能检查:hmapdev 建到了 /tmp
error: no active SDK version set
`resolveSkillsSource()` 先用**可执行文件位置**向上找仓库
(tools/hmapdev → ../../skills),落空才回退到 SDK store 的活跃版本。
我把二进制建到 /tmp/hmapdev ⇒ 推出仓库失败 ⇒ 回退 ⇒ CI 里没有 store ⇒ 报错。
改法:建到仓库内 `<repo>/build/hmapdev_ci`。本地实测(构建在仓库内时,
即便从 /tmp 调用也能正确识别仓库源——解析依据是 exe 位置而非 cwd)。
## 附带记录
- 根 go.mod(1.21) 与 example/*/go.mod(1.25) 的版本不一致本身值得关注:
用 Go 1.22–1.24 的用户按示例走会失败。是否统一属产品决策,本次不动。
- actionlint 全绿。
252 lines
10 KiB
YAML
252 lines
10 KiB
YAML
# HomeAgent SDK 仓 CI。
|
||
#
|
||
# 与 release.yml 分工:本文件管「推送到 main / PR 时的检查」,release.yml 管
|
||
# 「release/** 推送时的发版」。此前本仓**只有** release.yml —— main 的推送与
|
||
# PR 完全没有检查,而 SDK 是被外部插件开发者直接依赖的契约面(sdk/plugin.go
|
||
# 的接口一旦破,所有外部插件编译失败),必须有门。
|
||
#
|
||
# 设计原则与主仓一致:**CI 里每条命令都是本地已实测通过的**。
|
||
# 不写「应该有用来试试」的步骤 —— 未验证的 CI 步骤会把假红灯变成常态。
|
||
#
|
||
# 明确不进 CI 的:
|
||
# - `hmapdev skill install`(会写 ~/.claude、~/.codex 等**开发者本机目录**)
|
||
# - 需要内核仓在场的检查(本仓独立可测;sync-lua-sdk.sh 会在缺内核时
|
||
# 明确 skip 而不是假装成功)
|
||
# - 任何网络/真机依赖
|
||
name: CI
|
||
|
||
on:
|
||
push:
|
||
branches: [main, 'release/**']
|
||
pull_request:
|
||
workflow_dispatch:
|
||
|
||
permissions:
|
||
contents: read
|
||
|
||
concurrency:
|
||
group: ci-${{ github.ref }}
|
||
cancel-in-progress: true
|
||
|
||
env:
|
||
# SDK 本身不需要 cgo(hmapdev 与 sdk 包都是纯 Go)—— 与主仓相反。
|
||
CGO_ENABLED: 0
|
||
GOFLAGS: -buildvcs=false
|
||
|
||
jobs:
|
||
# ── 根模块:SDK 对外接口所在 ──
|
||
go:
|
||
name: Go build / vet / test
|
||
runs-on: ubuntu-latest
|
||
timeout-minutes: 15
|
||
steps:
|
||
- uses: actions/checkout@v7
|
||
# ★ 钉 1.25 而不是 go-version-file: go.mod —— 根 go.mod 写的是
|
||
# go 1.21.0,但 20 个 example/*/go.mod 都要求 go 1.25.0。
|
||
# 读根 go.mod 会装 1.21,examples 构建必然失败
|
||
# ("go.mod requires go >= 1.25.0 (running go 1.21.0; GOTOOLCHAIN=local)")。
|
||
# GitHub runner 上 GOTOOLCHAIN=local,Go 不会自动下载更高工具链,
|
||
# 所以本地「能过」不代表 CI 能过。
|
||
- uses: actions/setup-go@v7
|
||
with:
|
||
go-version: '1.25'
|
||
cache: true
|
||
- name: go build ./...
|
||
run: go build ./...
|
||
- name: go vet ./...
|
||
run: go vet ./...
|
||
- name: go test ./...
|
||
run: go test ./... -count=1 -timeout 10m
|
||
|
||
# ── hmapdev 工具链(嵌套 module,根模块的 ./... 不会进入它)──
|
||
hmapdev:
|
||
name: hmapdev (${{ matrix.goos }}/${{ matrix.goarch }})
|
||
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
|
||
# ★ 钉 1.25 而不是 go-version-file: go.mod —— 根 go.mod 写的是
|
||
# go 1.21.0,但 20 个 example/*/go.mod 都要求 go 1.25.0。
|
||
# 读根 go.mod 会装 1.21,examples 构建必然失败
|
||
# ("go.mod requires go >= 1.25.0 (running go 1.21.0; GOTOOLCHAIN=local)")。
|
||
# GitHub runner 上 GOTOOLCHAIN=local,Go 不会自动下载更高工具链,
|
||
# 所以本地「能过」不代表 CI 能过。
|
||
- uses: actions/setup-go@v7
|
||
with:
|
||
go-version: '1.25'
|
||
cache: true
|
||
|
||
# tools/hmapdev 是**独立 module**(有自己的 go.mod)——
|
||
# 根模块的 `go test ./...` 不会进入它,必须单独跑,否则它的测试
|
||
# 永远不在 CI 里执行。这是 Go 的模块边界,不是配置问题。
|
||
- name: go test(嵌套 module)
|
||
working-directory: tools/hmapdev
|
||
run: go test ./... -count=1 -timeout 10m
|
||
|
||
# main 包在 tools/hmapdev —— 不指定工作目录会在仓库根跑 `go build .`,
|
||
# 而根目录没有 Go 文件(包在 sdk/ 子目录),报 "no Go files in ..."。
|
||
- name: 交叉编译
|
||
working-directory: tools/hmapdev
|
||
env:
|
||
GOOS: ${{ matrix.goos }}
|
||
GOARCH: ${{ matrix.goarch }}
|
||
run: |
|
||
set -euo pipefail
|
||
out="hmapdev_${{ matrix.goos }}_${{ matrix.goarch }}${{ matrix.ext }}"
|
||
go build -trimpath \
|
||
-ldflags "-X gitcode.com/JianFeeeee/homeagent-sdk/meta.Version=0.0.0-ci" \
|
||
-o "/tmp/$out" .
|
||
test -s "/tmp/$out" || { echo "ERROR: 未产出 $out"; exit 1; }
|
||
printf " ✓ %-28s %s 字节\n" "$out" "$(stat -c %s "/tmp/$out")"
|
||
file "/tmp/$out"
|
||
|
||
# ── 示例插件:发版产物里最容易被使用者直接安装的东西 ──
|
||
#
|
||
# 为什么必须验:示例是使用者的模板(拷了就改),且**发版会连同 .hmap 一起发**
|
||
# —— 插件二进制与内核是协议绑定的(ProtocolVersion + 统一共享内存区魔数),
|
||
# 示例编不出来就意味着这次发版发不出配套产物。
|
||
#
|
||
# ★ 示例**不能**用 `go build` 验:它们是插件(只有 plugin.go、没有 func main),
|
||
# 必须由 hmapdev 注入 main 包装。直接 go build 会得到
|
||
# "function main is undeclared in the main package" —— 那不是缺陷,
|
||
# 是构建方式不对(本地实测确认)。
|
||
examples:
|
||
name: Examples (${{ matrix.target }})
|
||
runs-on: ubuntu-latest
|
||
timeout-minutes: 30
|
||
strategy:
|
||
fail-fast: false
|
||
matrix:
|
||
# windows 不在列:build-examples.sh 会明确拒绝(协议 2 的统一共享
|
||
# 内存区未移植到 Windows),那是有意的设计而不是待修缺陷。
|
||
target: ['linux/amd64', 'darwin/arm64']
|
||
steps:
|
||
- uses: actions/checkout@v7
|
||
# ★ 钉 1.25 而不是 go-version-file: go.mod —— 根 go.mod 写的是
|
||
# go 1.21.0,但 20 个 example/*/go.mod 都要求 go 1.25.0。
|
||
# 读根 go.mod 会装 1.21,examples 构建必然失败
|
||
# ("go.mod requires go >= 1.25.0 (running go 1.21.0; GOTOOLCHAIN=local)")。
|
||
# GitHub runner 上 GOTOOLCHAIN=local,Go 不会自动下载更高工具链,
|
||
# 所以本地「能过」不代表 CI 能过。
|
||
- uses: actions/setup-go@v7
|
||
with:
|
||
go-version: '1.25'
|
||
cache: true
|
||
|
||
- name: 构建 hmapdev(宿主)
|
||
run: |
|
||
set -euo pipefail
|
||
cd tools/hmapdev
|
||
go build -o "$GITHUB_WORKSPACE/build/hmapdev_host" .
|
||
|
||
# 用发版同一个脚本(package/build-examples.sh),避免 CI 与发版路径分叉。
|
||
- name: 构建全部示例
|
||
env:
|
||
HMAPDEV: ${{ github.workspace }}/build/hmapdev_host
|
||
TARGET: ${{ matrix.target }}
|
||
run: |
|
||
set -euo pipefail
|
||
bash package/build-examples.sh "$TARGET" /tmp/examples
|
||
echo
|
||
n=$(find /tmp/examples -name '*.hmap' | wc -l)
|
||
echo " .hmap 产物数: $n"
|
||
# 示例目录数应与产物数一致(少一个都要红)
|
||
want=$(find example -mindepth 2 -maxdepth 2 -name plugin.go | wc -l)
|
||
echo " 示例源码数: $want"
|
||
[ "$n" -ge "$want" ] || { echo "ERROR: 产物少于示例数"; exit 1; }
|
||
for f in /tmp/examples/*.hmap; do
|
||
printf " %9.1fKB %s\n" \
|
||
"$(stat -c %s "$f" | awk '{print $1/1024}')" "$(basename "$f")"
|
||
done
|
||
|
||
# ── 一致性与文档 ──
|
||
consistency:
|
||
name: Consistency & docs
|
||
runs-on: ubuntu-latest
|
||
timeout-minutes: 15
|
||
steps:
|
||
- uses: actions/checkout@v7
|
||
|
||
# sdk.lua 有**四份**副本(本仓三份 + 内核仓一份),历史上漂移过,
|
||
# 出现「mock 有、内核没有」的静默失配。此处钉住本仓内的三份。
|
||
- name: Lua SDK 副本一致性
|
||
run: |
|
||
set -euo pipefail
|
||
canon=sdk/lua/sdk.lua
|
||
[ -f "$canon" ] || { echo "ERROR: 缺 $canon"; exit 1; }
|
||
want=$(sha256sum "$canon" | cut -d' ' -f1)
|
||
fail=0
|
||
for f in tools/hmapdev/assets/sdk.lua example/luademo/sdk.lua; do
|
||
have=$(sha256sum "$f" | cut -d' ' -f1)
|
||
if [ "$have" = "$want" ]; then
|
||
echo " ✓ $f"
|
||
else
|
||
echo " ✗ $f 与 $canon 不一致" >&2
|
||
echo " canon=$want" >&2
|
||
echo " this =$have" >&2
|
||
echo " 解法:bash scripts/sync-lua-sdk.sh" >&2
|
||
fail=1
|
||
fi
|
||
done
|
||
[ "$fail" = "0" ] || exit 1
|
||
|
||
# ★ 钉 1.25 而不是 go-version-file: go.mod —— 根 go.mod 写的是
|
||
# go 1.21.0,但 20 个 example/*/go.mod 都要求 go 1.25.0。
|
||
# 读根 go.mod 会装 1.21,examples 构建必然失败
|
||
# ("go.mod requires go >= 1.25.0 (running go 1.21.0; GOTOOLCHAIN=local)")。
|
||
# GitHub runner 上 GOTOOLCHAIN=local,Go 不会自动下载更高工具链,
|
||
# 所以本地「能过」不代表 CI 能过。
|
||
- uses: actions/setup-go@v7
|
||
with:
|
||
go-version: '1.25'
|
||
cache: true
|
||
|
||
# skills/ 会随 SDK store 分发给所有 agent(hmapdev skill install)。
|
||
# skill list 会读 skills/ 目录并报告可用项 —— 目录结构坏掉会在这里红。
|
||
- name: 技能目录可被 hmapdev 识别
|
||
run: |
|
||
set -euo pipefail
|
||
# ★ 必须把 hmapdev 建在**仓库内**:resolveSkillsSource() 先从
|
||
# 可执行文件位置向上找仓库(tools/hmapdev → ../../skills),
|
||
# 落空才回退到 SDK store 的活跃版本 —— 而 CI 里没有 store,
|
||
# 于是报 "no active SDK version set"。建到 /tmp 就会落空。
|
||
mkdir -p build
|
||
( cd tools/hmapdev && go build -o "$GITHUB_WORKSPACE/build/hmapdev_ci" . )
|
||
./build/hmapdev_ci skill list
|
||
./build/hmapdev_ci skill path
|
||
|
||
- uses: actions/setup-python@v7
|
||
with:
|
||
python-version: '3.12'
|
||
|
||
# 文档站会被部署(deploy-sdk-site.sh)——站点构建坏了此前无从发现。
|
||
# --strict 把 warning 升级为 error:断链、缺失引用都会红。
|
||
#
|
||
# ★ 不能用 yaml.safe_load 校验 mkdocs.yml:它含 mkdocs-material 的
|
||
# `!!python/name:` 标签(配置 emoji 的官方写法),safe_load 处理不了,
|
||
# 会报 ConstructorError —— 那是校验方式不对,不是配置有问题。
|
||
- name: 文档站构建(mkdocs --strict)
|
||
run: |
|
||
set -euo pipefail
|
||
python3 -m pip install --quiet mkdocs-material
|
||
mkdocs build --strict --site-dir /tmp/site
|