Add profile loading and process execution
This commit is contained in:
172
cmd/releasekit/internal/cli/config_test.go
Normal file
172
cmd/releasekit/internal/cli/config_test.go
Normal file
@@ -0,0 +1,172 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user