From 9a68a17ceca66bc907f22f538f2ea39ff6341868 Mon Sep 17 00:00:00 2001 From: Sycun <165354365+Sycun@users.noreply.github.com> Date: Thu, 8 Oct 2026 16:16:14 +0800 Subject: [PATCH] fix: the password-reset entry builds the cmd/server package, not one file `./run.sh --reset-admin-password` rebuilds the binary whenever it is missing or older than the sources, through build_go_project_quiet - the one build path left that compiled the single file `cmd/server/main.go`. A file-based go build only compiles the file it names, so it dropped every sibling of package main that this PR added; measured on the parent commit: cmd/server/main.go:35:22: undefined: updateCommandIfNeeded (the symbol lives in cmd/server/update_cli.go), which made the documented password-reset entry exactly the path that could not build itself. The normal start path and upgrade.sh already build `./cmd/server`; the quiet path now does too, and a test scans run.sh, upgrade.sh and scripts/*.sh so a file-based go build cannot come back unnoticed - it fails on the pre-fix tree with the command named. --- cmd/server/build_scripts_test.go | 47 ++++++++++++++++++++++++++++++++ run.sh | 2 +- 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 cmd/server/build_scripts_test.go diff --git a/cmd/server/build_scripts_test.go b/cmd/server/build_scripts_test.go new file mode 100644 index 00000000..a2c45721 --- /dev/null +++ b/cmd/server/build_scripts_test.go @@ -0,0 +1,47 @@ +package main + +import ( + "os" + "path/filepath" + "strings" + "testing" +) + +// Every `go build` in this repository's scripts has to target the cmd/server package. +// Building the single file cmd/server/main.go was tried once and broke the password reset +// entry: the file-based form silently leaves out sibling files of package main (it was +// update_cli.go that disappeared), and only `run.sh --reset-admin-password` used that +// build path, so nothing noticed until an operator needed it in an emergency. Compiling +// the package can never have that failure mode. +func TestScriptsBuildThePackageNotASingleFile(t *testing.T) { + root := filepath.Join("..", "..") + scripts := []string{filepath.Join(root, "run.sh"), filepath.Join(root, "upgrade.sh")} + more, err := filepath.Glob(filepath.Join(root, "scripts", "*.sh")) + if err != nil { + t.Fatal(err) + } + scripts = append(scripts, more...) + + found := 0 + for _, script := range scripts { + data, err := os.ReadFile(script) + if err != nil { + t.Fatalf("read %s: %v", script, err) + } + for _, line := range strings.Split(string(data), "\n") { + if !strings.Contains(line, "go build") { + continue + } + found++ + if strings.Contains(line, ".go") { + t.Errorf("%s builds a single .go file; build ./cmd/server instead:\n %s", + script, strings.TrimSpace(line)) + } + } + } + // A scan that finds no build command at all is looking in the wrong place, and a test + // that cannot see the thing it guards passes for the wrong reason. + if found == 0 { + t.Fatal("no `go build` command found in the scripts") + } +} diff --git a/run.sh b/run.sh index c58b6186..3f6e382a 100755 --- a/run.sh +++ b/run.sh @@ -374,7 +374,7 @@ build_go_project_quiet() { rm -f "$GO_DOWNLOAD_LOG" GO_BUILD_LOG=$(mktemp) - if ! GOPROXY="$GOPROXY" go build -o "$BINARY_NAME" cmd/server/main.go >"$GO_BUILD_LOG" 2>&1; then + if ! GOPROXY="$GOPROXY" go build -o "$BINARY_NAME" ./cmd/server >"$GO_BUILD_LOG" 2>&1; then error "Build failed" echo "" info "Build error details:"