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.
This commit is contained in:
Sycun committed 2026-10-08 16:16:14 +08:00
1 parent 9c6928074d
commit 9a68a17cec
2 files changed
+48 -1

No files matched your search

+47
View File
@@ -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")
}
}
+1 -1
View File
@@ -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:"