package main import ( "bytes" "context" "encoding/json" "fmt" "os" "os/exec" "path/filepath" "strings" "testing" "gitea.maximumdirect.net/eric/ReleaseKit/buildinfo" "gitea.maximumdirect.net/eric/ReleaseKit/cmd/releasekit/internal/cli" ) func TestVersionCommand(t *testing.T) { var stdout, stderr bytes.Buffer if status := run(context.Background(), []string{"version"}, &stdout, &stderr); status != 0 { t.Fatalf("run() status = %d, want 0; stderr = %q", status, stderr.String()) } if want := fmt.Sprintf("releasekit %s\n", buildinfo.Version()); stdout.String() != want { t.Fatalf("version output = %q, want %q", stdout.String(), want) } if stderr.Len() != 0 { t.Fatalf("version command wrote to stderr: %q", stderr.String()) } } func TestUnknownCommand(t *testing.T) { var stdout, stderr bytes.Buffer if status := run(context.Background(), []string{"publish"}, &stdout, &stderr); status != 2 { t.Fatalf("run() status = %d, want 2", status) } if stdout.Len() != 0 { t.Fatalf("unknown command wrote to stdout: %q", stdout.String()) } if want := "unknown command \"publish\"\n" + cli.Usage + "\n"; stderr.String() != want { t.Fatalf("usage output = %q, want %q", stderr.String(), want) } } func TestCheckCommandBindsConfiguredChecksToCapturedCandidate(t *testing.T) { repository := newCLIRepository(t) profilePath := filepath.Join(t.TempDir(), "profile with spaces.json") executable, err := os.Executable() if err != nil { t.Fatal(err) } settings := cli.Settings{ Product: "Example Product", Remote: "origin", Checks: []cli.CheckCommand{{ Args: []string{executable, "-test.run=TestCandidateCheckHelper", "--"}, Env: map[string]string{ "RELEASEKIT_CHECK_HELPER": "1", "RELEASEKIT_VERSION": "profile version", "RELEASEKIT_CANDIDATE": "profile commit", }, }}, } contents, err := json.Marshal(settings) if err != nil { t.Fatal(err) } if err := os.WriteFile(profilePath, contents, 0o600); err != nil { t.Fatal(err) } var stdout, stderr bytes.Buffer args := []string{"check", "--repo", repository, "--config", profilePath, "v1.2.3"} if status := run(context.Background(), args, &stdout, &stderr); status != 0 { t.Fatalf("run() status = %d; stdout=%q stderr=%q", status, stdout.String(), stderr.String()) } commit := cliGitOutput(t, repository, "rev-parse", "HEAD") if want := "v1.2.3|" + commit; stderr.String() != want { t.Fatalf("configured check received %q, want captured candidate %q", stderr.String(), want) } if want := fmt.Sprintf("local candidate v1.2.3 at %s is valid\n", commit); stdout.String() != want { t.Fatalf("stdout = %q, want %q", stdout.String(), want) } } func TestCandidateCheckHelper(t *testing.T) { if os.Getenv("RELEASEKIT_CHECK_HELPER") != "1" { return } fmt.Fprintf(os.Stdout, "%s|%s", os.Getenv("RELEASEKIT_VERSION"), os.Getenv("RELEASEKIT_CANDIDATE")) os.Exit(0) } func newCLIRepository(t *testing.T) string { t.Helper() repository := filepath.Join(t.TempDir(), "candidate repository") if err := os.Mkdir(repository, 0o700); err != nil { t.Fatal(err) } cliGitRun(t, repository, "init", "--initial-branch=main") cliGitRun(t, repository, "config", "user.name", "ReleaseKit Test") cliGitRun(t, repository, "config", "user.email", "releasekit@example.test") cliGitRun(t, repository, "config", "commit.gpgsign", "false") write := func(name, value string) { t.Helper() path := filepath.Join(repository, filepath.FromSlash(name)) if err := os.MkdirAll(filepath.Dir(path), 0o700); err != nil { t.Fatal(err) } if err := os.WriteFile(path, []byte(value), 0o600); err != nil { t.Fatal(err) } } write("go.mod", "module example.com/cli-candidate\n\ngo 1.25.0\n") write("candidate_test.go", "package candidate\nimport \"testing\"\nfunc TestFixture(t *testing.T) {}\n") write("docs/releases/v1.2.3.md", "# Example Product v1.2.3\n\nRelease note.\n") cliGitRun(t, repository, "add", "--all") cliGitRun(t, repository, "commit", "-m", "candidate") return repository } func cliGitRun(t *testing.T, repository string, args ...string) { t.Helper() commandArgs := append([]string{"git"}, args...) command := exec.Command(commandArgs[0], commandArgs[1:]...) command.Dir = repository output, err := command.CombinedOutput() if err != nil { t.Fatalf("%v: %v\n%s", commandArgs, err, output) } } func cliGitOutput(t *testing.T, repository string, args ...string) string { t.Helper() commandArgs := append([]string{"git"}, args...) command := exec.Command(commandArgs[0], commandArgs[1:]...) command.Dir = repository output, err := command.Output() if err != nil { t.Fatalf("%v: %v", commandArgs, err) } return strings.TrimSpace(string(output)) }