From c7711e0becf1d5bc69b9708a5a9934990256014f Mon Sep 17 00:00:00 2001 From: k1LoW Date: Fri, 28 Oct 2022 10:43:52 +0900 Subject: [PATCH 1/2] Support `--runner req:https://example.com/api/v1` option for CLI --- cmd/list.go | 14 ++--- cmd/new.go | 45 ++++++++-------- cmd/root.go | 149 ++++++++++++++++++++++++++++++++++++++++++++++------ cmd/run.go | 126 +++++--------------------------------------- 4 files changed, 175 insertions(+), 159 deletions(-) diff --git a/cmd/list.go b/cmd/list.go index a2b5eee5..82dbaed2 100644 --- a/cmd/list.go +++ b/cmd/list.go @@ -50,7 +50,7 @@ var listCmd = &cobra.Command{ table.SetBorder(false) pathp := strings.Join(args, string(filepath.ListSeparator)) - opts, err := collectOpts() + opts, err := flags.ToOpts() if err != nil { return err } @@ -73,10 +73,10 @@ var listCmd = &cobra.Command{ func init() { rootCmd.AddCommand(listCmd) - listCmd.Flags().BoolVarP(&skipIncluded, "skip-included", "", false, `skip running the included step by itself`) - listCmd.Flags().StringSliceVarP(&vars, "var", "", []string{}, `set var to runbook ("key:value")`) - listCmd.Flags().StringSliceVarP(&overlays, "overlay", "", []string{}, "overlay values on the runbook") - listCmd.Flags().StringSliceVarP(&underlays, "underlay", "", []string{}, "lay values under the runbook") - listCmd.Flags().IntVarP(&sample, "sample", "", 0, "run the specified number of runbooks at random") - listCmd.Flags().StringVarP(&shuffle, "shuffle", "", "off", `randomize the order of running runbooks ("on","off",N)`) + listCmd.Flags().BoolVarP(&flags.SkipIncluded, "skip-included", "", false, `skip running the included step by itself`) + listCmd.Flags().StringSliceVarP(&flags.Vars, "var", "", []string{}, `set var to runbook ("key:value")`) + listCmd.Flags().StringSliceVarP(&flags.Overlays, "overlay", "", []string{}, "overlay values on the runbook") + listCmd.Flags().StringSliceVarP(&flags.Underlays, "underlay", "", []string{}, "lay values under the runbook") + listCmd.Flags().IntVarP(&flags.Sample, "sample", "", 0, "run the specified number of runbooks at random") + listCmd.Flags().StringVarP(&flags.Shuffle, "shuffle", "", "off", `randomize the order of running runbooks ("on","off",N)`) } diff --git a/cmd/new.go b/cmd/new.go index e06b2ce9..bced6e39 100644 --- a/cmd/new.go +++ b/cmd/new.go @@ -58,19 +58,21 @@ var newCmd = &cobra.Command{ al = [][]string{args} } ctx := context.Background() - rb := runn.NewRunbook(desc) - p := filepath.Clean(out) - if _, err := os.Stat(p); err == nil { - f, err := os.Open(p) - if err != nil { - return err - } - rb, err = runn.LoadRunbook(f) - if err != nil { - return err - } - if desc != "" { - rb.Desc = desc + rb := runn.NewRunbook(flags.Desc) + if flags.Out != "" { + p := filepath.Clean(flags.Out) + if _, err := os.Stat(p); err == nil { + f, err := os.Open(p) + if err != nil { + return err + } + rb, err = runn.LoadRunbook(f) + if err != nil { + return err + } + if flags.Desc != "" { + rb.Desc = flags.Desc + } } } for _, args := range al { @@ -78,10 +80,10 @@ var newCmd = &cobra.Command{ return err } } - if out == "" { + if flags.Out == "" { o = os.Stdout } else { - o, err = os.Create(filepath.Clean(out)) + o, err = os.Create(filepath.Clean(flags.Out)) if err != nil { return err } @@ -101,7 +103,7 @@ var newCmd = &cobra.Command{ return nil } - if andRun { + if flags.AndRun { if err := runAndCapture(ctx, o, fn); err != nil { return err } @@ -117,10 +119,10 @@ var newCmd = &cobra.Command{ func init() { rootCmd.AddCommand(newCmd) - newCmd.Flags().StringVarP(&desc, "desc", "", "", "description of runbook") - newCmd.Flags().StringVarP(&out, "out", "", "", "target path of runbook") - newCmd.Flags().BoolVarP(&andRun, "and-run", "", false, "run created runbook and capture the response for test") - newCmd.Flags().BoolVarP(&grpcNoTLS, "grpc-no-tls", "", false, "disable TLS use in all gRPC runners") + newCmd.Flags().StringVarP(&flags.Desc, "desc", "", "", "description of runbook") + newCmd.Flags().StringVarP(&flags.Out, "out", "", "", "target path of runbook") + newCmd.Flags().BoolVarP(&flags.AndRun, "and-run", "", false, "run created runbook and capture the response for test") + newCmd.Flags().BoolVarP(&flags.GRPCNoTLS, "grpc-no-tls", "", false, "disable TLS use in all gRPC runners") } func runAndCapture(ctx context.Context, o *os.File, fn func(*os.File) error) error { @@ -148,9 +150,8 @@ func runAndCapture(ctx context.Context, o *os.File, fn func(*os.File) error) err opts := []runn.Option{ runn.Book(tf.Name()), runn.Capture(capture.Runbook(td, capture.RunbookLoadDesc(true))), - runn.GRPCNoTLS(grpcNoTLS), + runn.GRPCNoTLS(flags.GRPCNoTLS), } - oo, err := runn.New(opts...) if err != nil { return err diff --git a/cmd/root.go b/cmd/root.go index ad3b68a5..51f01f58 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -22,29 +22,24 @@ THE SOFTWARE. package cmd import ( + "errors" + "fmt" "os" + "regexp" + "runtime" + "sort" + "strconv" + "strings" + "time" + "github.com/k1LoW/runn" + "github.com/k1LoW/runn/capture" "github.com/k1LoW/runn/version" + "github.com/spf13/cast" "github.com/spf13/cobra" ) -var ( - debug bool - failFast bool - skipTest bool - skipIncluded bool - grpcNoTLS bool - captureDir string - vars []string - overlays []string - underlays []string - sample int - shuffle string - parallel string - desc string - out string - andRun bool -) +var flags = &Flags{} // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ @@ -61,3 +56,123 @@ func Execute() { os.Exit(1) } } + +var intRe = regexp.MustCompile(`^\-?[0-9]+$`) +var floatRe = regexp.MustCompile(`^\-?[0-9.]+$`) + +type Flags struct { + Debug bool + FailFast bool + SkipTest bool + SkipIncluded bool + GRPCNoTLS bool + CaptureDir string + Vars []string + Runners []string + Overlays []string + Underlays []string + Sample int + Shuffle string + Parallel string + Desc string + Out string + AndRun bool +} + +func (f *Flags) ToOpts() ([]runn.Option, error) { + const ( + on = "on" + off = "off" + keyValueSep = ":" + keysSep = "." + ) + opts := []runn.Option{ + runn.Debug(f.Debug), + runn.SkipTest(f.SkipTest), + runn.SkipIncluded(f.SkipIncluded), + runn.GRPCNoTLS(f.GRPCNoTLS), + runn.Capture(runn.NewCmdOut(os.Stdout)), + } + if f.Sample > 0 { + opts = append(opts, runn.RunSample(f.Sample)) + } + if f.Shuffle != "" { + switch { + case f.Shuffle == on: + opts = append(opts, runn.RunShuffle(true, time.Now().UnixNano())) + case f.Shuffle == off: + default: + seed, err := strconv.ParseInt(f.Shuffle, 10, 64) + if err != nil { + return nil, errors.New(`should be "on", "off" or number for seed: --shuffle`) + } + opts = append(opts, runn.RunShuffle(true, seed)) + } + } + if f.Parallel != "" { + switch { + case f.Parallel == on: + opts = append(opts, runn.RunParallel(true, int64(runtime.GOMAXPROCS(0)))) + case f.Parallel == off: + default: + max, err := strconv.ParseInt(f.Parallel, 10, 64) + if err != nil { + return nil, errors.New(`should be "on", "off" or number for seed: --parallel`) + } + opts = append(opts, runn.RunParallel(true, max)) + } + } + + for _, v := range f.Vars { + splitted := strings.Split(v, keyValueSep) + if len(splitted) < 2 { + return nil, fmt.Errorf("invalid var: %s", v) + } + vk := strings.Split(splitted[0], keysSep) + vv := strings.Join(splitted[1:], keyValueSep) + switch { + case intRe.MatchString(vv): + vvv, err := cast.ToIntE(vv) + if err == nil { + opts = append(opts, runn.Var(vk, vvv)) + continue + } + case floatRe.MatchString(vv): + vvv, err := cast.ToFloat64E(vv) + if err == nil { + opts = append(opts, runn.Var(vk, vvv)) + continue + } + } + opts = append(opts, runn.Var(vk, vv)) + } + for _, v := range f.Runners { + splitted := strings.Split(v, keyValueSep) + if len(splitted) < 2 { + return nil, fmt.Errorf("invalid var: %s", v) + } + vk := splitted[0] + vv := strings.Join(splitted[1:], keyValueSep) + opts = append(opts, runn.Runner(vk, vv)) + } + for _, o := range f.Overlays { + opts = append(opts, runn.Overlay(o)) + } + sort.SliceStable(f.Underlays, func(i, j int) bool { + return i > j + }) + for _, u := range f.Underlays { + opts = append(opts, runn.Underlay(u)) + } + if f.CaptureDir != "" { + fi, err := os.Stat(f.CaptureDir) + if err != nil { + return nil, err + } + if !fi.IsDir() { + return nil, fmt.Errorf("%s is not directory", f.CaptureDir) + } + opts = append(opts, runn.Capture(capture.Runbook(f.CaptureDir))) + } + return opts, nil +} diff --git a/cmd/run.go b/cmd/run.go index 822b516c..38ce69c3 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -23,21 +23,13 @@ package cmd import ( "context" - "errors" "fmt" "os" "path/filepath" - "regexp" - "runtime" - "sort" - "strconv" "strings" - "time" "github.com/fatih/color" "github.com/k1LoW/runn" - "github.com/k1LoW/runn/capture" - "github.com/spf13/cast" "github.com/spf13/cobra" ) @@ -51,7 +43,7 @@ var runCmd = &cobra.Command{ green := color.New(color.FgGreen).SprintFunc() red := color.New(color.FgRed).SprintFunc() pathp := strings.Join(args, string(filepath.ListSeparator)) - opts, err := collectOpts() + opts, err := flags.ToOpts() if err != nil { return err } @@ -90,108 +82,16 @@ var runCmd = &cobra.Command{ func init() { rootCmd.AddCommand(runCmd) - runCmd.Flags().BoolVarP(&debug, "debug", "", false, "debug") - runCmd.Flags().BoolVarP(&failFast, "fail-fast", "", false, "fail fast") - runCmd.Flags().BoolVarP(&skipTest, "skip-test", "", false, `skip "test:" section`) - runCmd.Flags().BoolVarP(&skipIncluded, "skip-included", "", false, `skip running the included step by itself`) - runCmd.Flags().BoolVarP(&grpcNoTLS, "grpc-no-tls", "", false, "disable TLS use in all gRPC runners") - runCmd.Flags().StringVarP(&captureDir, "capture", "", "", "destination of runbook run capture results") - runCmd.Flags().StringSliceVarP(&vars, "var", "", []string{}, `set var to runbook ("key:value")`) - runCmd.Flags().StringSliceVarP(&overlays, "overlay", "", []string{}, "overlay values on the runbook") - runCmd.Flags().StringSliceVarP(&underlays, "underlay", "", []string{}, "lay values under the runbook") - runCmd.Flags().IntVarP(&sample, "sample", "", 0, "run the specified number of runbooks at random") - runCmd.Flags().StringVarP(&shuffle, "shuffle", "", "off", `randomize the order of running runbooks ("on","off",N)`) - runCmd.Flags().StringVarP(¶llel, "parallel", "", "off", `parallelize runs of runbooks ("on","off",N)`) -} - -var intRe = regexp.MustCompile(`^\-?[0-9]+$`) -var floatRe = regexp.MustCompile(`^\-?[0-9.]+$`) - -func collectOpts() ([]runn.Option, error) { - const ( - on = "on" - off = "off" - keyValueSep = ":" - keysSep = "." - ) - opts := []runn.Option{ - runn.Debug(debug), - runn.SkipTest(skipTest), - runn.SkipIncluded(skipIncluded), - runn.GRPCNoTLS(grpcNoTLS), - runn.Capture(runn.NewCmdOut(os.Stdout)), - } - if sample > 0 { - opts = append(opts, runn.RunSample(sample)) - } - if shuffle != "" { - switch { - case shuffle == on: - opts = append(opts, runn.RunShuffle(true, time.Now().UnixNano())) - case shuffle == off: - default: - seed, err := strconv.ParseInt(shuffle, 10, 64) - if err != nil { - return nil, errors.New(`should be "on", "off" or number for seed: --shuffle`) - } - opts = append(opts, runn.RunShuffle(true, seed)) - } - } - if parallel != "" { - switch { - case parallel == on: - opts = append(opts, runn.RunParallel(true, int64(runtime.GOMAXPROCS(0)))) - case parallel == off: - default: - max, err := strconv.ParseInt(parallel, 10, 64) - if err != nil { - return nil, errors.New(`should be "on", "off" or number for seed: --parallel`) - } - opts = append(opts, runn.RunParallel(true, max)) - } - } - - for _, v := range vars { - splitted := strings.Split(v, keyValueSep) - if len(splitted) < 2 { - return nil, fmt.Errorf("invalid var: %s", v) - } - vk := strings.Split(splitted[0], keysSep) - vv := strings.Join(splitted[1:], keyValueSep) - switch { - case intRe.MatchString(vv): - vvv, err := cast.ToIntE(vv) - if err == nil { - opts = append(opts, runn.Var(vk, vvv)) - continue - } - case floatRe.MatchString(vv): - vvv, err := cast.ToFloat64E(vv) - if err == nil { - opts = append(opts, runn.Var(vk, vvv)) - continue - } - } - opts = append(opts, runn.Var(vk, vv)) - } - for _, o := range overlays { - opts = append(opts, runn.Overlay(o)) - } - sort.SliceStable(underlays, func(i, j int) bool { - return i > j - }) - for _, u := range underlays { - opts = append(opts, runn.Underlay(u)) - } - if captureDir != "" { - fi, err := os.Stat(captureDir) - if err != nil { - return nil, err - } - if !fi.IsDir() { - return nil, fmt.Errorf("%s is not directory", captureDir) - } - opts = append(opts, runn.Capture(capture.Runbook(captureDir))) - } - return opts, nil + runCmd.Flags().BoolVarP(&flags.Debug, "debug", "", false, "debug") + runCmd.Flags().BoolVarP(&flags.FailFast, "fail-fast", "", false, "fail fast") + runCmd.Flags().BoolVarP(&flags.SkipTest, "skip-test", "", false, `skip "test:" section`) + runCmd.Flags().BoolVarP(&flags.SkipIncluded, "skip-included", "", false, `skip running the included step by itself`) + runCmd.Flags().BoolVarP(&flags.GRPCNoTLS, "grpc-no-tls", "", false, "disable TLS use in all gRPC runners") + runCmd.Flags().StringVarP(&flags.CaptureDir, "capture", "", "", "destination of runbook run capture results") + runCmd.Flags().StringSliceVarP(&flags.Vars, "var", "", []string{}, `set var to runbook ("key:value")`) + runCmd.Flags().StringSliceVarP(&flags.Overlays, "overlay", "", []string{}, "overlay values on the runbook") + runCmd.Flags().StringSliceVarP(&flags.Underlays, "underlay", "", []string{}, "lay values under the runbook") + runCmd.Flags().IntVarP(&flags.Sample, "sample", "", 0, "run the specified number of runbooks at random") + runCmd.Flags().StringVarP(&flags.Shuffle, "shuffle", "", "off", `randomize the order of running runbooks ("on","off",N)`) + runCmd.Flags().StringVarP(&flags.Parallel, "parallel", "", "off", `parallelize runs of runbooks ("on","off",N)`) } From a1c138567396682b5239662b25875c32c1e88d9b Mon Sep 17 00:00:00 2001 From: k1LoW Date: Fri, 28 Oct 2022 14:15:50 +0900 Subject: [PATCH 2/2] Add --runner --- cmd/list.go | 1 + cmd/run.go | 1 + 2 files changed, 2 insertions(+) diff --git a/cmd/list.go b/cmd/list.go index 82dbaed2..ee517c68 100644 --- a/cmd/list.go +++ b/cmd/list.go @@ -75,6 +75,7 @@ func init() { rootCmd.AddCommand(listCmd) listCmd.Flags().BoolVarP(&flags.SkipIncluded, "skip-included", "", false, `skip running the included step by itself`) listCmd.Flags().StringSliceVarP(&flags.Vars, "var", "", []string{}, `set var to runbook ("key:value")`) + listCmd.Flags().StringSliceVarP(&flags.Runners, "runner", "", []string{}, `set runner to runbook ("key:dsn")`) listCmd.Flags().StringSliceVarP(&flags.Overlays, "overlay", "", []string{}, "overlay values on the runbook") listCmd.Flags().StringSliceVarP(&flags.Underlays, "underlay", "", []string{}, "lay values under the runbook") listCmd.Flags().IntVarP(&flags.Sample, "sample", "", 0, "run the specified number of runbooks at random") diff --git a/cmd/run.go b/cmd/run.go index 38ce69c3..3ac2997d 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -89,6 +89,7 @@ func init() { runCmd.Flags().BoolVarP(&flags.GRPCNoTLS, "grpc-no-tls", "", false, "disable TLS use in all gRPC runners") runCmd.Flags().StringVarP(&flags.CaptureDir, "capture", "", "", "destination of runbook run capture results") runCmd.Flags().StringSliceVarP(&flags.Vars, "var", "", []string{}, `set var to runbook ("key:value")`) + runCmd.Flags().StringSliceVarP(&flags.Runners, "runner", "", []string{}, `set runner to runbook ("key:dsn")`) runCmd.Flags().StringSliceVarP(&flags.Overlays, "overlay", "", []string{}, "overlay values on the runbook") runCmd.Flags().StringSliceVarP(&flags.Underlays, "underlay", "", []string{}, "lay values under the runbook") runCmd.Flags().IntVarP(&flags.Sample, "sample", "", 0, "run the specified number of runbooks at random")