Add local candidate validation
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
@@ -15,26 +16,49 @@ import (
|
||||
"gitea.maximumdirect.net/eric/ReleaseKit/internal/process"
|
||||
)
|
||||
|
||||
const Usage = "usage: releasekit version"
|
||||
const Usage = "usage: releasekit version\n releasekit check [--repo DIR] [--config FILE] VERSION"
|
||||
|
||||
type Command string
|
||||
|
||||
const VersionCommand Command = "version"
|
||||
const (
|
||||
VersionCommand Command = "version"
|
||||
CheckAction Command = "check"
|
||||
)
|
||||
|
||||
// Invocation contains parsed command settings owned by the CLI adapter.
|
||||
type Invocation struct {
|
||||
Command Command
|
||||
Command Command
|
||||
Repository string
|
||||
ConfigPath string
|
||||
Version string
|
||||
}
|
||||
|
||||
// Parse accepts only commands that have been implemented by the executable.
|
||||
func Parse(args []string) (Invocation, error) {
|
||||
if len(args) == 1 && args[0] == string(VersionCommand) {
|
||||
return Invocation{Command: VersionCommand}, nil
|
||||
}
|
||||
if len(args) == 0 {
|
||||
return Invocation{}, errors.New("a command is required")
|
||||
}
|
||||
return Invocation{}, fmt.Errorf("unknown command %q", args[0])
|
||||
switch args[0] {
|
||||
case string(VersionCommand):
|
||||
if len(args) != 1 {
|
||||
return Invocation{}, errors.New("version takes no arguments")
|
||||
}
|
||||
return Invocation{Command: VersionCommand}, nil
|
||||
case string(CheckAction):
|
||||
flags := flag.NewFlagSet("check", flag.ContinueOnError)
|
||||
flags.SetOutput(io.Discard)
|
||||
repository := flags.String("repo", ".", "repository directory")
|
||||
configPath := flags.String("config", "", "profile path")
|
||||
if err := flags.Parse(args[1:]); err != nil {
|
||||
return Invocation{}, err
|
||||
}
|
||||
if flags.NArg() != 1 {
|
||||
return Invocation{}, errors.New("check requires one version argument")
|
||||
}
|
||||
return Invocation{Command: CheckAction, Repository: *repository, ConfigPath: *configPath, Version: flags.Arg(0)}, nil
|
||||
default:
|
||||
return Invocation{}, fmt.Errorf("unknown command %q", args[0])
|
||||
}
|
||||
}
|
||||
|
||||
// CheckCommand contains one direct child-process invocation from a profile.
|
||||
@@ -101,12 +125,19 @@ func LoadSettings(repoDir, configPath string) (Settings, error) {
|
||||
|
||||
// RunChecks runs configured argument vectors in repoDir. Each command receives
|
||||
// its own environment overlay and inherits the remaining process environment.
|
||||
func RunChecks(ctx context.Context, repoDir string, checks []CheckCommand, stdout, stderr io.Writer) error {
|
||||
func RunChecks(ctx context.Context, repoDir string, checks []CheckCommand, ownedEnv map[string]string, stdout, stderr io.Writer) error {
|
||||
for i, check := range checks {
|
||||
environment := make(map[string]string, len(check.Env)+len(ownedEnv))
|
||||
for key, value := range check.Env {
|
||||
environment[key] = value
|
||||
}
|
||||
for key, value := range ownedEnv {
|
||||
environment[key] = value
|
||||
}
|
||||
if err := process.Run(ctx, process.Invocation{
|
||||
Args: check.Args,
|
||||
Dir: repoDir,
|
||||
Env: check.Env,
|
||||
Env: environment,
|
||||
Stdout: stdout,
|
||||
Stderr: stderr,
|
||||
}); err != nil {
|
||||
|
||||
@@ -19,6 +19,16 @@ func TestParse(t *testing.T) {
|
||||
if invocation.Command != VersionCommand {
|
||||
t.Fatalf("Parse() command = %q, want %q", invocation.Command, VersionCommand)
|
||||
}
|
||||
check, err := Parse([]string{"check", "--repo", "repository with spaces", "--config", "profiles/release config.json", "v1.2.3"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if check.Command != CheckAction || check.Repository != "repository with spaces" || check.ConfigPath != "profiles/release config.json" || check.Version != "v1.2.3" {
|
||||
t.Fatalf("Parse(check) = %#v", check)
|
||||
}
|
||||
if _, err := Parse([]string{"check", "v1.2.3", "--repo", "repository"}); err == nil {
|
||||
t.Fatal("Parse accepted a flag after the version")
|
||||
}
|
||||
if _, err := Parse(nil); err == nil || !strings.Contains(err.Error(), "command is required") {
|
||||
t.Fatalf("Parse(nil) error = %v, want missing-command error", err)
|
||||
}
|
||||
@@ -139,12 +149,16 @@ func TestRunChecksUsesConfiguredArgumentsEnvironmentAndDirectory(t *testing.T) {
|
||||
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)
|
||||
Env: map[string]string{
|
||||
"RELEASEKIT_CONFIGURED_HELPER": "1",
|
||||
"RELEASEKIT_CONFIGURED_VALUE": "selected value",
|
||||
"RELEASEKIT_VERSION": "profile value",
|
||||
},
|
||||
}}, map[string]string{"RELEASEKIT_VERSION": "captured version", "RELEASEKIT_CANDIDATE": "captured commit"}, &stdout, &stderr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
want := fmt.Sprintf("%s|argument with spaces|selected value", workdir)
|
||||
want := fmt.Sprintf("%s|argument with spaces|selected value|captured version|captured commit", workdir)
|
||||
if stdout.String() != want {
|
||||
t.Fatalf("stdout = %q, want %q", stdout.String(), want)
|
||||
}
|
||||
@@ -158,7 +172,7 @@ func TestConfiguredCommandHelper(t *testing.T) {
|
||||
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"))
|
||||
fmt.Fprintf(os.Stdout, "%s|%s|%s|%s|%s", workdir, os.Args[len(os.Args)-1], os.Getenv("RELEASEKIT_CONFIGURED_VALUE"), os.Getenv("RELEASEKIT_VERSION"), os.Getenv("RELEASEKIT_CANDIDATE"))
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user