//go:build ignore package main import ( "errors" "fmt" "os" "os/exec" "path/filepath" "runtime" "strings" ) const modulePath = "code.zhecent.com/open/shop-crm-agent" func main() { if err := run(); err != nil { _, _ = fmt.Fprintln(os.Stderr, err) os.Exit(1) } } func run() error { repoRoot, err := os.Getwd() if err != nil { return err } if _, err := os.Stat(filepath.Join(repoRoot, "go.mod")); err != nil { return errors.New("build.go must run from the shop-crm-agent repository root") } moduleCommand := exec.Command("go", "list", "-m", "-f", "{{.Path}}") moduleCommand.Dir = repoRoot moduleOutput, err := moduleCommand.CombinedOutput() if err != nil { return fmt.Errorf("read Go module path: %w: %s", err, strings.TrimSpace(string(moduleOutput))) } if actualModule := strings.TrimSpace(string(moduleOutput)); actualModule != modulePath { return fmt.Errorf("unexpected Go module; want %s", modulePath) } env := withEnv(os.Environ(), "CGO_ENABLED", "0") if err := runCommand(repoRoot, env, "go", "test", "./..."); err != nil { return fmt.Errorf("test shop-crm-agent: %w", err) } version := gitVersion(repoRoot) binaryName := "shop-crm-agent" if runtime.GOOS == "windows" { binaryName += ".exe" } binDir := filepath.Join(repoRoot, "bin") if err := os.MkdirAll(binDir, 0o755); err != nil { return err } tempFile, err := os.CreateTemp(binDir, "."+binaryName+".tmp-") if err != nil { return err } tempPath := tempFile.Name() if err := tempFile.Close(); err != nil { return err } if err := os.Remove(tempPath); err != nil { return err } defer os.Remove(tempPath) ldflags := "-s -w -X main.version=" + version if err := runCommand(repoRoot, env, "go", "build", "-trimpath", "-ldflags", ldflags, "-o", tempPath, "./cmd/shop-crm-agent"); err != nil { return fmt.Errorf("build shop-crm-agent: %w", err) } if runtime.GOOS != "windows" { if err := os.Chmod(tempPath, 0o755); err != nil { return err } } probe := exec.Command(tempPath, "--version") probe.Dir = repoRoot probeOutput, err := probe.CombinedOutput() if err != nil { return fmt.Errorf("probe built binary: %w: %s", err, strings.TrimSpace(string(probeOutput))) } targetPath := filepath.Join(binDir, binaryName) if err := replaceBinary(tempPath, targetPath); err != nil { return err } fmt.Printf("installed: %s\n", filepath.Join("bin", binaryName)) fmt.Printf("version: %s\n", strings.TrimSpace(string(probeOutput))) return nil } func gitVersion(repoRoot string) string { command := exec.Command("git", "describe", "--tags", "--always", "--dirty") command.Dir = repoRoot output, err := command.Output() if err != nil || strings.TrimSpace(string(output)) == "" { return "dev" } return strings.TrimSpace(string(output)) } func replaceBinary(source, target string) error { if err := os.Rename(source, target); err != nil { return fmt.Errorf("install built binary: %w", err) } return nil } func runCommand(dir string, env []string, name string, args ...string) error { command := exec.Command(name, args...) command.Dir = dir command.Env = env command.Stdout = os.Stdout command.Stderr = os.Stderr return command.Run() } func withEnv(env []string, key, value string) []string { prefix := key + "=" result := make([]string, 0, len(env)+1) for _, entry := range env { if !strings.HasPrefix(entry, prefix) { result = append(result, entry) } } return append(result, prefix+value) }