173 lines
5.4 KiB
Go
173 lines
5.4 KiB
Go
package cli
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestParse(t *testing.T) {
|
|
invocation, err := Parse([]string{"version"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if invocation.Command != VersionCommand {
|
|
t.Fatalf("Parse() command = %q, want %q", invocation.Command, VersionCommand)
|
|
}
|
|
if _, err := Parse(nil); err == nil || !strings.Contains(err.Error(), "command is required") {
|
|
t.Fatalf("Parse(nil) error = %v, want missing-command error", err)
|
|
}
|
|
if _, err := Parse([]string{"publish"}); err == nil || !strings.Contains(err.Error(), "unknown command") {
|
|
t.Fatalf("Parse(publish) error = %v, want unknown-command error", err)
|
|
}
|
|
}
|
|
|
|
func TestLoadSettingsResolvesPathsAndPreservesArguments(t *testing.T) {
|
|
repoDir := filepath.Join(t.TempDir(), "repository with spaces")
|
|
profileDir := filepath.Join(repoDir, "profiles with spaces")
|
|
if err := os.MkdirAll(profileDir, 0o700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
want := Settings{
|
|
Product: "Example Product",
|
|
Remote: "upstream",
|
|
Checks: []CheckCommand{{
|
|
Args: []string{"sh", "scripts/check release.sh", "two words"},
|
|
Env: map[string]string{"RELEASE_MODE": "candidate check"},
|
|
}},
|
|
}
|
|
contents, err := json.Marshal(want)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(profileDir, "release profile.json"), contents, 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
got, err := LoadSettings(repoDir, filepath.Join("profiles with spaces", "release profile.json"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got.Product != want.Product || got.Remote != want.Remote || len(got.Checks) != 1 {
|
|
t.Fatalf("LoadSettings() = %#v, want product, remote, and one check", got)
|
|
}
|
|
if got.Checks[0].Args[1] != "scripts/check release.sh" || got.Checks[0].Args[2] != "two words" {
|
|
t.Fatalf("check arguments were changed: %#v", got.Checks[0].Args)
|
|
}
|
|
if got.Checks[0].Env["RELEASE_MODE"] != "candidate check" {
|
|
t.Fatalf("check environment = %#v", got.Checks[0].Env)
|
|
}
|
|
}
|
|
|
|
func TestLoadSettingsDefaultsRemoteAndConfigPath(t *testing.T) {
|
|
repoDir := t.TempDir()
|
|
contents := `{"product":"Example"}`
|
|
profilePath := filepath.Join(repoDir, "releasekit.json")
|
|
if err := os.WriteFile(profilePath, []byte(contents), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, test := range []struct {
|
|
name string
|
|
path string
|
|
}{
|
|
{name: "default path"},
|
|
{name: "absolute path", path: profilePath},
|
|
} {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
settings, err := LoadSettings(repoDir, test.path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if settings.Remote != "origin" {
|
|
t.Fatalf("default remote = %q, want origin", settings.Remote)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestExampleProfileLoads(t *testing.T) {
|
|
repoDir, err := filepath.Abs(filepath.Join("..", "..", "..", ".."))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
settings, err := LoadSettings(repoDir, filepath.Join("examples", "releasekit.json"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if settings.Product != "Example" || settings.Remote != "origin" || len(settings.Checks) != 1 {
|
|
t.Fatalf("example settings = %#v", settings)
|
|
}
|
|
}
|
|
|
|
func TestLoadSettingsRejectsInvalidProfiles(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
content string
|
|
want string
|
|
}{
|
|
{name: "missing product", content: `{}`, want: "product is required"},
|
|
{name: "unknown top-level field", content: `{"product":"Example","delivery":{}}`, want: "unknown field"},
|
|
{name: "unsupported build field", content: `{"product":"Example","build":{}}`, want: "unknown field"},
|
|
{name: "unknown command field", content: `{"product":"Example","checks":[{"args":["true"],"shell":true}]}`, want: "unknown field"},
|
|
{name: "command is required", content: `{"product":"Example","checks":[{"args":[]}]}`, want: "must include a command"},
|
|
{name: "multiple JSON values", content: `{"product":"Example"}{"product":"Other"}`, want: "multiple JSON values"},
|
|
}
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
repoDir := t.TempDir()
|
|
path := filepath.Join(repoDir, "profile.json")
|
|
if err := os.WriteFile(path, []byte(test.content), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := LoadSettings(repoDir, path); err == nil || !strings.Contains(err.Error(), test.want) {
|
|
t.Fatalf("LoadSettings() error = %v, want text %q", err, test.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRunChecksUsesConfiguredArgumentsEnvironmentAndDirectory(t *testing.T) {
|
|
workdir := filepath.Join(t.TempDir(), "repo with spaces")
|
|
if err := os.Mkdir(workdir, 0o700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var stdout, stderr bytes.Buffer
|
|
err := RunChecks(context.Background(), workdir, []CheckCommand{{
|
|
Args: []string{helperExecutable(t), "-test.run=TestConfiguredCommandHelper", "--", "argument with spaces"},
|
|
Env: map[string]string{"RELEASEKIT_CONFIGURED_HELPER": "1", "RELEASEKIT_CONFIGURED_VALUE": "selected value"},
|
|
}}, &stdout, &stderr)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
want := fmt.Sprintf("%s|argument with spaces|selected value", workdir)
|
|
if stdout.String() != want {
|
|
t.Fatalf("stdout = %q, want %q", stdout.String(), want)
|
|
}
|
|
}
|
|
|
|
func TestConfiguredCommandHelper(t *testing.T) {
|
|
if os.Getenv("RELEASEKIT_CONFIGURED_HELPER") != "1" {
|
|
return
|
|
}
|
|
workdir, err := os.Getwd()
|
|
if err != nil {
|
|
os.Exit(9)
|
|
}
|
|
fmt.Fprintf(os.Stdout, "%s|%s|%s", workdir, os.Args[len(os.Args)-1], os.Getenv("RELEASEKIT_CONFIGURED_VALUE"))
|
|
os.Exit(0)
|
|
}
|
|
|
|
func helperExecutable(t *testing.T) string {
|
|
t.Helper()
|
|
executable, err := os.Executable()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return executable
|
|
}
|