ci / test (pull_request) Failing after 1m0s
Why: Merge commits share a tree with the pinned feature commit, the import ratchet downloaded modules during CI, and task sync wrote the checkpoint onto the wrong card. Evidence: check-pins accepts 6c0f1e8 (same tree as Backend squad 8e987bf) and rejects empty-tree 8db069d; both objects stayed local. An empty GOMODCACHE run of lint-boundaries matches the cached go list, 14 pairs. bash -n scripts/task.sh. Impact: make pin no longer checks out Backend nested core or agent-command, and a failing pin check does not fail the target. task sync writes the branch card or warns. precheck reports completed-but-unarchived cards and card-close branches older than 24 hours. Refs: feature/agent-stack-r0-r1 Co-authored-by: Cursor <cursoragent@cursor.com>
100 lines
2.2 KiB
Go
100 lines
2.2 KiB
Go
// 离线列出模块内非测试 Go 文件的导入。
|
|
// 只使用标准库,跳过 _test.go 和带 go.mod 的子目录,避免 go list 去下载模块图。
|
|
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"go/parser"
|
|
"go/token"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
func main() {
|
|
for _, root := range os.Args[1:] {
|
|
mod := modulePath(filepath.Join(root, "go.mod"))
|
|
if mod == "" {
|
|
fmt.Fprintf(os.Stderr, "lint-imports: %s has no module path\n", root)
|
|
os.Exit(1)
|
|
}
|
|
err := filepath.WalkDir(root, func(path string, d os.DirEntry, err error) error {
|
|
if err != nil || !d.IsDir() {
|
|
return nil
|
|
}
|
|
name := d.Name()
|
|
if name == "vendor" || (name != "." && strings.HasPrefix(name, ".")) {
|
|
return filepath.SkipDir
|
|
}
|
|
if path != root {
|
|
if _, statErr := os.Stat(filepath.Join(path, "go.mod")); statErr == nil {
|
|
return filepath.SkipDir
|
|
}
|
|
}
|
|
return printImports(root, mod, path)
|
|
})
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "lint-imports: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
}
|
|
|
|
func modulePath(goMod string) string {
|
|
f, err := os.Open(goMod)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
defer f.Close()
|
|
sc := bufio.NewScanner(f)
|
|
for sc.Scan() {
|
|
fields := strings.Fields(sc.Text())
|
|
if len(fields) >= 2 && fields[0] == "module" {
|
|
return fields[1]
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func printImports(root, mod, dir string) error {
|
|
rel, err := filepath.Rel(root, dir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
importer := mod
|
|
if rel != "." {
|
|
importer = mod + "/" + filepath.ToSlash(rel)
|
|
}
|
|
entries, err := os.ReadDir(dir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fset := token.NewFileSet()
|
|
seen := map[string]struct{}{}
|
|
var imports []string
|
|
for _, entry := range entries {
|
|
name := entry.Name()
|
|
if entry.IsDir() || !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") {
|
|
continue
|
|
}
|
|
file, err := parser.ParseFile(fset, filepath.Join(dir, name), nil, parser.ImportsOnly)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
for _, imp := range file.Imports {
|
|
path := strings.Trim(imp.Path.Value, `"`)
|
|
if _, ok := seen[path]; ok {
|
|
continue
|
|
}
|
|
seen[path] = struct{}{}
|
|
imports = append(imports, path)
|
|
}
|
|
}
|
|
if len(imports) == 0 {
|
|
return nil
|
|
}
|
|
fmt.Printf("%s %s\n", importer, strings.Join(imports, " "))
|
|
return nil
|
|
}
|