189 lines
6.5 KiB
Go
189 lines
6.5 KiB
Go
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{"unknown"}, &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 \"unknown\"\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 TestPublishCommandPublishesConfiguredCandidate(t *testing.T) {
|
|
repository := newCLIRepository(t)
|
|
settings := cli.Settings{
|
|
Product: "Example Product",
|
|
Remote: "origin",
|
|
Checks: []cli.CheckCommand{{
|
|
Args: []string{"go", "test", "-mod=readonly", "-count=1", "./..."},
|
|
Env: map[string]string{
|
|
"GOTOOLCHAIN": "local",
|
|
"GOPROXY": "off",
|
|
"GOSUMDB": "off",
|
|
},
|
|
}},
|
|
}
|
|
contents, err := json.Marshal(settings)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(repository, "releasekit.json"), contents, 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
cliGitRun(t, repository, "add", "releasekit.json")
|
|
cliGitRun(t, repository, "commit", "-m", "configure source release")
|
|
remote := filepath.Join(t.TempDir(), "origin.git")
|
|
cliGitRun(t, repository, "init", "--bare", remote)
|
|
cliGitRun(t, repository, "remote", "add", "origin", remote)
|
|
cliGitRun(t, repository, "push", "--set-upstream", "origin", "main")
|
|
|
|
var stdout, stderr bytes.Buffer
|
|
args := []string{"publish", "--repo", repository, "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")
|
|
tagObject := cliGitOutput(t, repository, "rev-parse", "refs/tags/v1.2.3")
|
|
if want := fmt.Sprintf("published v1.2.3 at %s (tag object %s)\n", commit, tagObject); stdout.String() != want {
|
|
t.Fatalf("stdout = %q, want %q", stdout.String(), want)
|
|
}
|
|
if !bytes.Contains(stderr.Bytes(), []byte("validating and publishing v1.2.3")) || !bytes.Contains(stderr.Bytes(), []byte("example.com/cli-candidate")) {
|
|
t.Fatalf("stderr does not show publication progress and validation: %q", stderr.String())
|
|
}
|
|
if got := cliGitOutput(t, remote, "rev-parse", "refs/tags/v1.2.3"); got != tagObject {
|
|
t.Fatalf("remote tag object = %s, want %s", got, tagObject)
|
|
}
|
|
}
|
|
|
|
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))
|
|
}
|