mirror of
https://gitcode.com/JianFeeeee/homeagent-sdk.git
synced 2026-10-31 14:27:30 +00:00
fix(examples): 恢复 go.mod 相对路径 + 移除 plg.json 的 sdk 固定(修 CI 红)
CI 上 `Examples (linux/amd64)` 与 `(darwin/arm64)` 双红,只有两个失败: ✗ commondev 构建失败 ✗ editdoc 构建失败 error: 项目声明 sdk=1.4.0,但本地 SDK 存储里没有这个版本 其余 20 个示例全部成功 —— 说明不是通用问题,而是这两个被改坏了。 ## 根因(两个叠加) **① go.mod 被本机绝对路径污染** 我在上一个提交里用 `git add -A`,把本机 `go build` **自动改写**过的 go.mod 一并提交了: require github.com/JianFeeeee/homeagentsdk v1.4.0 replace github.com/JianFeeeee/homeagentsdk => /root/.homeagent/hmapdev/sdk/v1.4.0 基线(origin/main)是: require github.com/JianFeeeee/homeagentsdk v0.0.0 replace github.com/JianFeeeee/homeagentsdk => ../../ 本机那个目录真的存在 ⇒ 本地全绿;CI 没有 ⇒ 必红。 **② plg.json 声明了 `"sdk": "1.4.0"`** 一声明版本,hmapdev 就去**本地 SDK store** 找它,找不到直接拒绝构建。 全仓 20+ 示例**都不声明**,只有我改过的这两个声明了。 示例的正确依赖表达是 go.mod 的 `v0.0.0` + `replace ../../`。 ## 修法 两个文件都恢复到与其余示例一致的写法。 ## 判据(3 条,都是新加的) · `TestExampleGoModHasNoAbsoluteReplace`:任何示例 go.mod 不得含 `/root/`、`/home/`、`/Users/`、`C:\` · `TestExampleGoModUsesRelativeSDKReplace`:replace 必须是相对路径 `../../` · `TestExamplePlgJsonDoesNotPinSDKVersion`:plg.json 不得声明 sdk 变异 2/2 咬住(重新引入绝对路径 / 重新声明 sdk,都准确报出文件路径)。 ## 本地验证(模拟 CI 干净环境) 用干净 HOME 跑 `package/build-examples.sh`: · 修复前:成功 18 / 失败 4(commondev, editdoc, browser, rss) · 修复后:成功 20 / 失败 2(browser, rss —— **本机代理不通**, `proxy.golang.org` 超时;用本地 modcache 验证这两个可正常构建) 即 22/22 源码都能构建,CI 有网络不受影响。 ## 教训 `git add -A` 会把「构建工具自动改写的文件」一起提交。 提交前必须 `git status` 逐个看,尤其 go.mod / go.sum。
This commit is contained in:
@ -1,65 +1,7 @@
|
|||||||
module commondev
|
module commondev
|
||||||
|
|
||||||
go 1.21.0
|
go 1.25.0
|
||||||
|
|
||||||
require github.com/JianFeeeee/homeagentsdk v1.4.0
|
require github.com/JianFeeeee/homeagentsdk v0.0.0
|
||||||
|
|
||||||
// 与同目录其它示例一致:SDK 指向仓库内的 vendored 副本
|
replace github.com/JianFeeeee/homeagentsdk => ../../
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
replace github.com/JianFeeeee/homeagentsdk => /root/.homeagent/hmapdev/sdk/v1.4.0
|
|
||||||
|
|||||||
@ -6,8 +6,7 @@
|
|||||||
"description": "主管式多仓库开发流水线:登记项目、开工程对话、为每条线拉起内置 pi 并注册一对通道,投递任务给 pi 并在同一会话内续投。",
|
"description": "主管式多仓库开发流水线:登记项目、开工程对话、为每条线拉起内置 pi 并注册一对通道,投递任务给 pi 并在同一会话内续投。",
|
||||||
"author": "HomeAgent",
|
"author": "HomeAgent",
|
||||||
"entry": "plugin.so",
|
"entry": "plugin.so",
|
||||||
"sdk": "1.4.0",
|
"tags": ["commondev", "git", "agent", "develop"],
|
||||||
"tags": ["commondev", "git", "agent", "develop"],
|
|
||||||
"targets": "linux/amd64",
|
"targets": "linux/amd64",
|
||||||
"rawfiles": []
|
"rawfiles": []
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,18 +2,6 @@ module editdoc
|
|||||||
|
|
||||||
go 1.25.0
|
go 1.25.0
|
||||||
|
|
||||||
require github.com/JianFeeeee/homeagentsdk v1.4.0
|
require github.com/JianFeeeee/homeagentsdk v0.0.0
|
||||||
|
|
||||||
|
replace github.com/JianFeeeee/homeagentsdk => ../../
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
replace github.com/JianFeeeee/homeagentsdk => /root/.homeagent/hmapdev/sdk/v1.4.0
|
|
||||||
|
|||||||
@ -18,6 +18,5 @@
|
|||||||
"outdir": "dist",
|
"outdir": "dist",
|
||||||
"bundle": true,
|
"bundle": true,
|
||||||
"replaces": {},
|
"replaces": {},
|
||||||
"source_dirs": [],
|
"source_dirs": []
|
||||||
"sdk": "1.4.0"
|
|
||||||
}
|
}
|
||||||
129
tools/hmapdev/example_gomod_test.go
Normal file
129
tools/hmapdev/example_gomod_test.go
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
// 示例插件的 go.mod 判据(2026-10-17 CI 事故)。
|
||||||
|
//
|
||||||
|
// ## 事故
|
||||||
|
//
|
||||||
|
// 我在一个提交里用 `git add -A` 把本机 `go build` **自动改写**过的
|
||||||
|
// go.mod 一并提交了:
|
||||||
|
//
|
||||||
|
// require github.com/JianFeeeee/homeagentsdk v1.4.0
|
||||||
|
// replace github.com/JianFeeeee/homeagentsdk => /root/.homeagent/hmapdev/sdk/v1.4.0
|
||||||
|
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 本机绝对路径
|
||||||
|
//
|
||||||
|
// 后果:CI(干净环境)上 commondev / editdoc 构建**必然失败**
|
||||||
|
//
|
||||||
|
// error: 项目声明 sdk=1.4.0,但本地 SDK 存储里没有这个版本
|
||||||
|
//
|
||||||
|
// 而本机能过(那个目录真的存在)⇒ 本地全绿掩盖了问题,PR 卡在 CI 才暴露。
|
||||||
|
//
|
||||||
|
// ## 判据
|
||||||
|
//
|
||||||
|
// 1. 任何示例的 go.mod 都**不得**含本机绝对路径
|
||||||
|
// 2. replace 必须是相对路径(`../../`),这是 SDK 仓内示例的约定
|
||||||
|
// 3. plg.json 不得声明 `sdk` 版本 —— 一声明就要求本地 SDK store 有该版本,
|
||||||
|
// 而示例的正确依赖表达是 go.mod 的 v0.0.0 + replace ../../
|
||||||
|
//
|
||||||
|
// 这三条合起来保证「CI 干净环境能构建全部示例」。
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ★★★ 判据:示例 go.mod 不得含本机绝对路径。
|
||||||
|
func TestExampleGoModHasNoAbsoluteReplace(t *testing.T) {
|
||||||
|
for _, gm := range findExampleGoMods(t) {
|
||||||
|
b, err := os.ReadFile(gm)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
src := string(b)
|
||||||
|
for _, bad := range []string{"/root/", "/home/", "/Users/", "C:\\"} {
|
||||||
|
if strings.Contains(src, bad) {
|
||||||
|
rel := mustRel(t, gm)
|
||||||
|
t.Fatalf("★ %s 含本机绝对路径 %q ——\n"+
|
||||||
|
" CI(干净环境)会因此构建失败,而本机因为有那个目录反而通过。\n"+
|
||||||
|
" 示例必须用相对路径:replace ... => ../../", rel, bad)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ★★★ 判据:示例的 replace 指向 SDK 仓根(相对路径)。
|
||||||
|
func TestExampleGoModUsesRelativeSDKReplace(t *testing.T) {
|
||||||
|
reReplace := regexp.MustCompile(`(?m)^replace\s+\S*homeagentsdk\S*\s*=>\s*(\S+)`)
|
||||||
|
for _, gm := range findExampleGoMods(t) {
|
||||||
|
b, _ := os.ReadFile(gm)
|
||||||
|
m := reReplace.FindStringSubmatch(string(b))
|
||||||
|
if m == nil {
|
||||||
|
continue // 没有 replace 也算合法(某些示例可能不用)
|
||||||
|
}
|
||||||
|
tgt := m[1]
|
||||||
|
if filepath.IsAbs(tgt) {
|
||||||
|
t.Fatalf("★ %s 的 replace 是绝对路径 %q(必须相对)", mustRel(t, gm), tgt)
|
||||||
|
}
|
||||||
|
if tgt != "../../" {
|
||||||
|
t.Errorf("%s 的 replace 是 %q,本仓约定为 ../../(与 ai_image/calendar 等一致)",
|
||||||
|
mustRel(t, gm), tgt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ★★★ 判据:示例 plg.json 不得声明 sdk 版本。
|
||||||
|
//
|
||||||
|
// 为什么:一声明 `"sdk": "1.4.0"`,hmapdev 就会去**本地 SDK store** 找该版本,
|
||||||
|
// 找不到直接拒绝构建。而示例的正确依赖表达是 go.mod 的 v0.0.0 + replace ../../。
|
||||||
|
// 全仓 20+ 个示例都不声明,只有被我改过的两个声明了 ⇒ CI 只在这两个上红。
|
||||||
|
func TestExamplePlgJsonDoesNotPinSDKVersion(t *testing.T) {
|
||||||
|
root := repoRootForTest(t)
|
||||||
|
matches, _ := filepath.Glob(filepath.Join(root, "example", "*", "plg.json"))
|
||||||
|
reSDK := regexp.MustCompile(`"sdk"\s*:`)
|
||||||
|
for _, p := range matches {
|
||||||
|
b, err := os.ReadFile(p)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if reSDK.Match(b) {
|
||||||
|
rel := mustRel(t, p)
|
||||||
|
t.Fatalf("★ %s 声明了 sdk 版本 ——\n"+
|
||||||
|
" 这会让 hmapdev 去本地 SDK store 找该版本,干净 CI 上必然失败。\n"+
|
||||||
|
" 示例请用 go.mod 的 `require ... v0.0.0` + `replace ... => ../../`", rel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func findExampleGoMods(t *testing.T) []string {
|
||||||
|
t.Helper()
|
||||||
|
root := repoRootForTest(t)
|
||||||
|
matches, err := filepath.Glob(filepath.Join(root, "example", "*", "go.mod"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(matches) == 0 {
|
||||||
|
t.Fatal("没找到任何示例 go.mod ⇒ 判据会假绿,路径写错了?")
|
||||||
|
}
|
||||||
|
return matches
|
||||||
|
}
|
||||||
|
|
||||||
|
func repoRootForTest(t *testing.T) string {
|
||||||
|
t.Helper()
|
||||||
|
wd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
// tools/hmapdev → 上两级
|
||||||
|
return filepath.Dir(filepath.Dir(wd))
|
||||||
|
}
|
||||||
|
|
||||||
|
func mustRel(t *testing.T, p string) string {
|
||||||
|
t.Helper()
|
||||||
|
r, err := filepath.Rel(repoRootForTest(t), p)
|
||||||
|
if err != nil {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user