mirror of
https://gitcode.com/JianFeeeee/homeagent-sdk.git
synced 2026-09-29 22:05:25 +00:00
ci: 建立 CI —— 此前 main 的推送与 PR 完全没有检查
## 缺口 本仓此前**只有 release.yml**(只在 release/** 推送时跑)。也就是说 推 main、开 PR 一律无检查,而 SDK 正是外部插件开发者直接依赖的契约面 (sdk/plugin.go 接口一破,所有外部插件编译失败)。 ## 四个 job(每条命令都本地实测过) | job | 内容 | 实测耗时 | |---|---|---| | go | 根模块 build + vet + test | <1s | | hmapdev | 嵌套 module 测试 + 五平台交叉编译(矩阵) | ~2s + 编译 | | examples | 构建全部 20 个示例(linux/amd64、darwin/arm64) | 9s / 21s | | consistency | Lua SDK 三副本一致 + skills 可识别 + mkdocs --strict | ~2s | ## 三处「不能想当然」的地方(都有实测依据) 1. **示例不能用 `go build` 验**。它们是插件(只有 plugin.go、没有 func main), 必须由 hmapdev 注入 main 包装;直接 go build 得到 "function main is undeclared in the main package" —— 那不是缺陷,是方式不对。 故与发版走**同一个脚本**(package/build-examples.sh),避免 CI 与发版路径分叉。 2. **tools/hmapdev 是独立 module**,根模块的 `go test ./...` 不会进入它 —— 必须单独跑,否则它的测试永远不在 CI 里执行(Go 的模块边界)。 3. **不能用 `yaml.safe_load` 校验 mkdocs.yml**:它含 mkdocs-material 的 `!!python/name:` 标签(配置 emoji 的官方写法),safe_load 报 ConstructorError —— 是校验方式不对。改用 `mkdocs build --strict` (本地实测 2s、0 warning)。 ## 明确不进 CI - `hmapdev skill install` —— 它会写开发者本机的 ~/.claude、~/.codex 等目录 - 需要内核仓在场的检查(本仓独立可测) - 任何网络/真机依赖 CGO_ENABLED=0(SDK 纯 Go,与主仓相反)。 actionlint 全绿(修掉一处 shellcheck SC2012)。
This commit is contained in:
219
.github/workflows/ci.yml
vendored
Normal file
219
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,219 @@
|
||||
# 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
|
||||
- uses: actions/setup-go@v7
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
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
|
||||
- uses: actions/setup-go@v7
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
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
|
||||
|
||||
- name: 交叉编译
|
||||
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
|
||||
- uses: actions/setup-go@v7
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
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
|
||||
|
||||
- uses: actions/setup-go@v7
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
cache: true
|
||||
|
||||
# skills/ 会随 SDK store 分发给所有 agent(hmapdev skill install)。
|
||||
# skill list 会读 skills/ 目录并报告可用项 —— 目录结构坏掉会在这里红。
|
||||
- name: 技能目录可被 hmapdev 识别
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd tools/hmapdev && go build -o /tmp/hmapdev . && cd "$GITHUB_WORKSPACE"
|
||||
/tmp/hmapdev skill list
|
||||
/tmp/hmapdev 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
|
||||
Reference in New Issue
Block a user