package main import ( "encoding/json" "os" "os/exec" "path/filepath" "runtime" "testing" ) func TestReleaseWrapperPreservesNativeExitStatuses(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("POSIX release entry point") } _, source, _, _ := runtime.Caller(0) root := filepath.Clean(filepath.Join(filepath.Dir(source), "../..")) realGit, err := exec.LookPath("git") if err != nil { t.Fatal(err) } wrapper, err := os.ReadFile(filepath.Join(root, "scripts/release")) if err != nil { t.Fatal(err) } for _, mode := range []struct { name string status int version string }{{"success", 0, "v1.2.3"}, {"invalid", 2, "invalid"}, {"rejected", 1, "v1.2.3"}, {"unknown", 3, "v1.2.3"}} { t.Run(mode.name, func(t *testing.T) { repository := filepath.Join(t.TempDir(), "source") clone := exec.Command(realGit, "clone", "--local", "--no-hardlinks", root, repository) if output, err := clone.CombinedOutput(); err != nil { t.Fatalf("clone: %v %s", err, output) } cliGitRun(t, repository, "config", "user.name", "ReleaseKit Test") cliGitRun(t, repository, "config", "user.email", "fixture@example.test") cliGitRun(t, repository, "config", "commit.gpgsign", "false") if err := os.WriteFile(filepath.Join(repository, "scripts/release"), wrapper, 0755); err != nil { t.Fatal(err) } if err := os.MkdirAll(filepath.Join(repository, "docs/releases"), 0700); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(repository, "docs/releases/v1.2.3.md"), []byte("# ReleaseKit v1.2.3\n"), 0600); err != nil { t.Fatal(err) } profile := map[string]any{"product": "ReleaseKit", "checks": []map[string]any{{"args": []string{"sh", "-c", "true"}}}} content, _ := json.Marshal(profile) if err := os.WriteFile(filepath.Join(repository, "releasekit.json"), content, 0600); err != nil { t.Fatal(err) } cliGitRun(t, repository, "add", "--all") cliGitRun(t, repository, "commit", "-m", "prepare wrapper fixture") remote := filepath.Join(t.TempDir(), "origin.git") cliGitRun(t, repository, "init", "--bare", remote) cliGitRun(t, repository, "remote", "set-url", "origin", remote) cliGitRun(t, repository, "push", "origin", "HEAD:refs/heads/main") if mode.name == "rejected" { if err := os.WriteFile(filepath.Join(remote, "hooks/pre-receive"), []byte("#!/bin/sh\nexit 1\n"), 0755); err != nil { t.Fatal(err) } } if mode.name == "unknown" { bin := t.TempDir() marker := filepath.Join(bin, "push-started") shim := `#!/bin/sh for arg do if [ "$arg" = push ]; then : > "$RELEASEKIT_TEST_PUSH_MARKER"; exit 1; fi done if [ -f "$RELEASEKIT_TEST_PUSH_MARKER" ]; then for arg do if [ "$arg" = ls-remote ]; then exit 128; fi; done fi exec "$RELEASEKIT_TEST_REAL_GIT" "$@" ` if err := os.WriteFile(filepath.Join(bin, "git"), []byte(shim), 0755); err != nil { t.Fatal(err) } t.Setenv("PATH", bin+string(os.PathListSeparator)+os.Getenv("PATH")) t.Setenv("RELEASEKIT_TEST_REAL_GIT", realGit) t.Setenv("RELEASEKIT_TEST_PUSH_MARKER", marker) } command := exec.Command("./scripts/release", mode.version) command.Dir = repository output, err := command.CombinedOutput() status := 0 if err != nil { exit, ok := err.(*exec.ExitError) if !ok { t.Fatal(err) } status = exit.ExitCode() } if status != mode.status { t.Fatalf("status=%d want=%d output=%s", status, mode.status, output) } }) } }